Wire Protocol
The shipped Chio wire protocol, defined tightly enough for an independent implementation. Native length-prefixed framing, hosted MCP HTTP session transport, and trust-control lifecycle endpoints share one signed-artifact contract for capabilities and receipts.
When to use this page
Source
This page normatively reflects spec/WIRE_PROTOCOL.md in the chio repository. Status: Normative shipped surface. Version 1.0. The keywords MUST, SHOULD, and MAY are normative.
Surface Model
Chio ships four cooperating protocol surfaces:
| Surface | Transport | Purpose |
|---|---|---|
| Native Chio transport | Length-prefixed canonical JSON | Direct agent-to-kernel messaging |
| Hosted MCP edge | JSON-RPC over HTTP POST plus SSE | Remote session admission and MCP-compatible runtime traffic |
| Trust-control lifecycle APIs | JSON over HTTP | Capability issuance, delegated issuance, receipt lookup, revocation |
| HTTP substrate | JSON over HTTP (localhost sidecar) | Evaluation and receipt signing for arbitrary HTTP API requests |
The native Chio transport does not define a session-initialization message. Initialization in the shipped stack happens on the hosted MCP surface. Native direct peers obtain capability material out of band and then begin sending AgentMessage frames immediately.
Native Chio Transport
Framing
Each native Chio frame is encoded as:
+----------------------+---------------------------+
| 4-byte length prefix | canonical JSON payload |
+----------------------+---------------------------+Normative rules:
- The length prefix MUST be an unsigned 32-bit integer in big-endian byte order.
- The length value MUST count only the payload bytes that follow the prefix.
- The payload MUST be canonical JSON as produced by RFC 8785-style canonicalization.
- The maximum permitted payload length is
16,777,216bytes (16 MiB). - A sender MUST NOT emit a larger frame.
- A receiver MUST reject any frame whose advertised length exceeds that maximum.
Example: a payload length of 256 bytes is encoded as 00 00 01 00.
Sender Requirements
- Senders MUST serialize native messages as canonical JSON before writing the frame.
- Senders MUST emit exactly one top-level JSON object per frame.
- Senders MUST use the discriminators and field names defined in the message catalog.
Receiver Behavior and Error Recovery
- If EOF occurs before the 4-byte prefix is fully read, the receiver MUST treat the connection as closed and deliver no partial message.
- If EOF occurs after the prefix but before the full payload is read, the receiver MUST treat the connection as closed.
- If the advertised length is greater than 16 MiB, the receiver MUST reject the frame as
message_too_large. - If the payload is not valid JSON for the expected message family, the receiver MUST reject the frame as a deserialization failure.
Recovery: Chio defines no in-band resynchronization marker for the native framed lane. After connection_closed, message_too_large, or deserialization failure, an implementation SHOULD close the current transport and establish a new connection before continuing.
Native Message Catalog
AgentMessage
All agent-to-kernel frames are JSON objects with a type discriminator.
type | Required fields | Meaning |
|---|---|---|
tool_call_request | id, capability_token, server_id, tool, params | Invoke one tool under one signed capability |
list_capabilities | none | Ask the kernel for the caller's currently valid capabilities |
heartbeat | none | Liveness probe |
tool_call_request fields:
| Field | Type | Meaning |
|---|---|---|
id | string | Correlation identifier echoed by kernel responses |
capability_token | CapabilityToken | Signed authority for this call |
server_id | string | Target tool server identifier |
tool | string | Tool name within the target server |
params | JSON value | Tool arguments |
KernelMessage
type | Required fields | Meaning |
|---|---|---|
tool_call_chunk | id, chunk_index, data | Streaming chunk emitted before the final response |
tool_call_response | id, result, receipt | Terminal result plus signed receipt |
capability_list | capabilities | Reply to list_capabilities |
capability_revoked | id | Notification that a capability identifier is no longer valid |
heartbeat | none | Liveness reply |
ToolCallResult
KernelMessage.tool_call_response.result is a tagged object with a status discriminator.
status | Required fields | Meaning |
|---|---|---|
ok | value | Tool completed and returned a value |
stream_complete | total_chunks | Tool completed after streaming chunks |
cancelled | reason, chunks_received | Explicit cancellation |
incomplete | reason, chunks_received | Non-terminal interruption or upstream truncation |
err | error | Denial or failure |
ToolCallError
ToolCallResult.status = "err" carries a tagged error object with a code discriminator.
code | Required fields | Meaning |
|---|---|---|
capability_denied | detail string | Capability was malformed, invalid, or bound to the wrong subject |
capability_expired | none | Capability is outside its validity window |
capability_revoked | none | Capability identifier is revoked |
policy_denied | detail.guard, detail.reason | A policy guard denied the action |
tool_server_error | detail string | Upstream tool server failed |
internal_error | detail string | Kernel-side internal failure |
Signed Artifact Requirements
Two nested signed Chio artifacts appear directly on the native wire:
CapabilityTokenChioReceipt
Preserve nested signed objects
Hosted MCP HTTP Session Transport
Endpoint Shape
POST /mcpcarries JSON-RPC requests and notifications.GET /mcpis the notification replay/live stream.DELETE /mcpterminates an existing session.
Session headers:
MCP-Session-IdMCP-Protocol-Version
Initialization Rules
- An
initializerequest MUST be sent toPOST /mcp. - An
initializerequest MUST be a JSON-RPC request and therefore include anid. - An
initializerequest MUST NOT includeMCP-Session-Id. - A successful initialize response MUST return an SSE stream and include
MCP-Session-Idon the HTTP response. - After successful initialize, the client MUST send
notifications/initializedbefore relying on ready-state operations.
Established-Session Rules
- Non-initialize requests MUST include
MCP-Session-Id. - If the session has a bound protocol version and the client sends
MCP-Protocol-Version, that header MUST match the stored session value. - POST requests MUST use
Content-Type: application/json. - GET notification streams MUST include
MCP-Session-Id. - Ready-state methods such as
tools/listandtools/callMUST not run until the session has receivednotifications/initialized.
Notification Stream and Replay
- At most one active GET notification stream is allowed per session.
- Notification replay uses the
Last-Event-IDrequest header. - Event identifiers are encoded as
{session_id}-{sequence}. - Replay requests outside the retained event window fail with
409 Conflict. - Hosted deployments that reuse one upstream owner across multiple sessions MUST keep late notifications and task handles scoped to the originating session. They MUST NOT fan out unattributed notifications or allow a different session to act on a foreign task id.
Hosted Session Lifecycle
Hosted sessions move through these states:
initializingreadydrainingdeletedexpiredclosed
Requests against draining, deleted, expired, or closed sessions MUST not silently resume prior state. Clients encountering those terminal states MUST re-run initialization.
Version Negotiation
The machine-readable negotiation artifact for the shipped stack is spec/versions/chio-protocol-negotiation.v1.json.
- Clients MAY send
initialize.params.protocolVersion. - The server compares that value against its supported version set.
- The current shipped implementation supports one MCP protocol version:
2025-11-25. - Compatibility determination is therefore an exact-match test against that supported set.
- There is no downgrade path; unsupported requested versions are rejected rather than silently downgraded.
- On success, the selected version is echoed in
result.protocolVersionand exposed underresult.capabilities.experimental.chioProtocol.selectedProtocolVersion. - On failure, initialize is rejected with JSON-RPC
-32600plus a structured Chio protocol error descriptor inerror.data.chioError.
Model Metadata Admission
- Hosted
tools/callrequests MAY carry model metadata under either_meta.modelMetadataor_meta.chioModelMetadata. - The hosted edge normalizes that payload into Chio request
model_metadata. - Caller-supplied metadata MUST be treated as
assertedprovenance at admission time even if the caller marks itverified. - Receipts and downstream exports MUST preserve the effective provenance class instead of silently upgrading caller assertions into verified runtime truth.
Native Direct Transport Versioning
- Native Chio framed transport is currently
chio-wire-v1. - Native direct peers do not negotiate in-band today; compatibility is an exact-match, out-of-band requirement.
- Because no in-band downgrade exists, incompatible native peers MUST close or reset the transport instead of attempting best-effort interop.
Trust-Control Capability Lifecycle
The trust-control service is implemented by chio trust serve.
Capability Issuance
Endpoint: POST /v1/capabilities/issue.
Request body:
| Field | Type | Meaning |
|---|---|---|
subjectPublicKey | string | Ed25519 subject key in hex |
scope | ChioScope | Capability scope to issue |
ttlSeconds | integer | Requested lifetime |
runtimeAttestation | object, optional | Attestation evidence used by issuance policy |
Success response: { "capability": <CapabilityToken> }.
Federated / Delegated Issuance
Endpoint: POST /v1/federation/capabilities/issue.
Delegation-relevant request fields:
| Field | Meaning |
|---|---|
presentation | Passport presentation proving federated subject identity |
expectedChallenge | Challenge the presentation must satisfy |
capability | Requested issued capability body |
delegationPolicy | Optional signed ceiling for delegated issuance |
upstreamCapabilityId | Optional imported parent capability anchor for multi-hop lineage |
Success response fields:
| Field | Meaning |
|---|---|
capability | Newly issued child capability |
delegationAnchorCapabilityId | Optional lineage anchor persisted by trust-control |
subjectPublicKey | Resolved subject key used for issuance |
Normative delegation rules:
- If
upstreamCapabilityIdis supplied, the request MUST also carry a delegation policy bound to that exact parent capability id. - If a delegation policy is supplied, the requested child capability MUST NOT exceed the policy ceiling.
- The trust-control service MUST reject untrusted delegation-policy signers.
Receipt Query
Endpoint: GET /v1/receipts/query.
Supported query parameters: capabilityId, toolServer, toolName, outcome, since, until, minCost, maxCost, cursor, limit, agentSubject.
Response body fields: totalCount (integer), nextCursor (integer or null), receipts (array of receipt rows).
Revocation
Endpoint: POST /v1/revocations.
Request body: { capabilityId: string }.
Success response fields: capabilityId, revoked (boolean), newlyRevoked (boolean, whether this call changed state).
Error Taxonomy
The machine-readable error registry for the shipped stack is spec/errors/chio-error-registry.v1.json. Registry guarantees:
- every Chio error entry has a unique numeric code
- every entry names one category
- every entry is marked
transient: true|false - every entry carries explicit retry guidance
Current registry categories: protocol, auth, capability, guard, budget, tool, internal.
Surface mapping rules:
- Native Chio
ToolCallErrordiscriminators map deterministically to registry entries such ascapability_denied,capability_expired,capability_revoked,guard_denied,tool_server_error, andinternal_error. - Hosted MCP initialize-time protocol rejection communicates the numeric Chio protocol code under JSON-RPC
error.data.chioError.code. - Trust-control remains HTTP-status-driven, but registry codes define the stable cross-surface classification and retry semantics.
HTTP Substrate Surface
The HTTP substrate is a fourth cooperating protocol surface alongside the native Chio transport, the hosted MCP edge, and the trust-control lifecycle APIs. It enables Chio to evaluate and sign receipts for arbitrary HTTP API requests, not only agent-protocol traffic.
The HTTP substrate uses a sidecar model. A Chio kernel runs as a local process and exposes three HTTP endpoints on localhost:
| Endpoint | Method | Purpose |
|---|---|---|
/chio/evaluate | POST | Evaluate an HTTP request against loaded policy |
/chio/verify | POST | Verify a receipt signature |
/chio/health | GET | Sidecar health check |
All language-specific SDKs consume this surface. They are thin HTTP clients over the sidecar evaluation protocol, not independent policy engines. The kernel remains the single trust anchor for capability validation, guard evaluation, and receipt signing. See the HTTP Substrate page for the full normative spec.
Schemas and Conformance
Versioned native message schemas live under:
spec/schemas/chio-wire/v1/agent/spec/schemas/chio-wire/v1/kernel/spec/schemas/chio-wire/v1/result/spec/schemas/chio-wire/v1/error/
Schema files in those directories are the machine-readable contract for the native Chio message families. Implementations MUST continue to serialize the native message variants in a form accepted by those schemas. Schema validation MUST be exercised against live Rust serialization, not handwritten examples alone.