Skip to content

Operations

Operations is inseam’s single named catalog of every action invocable against a running instance. A typed registry of OperationDefinitions with shared input/output validation, principal resolution, an idempotency cache, a rate-limit hook, and audit events — wrapped by an Invoker that every transport (HTTP, CLI, future gRPC, in-process native shell) wraps. Plugins contribute operations under prefixed namespaces.

A registered operation is described once and then invoked many times through the same pipeline:

  1. Lookup by name (OperationNotFoundError otherwise).
  2. Decode input through the operation’s StandardSchema validator (InputValidationError).
  3. Resolve principal — kind must be one of network-owner, host-owner, user, agent, service (else UnauthorizedError).
  4. Idempotency check (unary mutations only): keyed on (principal_id, operation, idempotency_key), 24h TTL, replay-with-different-input is IdempotencyReplayError.
  5. Rate-limit through the host-supplied RateLimiter (RateLimitedError).
  6. Audit prelude — auditSink.invoked with the canonical SHA-256 input digest.
  7. Invoke handler; validate output; cache result for idempotent unary mutations; emit auditSink.completed or auditSink.failed.

Two surfaces, split by package:

  • @inseam/operations-contractdefineOperation, OperationDefinition, OperationShape, OperationHandler, OperationContext, the framework error classes (InputValidationError, OutputValidationError, UnauthorizedError, RateLimitedError, NotFoundError, IdempotencyReplayError, OperationNotFoundError, InternalError), the wire-error envelope (WireError, WireStreamFrame), and the introspection shape (OperationDescribed). Zero runtime deps; no effect.
  • @inseam/core/operationsopenOperationRegistry, createInvoker, installCoreOperations, the registry-level errors, the per-host operationIdempotencyMigration, and the AuditSink / RateLimiter seams.
  • defineOperation({ name, shape, input, output, errors, idempotent, handler }) — the contract a plugin or core subsystem implements.
  • Shapes. V1 ships unary and server-stream. client-stream and bidirectional are reserved in the vocabulary and rejected by registry.add at registration time. Streams do not participate in the idempotency cache; an AbortSignal from the transport propagates to the handler’s ctx.signal.
  • openOperationRegistry({ store, clock, log }) — the named catalog. add validates prefix and list-field declarations; freeze locks the registry before invocation.
  • createInvoker(registry, { store, clock, log, auditSink, rateLimiter }) — wraps the registry with the 7-step pipeline. invokeUnary / invokeStream are the only entry points transports use.
  • installCoreOperations(registry) — registers operation.list and operation.describe, the two introspection operations every instance ships.
  • Tagged errors. Every operation error implements OperationError ({ readonly _tag: string }) with class.name === _tag. Handler-thrown errors that are neither framework errors nor declared in the operation’s errors array are coerced to InternalError and logged as core.diagnostic.unhandled_operation_error.

Exact signatures: @inseam/operations-contract API · arch/operations/spec.md.

Reach for Operations whenever an action needs to be callable from outside core — by a transport, by another subsystem, by a future remote peer. Naming convention: dot-separated, last segment is the verb. Read-only verbs (get, list, watch, describe) default idempotent: true; everything else defaults to false.

Plugins contribute through a prefix-scoped slot bound to their package name and allowed prefixes; the reserved core prefixes (connection., source., access., principal., network., host., plugin., operation.) are off-limits. *.list operations may declare orderableFields / filterableFields arrays; the registry validates each against the top-level properties of the output JSON Schema at registration time.

If an action is purely internal to a core subsystem and never crosses a transport boundary, a plain function is fine. Operations earns its weight when the action needs validation, audit, idempotency, or remote reach.

  • LLM summary — dense reference for agents.
  • Plugin system — how a plugin acquires its operations slot via RegistrationContext.
  • Access — Principal kinds and how transports resolve them before invocation.
  • Store — the persistence port the idempotency cache writes through.
  • arch/operations/design.md — why a single named catalog.
  • arch/operations/spec.md — types, the 7-step pipeline, errors, acceptance criteria.