API Reference
Sidecar Protocol
Last updated 2026-04-13
Sidecar Protocol
This document defines the current mustard-sidecar process contract.
Transport
The default transport is a length-prefixed binary frame over stdio:
u32little-endian header lengthu32little-endian binary payload length- UTF-8 JSON header bytes
- raw payload bytes
The JSON header carries ordinary protocol metadata such as method, id,
protocol_version, policy/auth fields, and structured guest values. Raw
program bytes and raw snapshot bytes travel in the binary payload section
instead of base64 fields.
The current protocol version is 2.
Debug mode is still available:
mustard-sidecar --jsonlswitches to newline-delimited JSON over stdio- JSONL mode preserves the older inspectable
program_base64andsnapshot_base64fields for debugging and corpus seeding
Safety limits:
- binary request frames larger than
1 MiBfail closed before protocol parsing - JSONL request lines larger than
1 MiBfail closed before JSON parsing - empty JSONL lines are ignored
Request Methods
mustard-sidecar accepts three request methods:
compilestartresume
All requests include:
protocol_version- an integer
idchosen by the host
The sidecar treats id as a correlation token only: it echoes the value back
verbatim and does not require request IDs to be unique.
compile
Binary-frame header:
{
"protocol_version": 2,
"method": "compile",
"id": 1,
"source": "const value = 1; value;"
}
compile does not send a binary payload. Successful responses return:
- a session-local
program_id - raw compiled program bytes in the binary payload section
In --jsonl mode, the same response exposes program_base64 instead.
start
Binary-frame header using a cached program:
{
"protocol_version": 2,
"method": "start",
"id": 2,
"program_id": "...",
"options": {
"inputs": {},
"capabilities": ["fetch_data"]
}
}
start requires either:
program_idfor a compiled program already cached in the current sidecar session- or raw program bytes in the binary payload, which may also seed that session cache
If both a program_id and inline program bytes are supplied, the digest must
match or the request fails closed. If neither is supplied, the request fails
closed.
Successful responses return either:
- a completed value with no binary payload
- or a suspended step containing
capability,args, plussnapshot_idandpolicy_idin the JSON header and raw snapshot bytes in the binary payload
In --jsonl mode, suspended steps expose snapshot_base64 instead of a raw
payload blob.
resume
Binary-frame header using cached snapshot/policy state:
{
"protocol_version": 2,
"method": "resume",
"id": 3,
"snapshot_id": "...",
"policy_id": "...",
"auth": {
"snapshot_key_base64": "...",
"snapshot_key_digest": "...",
"snapshot_token": "..."
},
"payload": {
"type": "value",
"value": { "Number": { "Finite": 1.0 } }
}
}
payload.type is value, error, or cancelled.
resume accepts either:
- raw snapshot bytes in the binary payload plus full
policy - or cached
snapshot_idplus cachedpolicy_idplus freshauth
The host must still reassert the authoritative restore policy before the sidecar will inspect or resume a loaded snapshot.
- Full
policyrequests must includecapabilities,limits,snapshot_id,snapshot_key_base64,snapshot_key_digest, andsnapshot_token. - Cached
policy_idrequests reuse thecapabilitiesandlimitsseeded from the originalstartrequest in the same sidecar session, but the host must still supply freshauthmetadata for the specific suspended snapshot being resumed.
The token is the lowercase hex HMAC-SHA256 of the detached snapshot_id under
the caller-chosen snapshot key. The sidecar recomputes snapshot_id from the
supplied raw snapshot bytes or from the cached bytes referenced by
snapshot_id before trusting the snapshot contents.
Response Shape
Every response includes:
protocol_versionidokresulton successerroron failure
Failures are rendered as guest-safe or protocol-safe strings and do not expose raw host capabilities or internal runtime handles.
Requests with a missing or unsupported protocol_version fail closed with an
explicit protocol-version error instead of attempting best-effort compatibility.
Capability Proxy Model
The sidecar does not execute host capabilities itself.
Instead:
- the guest hits a host boundary inside the shared Rust core
- the sidecar returns a suspended step with a capability name and structured arguments
- the embedding host performs the actual host work locally
- the host sends either a structured
resumevalue or a sanitizedresumeerror back to the sidecar
That means capability proxying happens through suspension and resume, not by shipping host callbacks or JavaScript functions into the sidecar process.
Session Semantics
- The sidecar keeps a session-local compiled-program cache keyed by
program_id. - The sidecar keeps a session-local suspended-snapshot cache keyed by
snapshot_id. - The sidecar keeps a session-local capability/limits cache keyed by
policy_id. compilereturns both raw program bytes and the matchingprogram_id.startmay reference a cachedprogram_idinstead of resending program bytes, but those IDs only remain valid for the lifetime of the current sidecar process.- Suspended
startandresumeresponses returnsnapshot_id, so laterresumerequests may reference cached bytes without resending the snapshot payload. - Suspended
startresponses also returnpolicy_id, so laterresumerequests may reference cached capability/limits metadata without resending it on every hop. - Hosts may still replay the same snapshot bytes in multiple
resumerequests as long as they preserve or recompute the matching detachedsnapshot_id,snapshot_key_digest, andsnapshot_token. - Replaying a snapshot re-executes from that suspension point deterministically
under the supplied
policy; there is still no in-sidecar single-use tracking. - If the embedding host wants stronger single-use or anti-replay guarantees, it must enforce them above this protocol boundary.
Lifecycle and Shutdown
- EOF on stdin is a clean shutdown signal. The sidecar exits successfully after processing all prior requests.
- Invalid request frames are fatal. The sidecar reports an error to stderr and exits with a non-zero status.
- The protocol is request/response only. There is no background push channel or heartbeat.
Termination
- Because cooperative cancellation is not implemented yet, hosts that need a hard stop must terminate the sidecar process.
- The sidecar is a separate process specifically so hosts can do that without corrupting the embedding process.
- Hard-stop semantics are therefore OS-process semantics, not an in-band protocol message.
- Once a sidecar is forcefully terminated, the embedding host must treat that process as dead and must not reuse its stdio channel.
- Any in-flight request is lost when the process is killed. To continue work,
the host starts a fresh sidecar and replays a previously persisted compiled
program blob or suspension snapshot, or recompiles from source if no saved
artifact exists. Cached
program_id,snapshot_id, andpolicy_idvalues do not survive process termination.