Skip to content

api daemon protocol

Zachary BENSALEM edited this page Aug 15, 2026 · 1 revision

Daemon protocol

Purpose

The daemon protocol is the versioned JSONL wire contract between a client and the headless Prime Agent daemon. It is the transport used by DaemonAgentConnection today and is intentionally JSON-serializable so a future remote gateway can proxy it without leaking transport details back into interactive mode. The wire contract lives in packages/coding-agent/src/modes/daemon/daemon-protocol.ts.

This page is a reference for the protocol mechanics and version history. The daemon architecture (socket ownership, workers, supervisor) is on the Daemon page.

Version constants

Defined in packages/coding-agent/src/modes/daemon/daemon-protocol.ts.

Constant Value Meaning
DAEMON_PROTOCOL_NAME prime-agent.daemon Protocol identity
DAEMON_PROTOCOL_VERSION 8 Wire protocol version
DAEMON_SCHEMA_REVISION 15 Monotonic wire-schema revision for field-sensitive compatibility checks
DAEMON_SCHEMA_ID protocol-8-schema-15-d28eaade1789 Canonical schema identity used for stale-daemon detection
DAEMON_COMMAND_ENVELOPE_MIN_PROTOCOL_VERSION 7 Version at which commands are wrapped in an envelope

DAEMON_PROTOCOL_VERSION is bumped for incompatible changes or when startup begins requiring behavior an older daemon cannot provide. DAEMON_SCHEMA_REVISION is bumped for additive schema changes (see the revision history). DAEMON_SCHEMA_ID is checked by prime-agent status to classify a daemon as current or stale (packages/coding-agent/src/cli/daemon-ps.ts).

Schema revision history

Recorded as comments in packages/coding-agent/src/modes/daemon/daemon-protocol.ts.

Revision Change
9 Published persisted RLM spawn depth on passive session rows
10 Published persisted RLM spawn depth on all session catalog rows
11 Added immediate get/set commands for active-session RLM max depth
12 Published idle-residency metadata on session summary rows
13 Narrowed agent-origin reach and roster wire shapes to the nuclear family
14 Carried the client's monotonic telemetry opt-out on attach and reattach
15 Added optional seedMessages on new_session (protocol 8)

Framing

Commands and events travel as JSON lines over the Unix socket.

Commands at protocol >= 7 use a DaemonCommandEnvelope:

{ "type": "command", "id": "...", "protocol": { "name": "prime-agent.daemon", "version": 8 }, "clientId": "...", "command": { "type": "list" } }

Events use a parallel DaemonEventEnvelope carrying an id, protocol, activeSessionId, sequence, cursor, and emittedAt, with the payload nested under event. Every event carries a monotonic sequence and a per-session cursor (generation + sequence) used for replay and resync.

On connect, the server immediately sends a daemon_hello frame with the protocol name/version, schemaId, schemaRevision, app version, runtime identity, a per-connection clientId, and the serverCapabilities list. The client advertises its own capabilities in attach/reattach.

Protocol version negotiation

  • The client sends its protocol version inside each command envelope and the hello advertises the server's version.
  • isDaemonCommandEnvelope accepts a command only when the envelope protocol version is between DAEMON_COMMAND_ENVELOPE_MIN_PROTOCOL_VERSION (7) and DAEMON_PROTOCOL_VERSION (8).
  • Rejected command lines are salvaged for their id (salvageDaemonCommandId) so parse failures still reach the sender as correlatable responses.
  • DaemonClient.request checks the negotiated hello against DAEMON_COMMAND_COMPATIBILITY before sending, and throws DaemonCapabilityUnavailableError when the server cannot honor the command.

Capability gating

Optional features go behind a negotiated server capability. Clients must check the capability before sending the command or depending on the event. Server capabilities are listed in DAEMON_DEFAULT_SERVER_CAPABILITIES in packages/coding-agent/src/modes/daemon/daemon-protocol.ts:

  • attach_snapshot, event_sequence (default client capabilities)
  • extension_ui, slim_attach, chunked_snapshot, client_owned_sessions
  • delete_rlm_subagent, heartbeat_catalog, heartbeat_management, model_catalog
  • side_question_transcript, transient_bash, session_input_admission, prompt_admission_cancellation, seed_messages

The command compatibility map, DAEMON_COMMAND_COMPATIBILITY, assigns each command a minProtocol, an optional minSchemaRevision, and an optional capability gate. The outbound event map, DAEMON_OUTBOUND_COMPATIBILITY, does the same for events. getDaemonCommandCompatibilities returns the effective gates for a command, folding in telemetry-policy and prompt-admission-cancellation gates when the command carries those optional fields.

Capability-gated examples

Capability Command(s) / event
client_owned_sessions complete_owned_session, promote_owned_session
delete_rlm_subagent delete_rlm_subagent
heartbeat_catalog heartbeats_list, heartbeats_changed event
heartbeat_management heartbeat_manage
model_catalog get_model_catalog
session_input_admission prompt, prompt_and_wait, steer, follow_up, resume_queue
prompt_admission_cancellation cancel_prompt_admission (also minSchemaRevision: 8)
seed_messages seedMessages on new_session (also minProtocol: 8, minSchemaRevision: 15)

Schema-gated examples

Gate Command
minSchemaRevision: 11 get_rlm_max_depth_status, set_rlm_max_depth
minSchemaRevision: 14 attach/reattach/create carrying a telemetry opt-out

Classification policy

Every daemon command, event, and response-shape change is classified as one of:

  • Backward-compatible: additive and safe for old daemons/clients to ignore. Most commands default to minProtocol: 7 (LEGACY_DAEMON_COMMAND).
  • Capability-gated: optional features behind a negotiated server capability; clients must check before sending.
  • Incompatible: requires bumping DAEMON_PROTOCOL_VERSION, or minProtocol/minSchemaRevision gates, and updating both compatibility maps plus both new-client/old-daemon and old-client/new-daemon tests.

The policy is documented in Patterns and conventions. Compatibility metadata is verified by tests in packages/coding-agent/test/daemon-protocol.test.ts, which assert the per-command gates and cover both version skew directions.

seedMessages on new_session

At protocol >= 8 (schema revision >= 15), the new_session command accepts an optional seedMessages array of { role: "user" | "assistant", text: string } entries appended to the fresh SessionManager before the swap resolves. Older daemons ignore unknown fields, so a client must not send seedMessages unless the negotiated hello meets the minProtocol: 8/minSchemaRevision: 15/seed_messages floor. getDaemonCommandCompatibilities adds the NEW_SESSION_SEED_MESSAGES_COMMAND gate only when seedMessages is present and non-empty, keeping bare new_session available on protocol 7. This is covered by the version-gates new_session seedMessages test in packages/coding-agent/test/daemon-protocol.test.ts.

Responses and replay

  • Responses are { id, type: "response", command, success: true, data? } or { id, type: "response", command, success: false, error, errorInfo? }.
  • Attach returns a DaemonAttachResult with a DaemonSessionSnapshot, lastEventSequence, and a DaemonReplayInfo computed from the client's resumeCursor (verdict complete, partial, or unavailable).
  • Slim (slim_attach) clients skip the legacy session_attached frame; chunked (chunked_snapshot) clients stream the transcript as session_snapshot_begin/chunk/end.

Related pages

Clone this wiki locally