Architecture

Untrusted tool calls need isolation from credentials, durable records, and other conversations. Polychrome separates coordination, storage, and execution into three planes, with one sandboxed harness per conversation.

The three runtime planes. A client calls the control plane through the public API. The control plane decides what happens in a turn. It commits every turn to the state plane, which alone writes the event log and also holds the credential, session, ceremony, and persona records. The control plane connects to one sandboxed harness per conversation. The harness runs the turn loop. It makes every turn-loop model call and every external MCP call.Clientchat, CLI, APIControl planeholds no log of its ownAgentServicereconcilerapprovalsState planethe durable authorityevent logappend-only · signed · sole writercredentialssessionsceremoniespersonasHarnessone pod per conversationrun_turntools · approvals · handoffsandboxedno payment keyModelany providerMCPexternal toolsAgentServicecommit / replay, mTLSHarnessServicecomplete()tools/call
unary callstreamasync / eventual

The three planes

The control plane runs as replica pods. It owns the public API, the Kubernetes reconciler, the approval RPC, and the read-only forensics UI. It coordinates turns and commits their results to the state plane. It holds no journal of its own.

The state plane runs as polychrome-state and stores durable records on its own volume. It alone writes the conversation journal. It also owns credential, session, ceremony, and persona records. The control plane connects to it over mutual TLS before binding any listener. If that connection fails, the control plane does not report ready or accept turns.

The execution plane is one harness pod per conversation. The harness runs the run_turn loop, executes pure tools and MCP calls, pauses for approvals, and hands off to other agents. Every turn-loop LLM call and external MCP call goes through the harness; the control plane reaches the provider only for transcript summarization and classification.

A client calls AgentService on the control plane. The control plane commits events to the state plane in atomic batches, then calls HarnessService on the harness. It propagates the traceparent header with that call. The harness calls the LLM provider and external MCP servers.

One turn, end to end

Use the controls below to follow a message through the system. The sequence shows the edge, control plane, reconciler, state plane's log, harness, and response.

A client request passes through the control plane and reconciler to a per-conversation harness. The state plane replays the journal and commits signed batches. The harness calls model providers and tools, then returns the output. Control plane State plane replay journal commit signed batch
1/13

Client → Control plane. The client opens a streaming connection. The edge verifies the caller and derives a stable conversation id from its native identifiers.

unary callstreamasync / eventual

The run_turn loop

The harness executes the agent loop in run_turn. The model emits text or requests a tool call. The loop executes tools and returns their results to the model. It repeats up to MAX_STEPS. A __handoff_to call or a tool requiring approval suspends the turn for the control plane to resolve.

The harness builds a model request, collects streamed text and tool calls, and executes tools. Tool results become input to the next model request. Handoff and approval requests suspend execution. The loop has a maximum step count.

Replay and exclusive journal access

A new replica resumes a conversation by replaying its partition through the state plane. The state plane alone opens and writes the Commonware journal on its volume. Control-plane replicas read that journal through the state plane, so they all read from the same authority.

Verify the event log

The event log uses signed roots to detect changes to committed events. The commands below verify those roots.

Each event produces one leaf digest from its position, kind, and payload. Changing any of these produces a different digest. The leaves form a Merkle Mountain Range. Each batch signs the resulting root with ed25519. It appends the signature and covered events to the same partition in one atomic commit. The signature covers the leaf count and root under a dedicated namespace.

Verification replays the partition and recomputes every root. A mismatch identifies the root that failed verification. The tree also supports proving one leaf against a trusted root without replaying the partition. The planes use these proofs to verify individual events. The commands below recompute the whole partition.

The first command asks the state plane to verify a named partition and requires no admin role. The second verifies a conversation through the control plane and requires an admin persona. Both commands are read-only and exit non-zero on failure. You can use either in incident-response checks.

Shell
# Ask the state plane to recompute one partition's signed roots.
polychrome state verify conv-abc --format json

# Or check a whole conversation through the control plane, as an admin.
polychrome conversation verify abc --actor '<provider>:<scope>:<external-id>'

Verification has limits. state verify fails when a partition contains no committed events. The roots cover event content, but exclude provenance tags. Changing only those tags does not change the root. Signatures detect changes to covered data; they do not prevent writes. The state plane enforces exclusive write access.

Payments

When a tool receives 402 Payment Required, the harness forwards the charge to the control plane. The control plane settles it and returns the response body with a signed receipt. Signing occurs on the control plane. The harness holds no signing key. Payments use the foundation capability polyc-payments through the trusted-tool proxy. The orchestration core does not require payment-provider-specific logic.

Funds remain in the caller's wallet. The server never holds a balance. The control plane holds a time-limited access key with spending and call restrictions, authorized through the caller's passkey. The delegation expires within MAX_DELEGATION_LIFETIME_SECS. After expiration, payment fails closed and prompts the caller for a new passkey approval.

Every payment requires human approval before settlement. The turn uses the same approval_request / approval_response pause as other sensitive tools. After settlement, a signed outbound_payment_receipt records the onchain reference and approved call in the event log. You can replay the log to audit each payment. A SecretStore stores keys in per-wallet Kubernetes Secrets in a cluster, or a local directory during development. Keys never enter the event log. Payments describes wallet linking and self-service tools.

Persisted event kinds

KindRecordsSigned?
turn_start / turn_completeAtomic-batch boundaries (workflow-event semantics)
user_msg / output_msgWire-encoded transcript messages
usagePer-turn input/output tokens (cost ledger)
summaryAnchored-iterative compaction of the older transcript
approval_request / approval_responseHuman-in-the-loop pause and decisionresponse ✓
handoff / handoff_deniedOne-way transfer to another agent, and a refused transfer
outbound_payment_receiptSettled agent payment: onchain reference bound to the approved call

Observability

A turn spans three planes, several pods, and an external provider. Server components using the shared runtime expose health, metrics, tracing, and logging interfaces so you can inspect a request across components.

SurfacePurpose
/healthz /livez /readyzHealth and readiness probes for Kubernetes, exposed by server components using the shared runtime.
/metricsPrometheus metrics for aggregate activity, exposed by the same side server.
OTLP tracesSpans from each plane, connected in one trace tree.
LogsLogs from each binary. RUST_LOG and RUST_LOG_FORMAT configure the tracing subscriber.

The W3C traceparent header connects control-plane and harness spans in one trace. That trace includes the public API, persistence, reconciliation, harness execution, and LLM provider calls. Set OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_SERVICE_NAME to enable the shared exporter.