Architecture

Components, ownership, the seat Pod contract, authentication and fencing, messaging, the gateway and the readiness flow.

This page is the binding description of how the components fit together: who owns what, the contract every seat Pod follows, and how messages, tools and readiness work. The design rationale is in Design decisions.

Components

ComponentCodeResponsibility
Specification and compilerpkg/spec, pkg/compileThe schema, plus the single validator used by both the provider and the controller. Resolves templates, applies versioned defaults, expands grants and routes, and computes per-seat revisions.
Kubernetes APIapi/v1alpha1AgentOrganization (declared) and AgentSeat (owned by the controller).
Terraform providerprovider/Writes the resolved organisation with server-side apply (field manager terraform-provider-steadmesh, never forced). Waits for readiness, imports, detects drift.
Controllercontroller/, runtime/Reconciles organisations into seats, runs seat lifecycle (wake, idle stop, safe restarts, fenced recovery, retirement), runs the sandbox backend and reports readiness.
Platform serviceservices/The trusted runtime: identity, durable inbox and outbox, memory, the tools gateway, the operation ledger, the scheduler, the model proxy, Slack ingress, verification and probes.
Connectorsconnectors/Slack (Socket Mode), Linear (GraphQL), model endpoints (Anthropic, OpenAI and any compatible endpoint, behind the model proxy), and secret resolvers for Kubernetes and Vault.
Seat runtimecmd/seat-runner, harnesses/, cmd/steadmesh-toolsThe in-Pod supervisor (lease, inbox, checkpoints, probes), the harness adapters and the tool client.
Packagingcharts/platform, build/The Helm chart (CRDs, controller, platform service) and container images.

The controller and the platform service never execute agent-written code inside their own processes. Agents run only in seat sandboxes.

Ownership

Each piece of configuration has exactly one writer:

InformationAuthoritative locationWriter
Organisation declarationInfrastructure source, applied to the Kubernetes specDeployment workflow
Readiness and effective revisionKubernetes statusController
Seat identity and retirementPlatform databaseController, through the platform
Messages and pending wakesPlatform databaseIngress and runtime services
MemoryPlatform databaseAgents, through tools
Workspace filesPer-seat persistent volumeThe seat's process
Projects and tasksThe work trackerAgents, through connectors
External operation attemptsOperation ledgerGateway
CredentialsKubernetes Secrets or VaultCredential owners

Terraform state holds identifiers, declared values and computed outputs. It never holds conversations, memory or credentials, and runtime activity never causes drift.

Namespaces and services

Secrets

Deterministic names

For seat key k in organisation o, the base name is seat- plus k lowercased with _ replaced by -, truncated to 40 characters. The suffix - plus the first 8 hex characters of sha256(o + "/" + k) is then appended. The result stays under the 52-character limit for StatefulSet names. The code is in pkg/names.

ObjectName
AgentSeat, StatefulSet, ServiceAccount, NetworkPolicyname
Podname-0
Workspace volume claim (no owner reference, so it is retained)ws-name
Manifest ConfigMapname-manifest

Labels: steadmesh.io/organization, steadmesh.io/seat and steadmesh.io/component=seat. ServiceAccounts are annotated with steadmesh.io/seat-id and steadmesh.io/organization-id.

Seat Pod contract

Authentication and fencing

There are three kinds of caller, each with its own credential: infrastructure management (the Kubernetes API), the controller (/internal/v1/*, using its ServiceAccount token, which must match an allow-listed username), and seats (/v1/*).

  1. A seat's token is checked with a TokenReview for audience steadmesh-gateway. The resulting system:serviceaccount:<ns>:<sa> identity maps to exactly one active seat. The Pod UID comes from the token's bound claims. A client cannot pick a different principal.
  2. POST /v1/lease/acquire succeeds when the lease is free, expired, or already held by the same Pod. It increments the generation. The TTL is 30s, and the runner renews every 10s.
  3. Every mutating call carries X-Steadmesh-Generation. The platform compares it with the current generation in the same transaction as the write, and stale or missing generations get 409 fenced. This covers inbox leases and acks, memory writes, events, checkpoints, handoffs and connector operations.
  4. A runner whose renewal is fenced kills its harness immediately and exits.
  5. The controller calls /internal/v1/seats/{id}/fence only after it has confirmed that the previous Pod no longer exists. It never force-deletes a Pod on a node it cannot reach, so availability waits until fencing is reliable.

Messages, inbox and execution

Gateway and operation ledger

connections.invoke works as follows:

  1. Check the grant: the seat's capability for connection:<k> must include the operation and match the target restrictions.
  2. Insert a pending ledger row. The idempotency key defaults to a hash of the seat, operation and canonical parameters; read-only operations get a fresh key each time.
  3. If the key already exists, return the recorded operation instead of running it again.
  4. Call the adapter and record the outcome:
    • success becomes succeeded, with the receipt;
    • a permanent error becomes failed;
    • a retryable error is retried with bounded backoff;
    • an ambiguous or unclassified error triggers a read-back. The effect is either found (succeeded) or not confirmed (unknown), and an unknown operation is never re-run automatically.

The effective authority is the intersection of three things: the platform grant, what the adapter implements, and what the external account allows.

Readiness flow

On each reconcile of the current generation, the controller works through these steps in order:

  1. Compile the specification and verify instruction digests (Configured).
  2. Sync identities with the platform. This starts retiring removed seats (they wind down, then retire; see Retiring a seat) and activates the new policy revision before returning (IdentitiesReady).
  3. Ensure each seat's objects: ServiceAccount, volume, manifest, NetworkPolicy and StatefulSet (StorageReady, HarnessCompatible).
  4. Run the NetworkPolicy enforcement probe (SandboxEnforced).
  5. Have the platform verify connections, Slack ingress and bound users (ConnectionsAuthenticated, IngressReady, BindingsValid).
  6. Probe each seat once per configuration revision, waking it if needed (RoutesExecutable).
  7. Aggregate the results into OperationalReady, which is true only when every condition is true for the current generation.

orgctl verify annotates the organisation with steadmesh.io/verify-request=<nonce>. The controller runs a completely fresh pass and echoes the nonce in steadmesh.io/verify-observed only once every check has reached a terminal result. Transient states such as a conflicting update or a probe Pod that is still running keep the pass open.

Lifecycle decisions

One poller per organisation reads /internal/v1/organizations/{id}/runtime every 2s and feeds a pure decision function:

Runtime API

Seat paths (/v1)Controller paths (/internal/v1)
POST lease/acquire, lease/renew, lease/release
POST state; GET self, bootstrap
GET tools; POST tools/{name}
GET inbox/next?wait=; POST inbox/{id}/ack
POST executions/{id}/events; PUT checkpoint
/v1/model/{connection}/… (model proxy)
POST organizations:sync
GET organizations/{id}/runtime
POST organizations/{id}/verify
DELETE organizations/{id}?retention=
POST seats/{id}/fence
POST seats/{id}/probe; GET seats/{id}/probe/{probe}

The wire types are in pkg/runtimeapi. Errors are JSON {code, message}, with codes unauthenticated, forbidden, fenced, conflict, not_found, invalid, blocked and unavailable. /healthz (liveness) and /readyz (database reachable) are separate, and /metrics serves Prometheus.

Durable data model

All durable data is in Postgres (migrations in services/store/migrations), scoped by organisation in every query and index:

Uniqueness and optimistic concurrency are enforced by database constraints, not only by application code.