Skip to content

WebSocket reference

The unified live endpoint is GET /ws. It carries JSON text frames with a kind discriminator from server to client and a cmd discriminator from client to server. Authentication applies to the HTTP upgrade request.

On connect, the server sends ready, then an authoritative snapshot of live runs, every pending MCP approval, and any Session or Workspace Ways transition that currently owns primary-runtime teardown. A client that falls behind the broadcast buffer is disconnected so its normal reconnect can hydrate from a fresh snapshot rather than continuing with silently missing frames.

{ "cmd": "ping" }

Returns { "kind": "pong" }.

{
"cmd": "session",
"id": "session-id",
"input": "Implement the requested change.",
"display_input": "Implement the requested change.",
"context_references": [],
"turn_id": "browser-stable-turn-id",
"idempotency_key": "browser-stable-send-id",
"reference_ids": [],
"model_override": null,
"target_agent": null
}
FieldMeaning
idSession ID
inputEffective execution input, including any structured inline context rendering
display_inputOptional user-visible composer text stored separately from execution expansion
context_referencesImmutable inline editor/Preview reference snapshots
turn_idStable client identity for durable accept, reconnect, and exact Stop; generated if absent
idempotency_keyStable send-attempt identity; defaults to turn_id
reference_idsSession-owned uploaded attachment relations
model_overrideOptional one-turn model within the Agent provider
target_agentOptional one-Agent target in a multi-Agent Session

If the same accepted identity is already running, the runtime reattaches rather than starting duplicate work. The normal sequence is session-accepted, session-start, streaming frames, then exactly one terminal Session frame.

{
"cmd": "session-stop",
"id": "session-id",
"turn_id": "browser-stable-turn-id"
}

A stale or already-finished ID produces session-stop-rejected. Stop is cooperative; a started tool may reach a safe boundary before terminal state.

{
"cmd": "mcp-approve",
"approval_id": "approval-id",
"decision": "allow",
"persist": "once"
}

decision is allow or deny. persist is one of:

  • once;
  • agent_tool;
  • agent_server;
  • any_agent_server.

An unknown/already-resolved ID returns mcp-approval-unknown.

CommandFieldsPurpose
run-workflowid, inputRun a manual Automation through the legacy workflow stream
chat-turnchat_id, contentRun one lightweight compatibility Chat turn
chat-stopchat_idStop the active compatibility Chat stream

These retained commands do not create separate browser destinations.

kindImportant fieldsMeaning
ready—Upgrade handling is ready
snapshotruns, approvals, environment_transitions?, attempt_ownerships?Complete live-run, pending-approval, and active primary-runtime ownership state at connection time
pong—JSON ping response
errormessageMalformed/unsupported command error

Each snapshot run includes workflow (the run key), optional turn_id, optional attempt_set_id, kind (workflow, session, or attempt), Agent buffers/status, optional awaiting-human state, and coordinator plan fields when present. A lane run key alone can be reused by a later set, so clients must also compare attempt_set_id.

Each environment_transitions entry carries session and the durable environment generation that teardown invalidated. An omitted or empty array means no environment transition owns teardown at that snapshot cursor. Clients should still re-read the canonical Session record after reconnect because a complete transition may have happened while the socket was offline.

Each attempt_ownerships entry carries workspace, the owning session, and the durable attempt_set_id. Every Session anchored to that Workspace must suspend primary Files, Source Control, Preview, and Terminal access until the exact set settles. The array is hydrated from durable current-set pointers, so an unresolved Ways decision remains authoritative after a daemon restart.

kindImportant fieldsMeaning
session-acceptedsession, turn_idDurable begin exists
session-startsession, turn_id?Execution started
tokenworkflow, agent, turn_id?, deltaText delta
reasoningworkflow, agent, turn_id?, deltaReasoning-channel delta when supplied
tool-callworkflow, agent, turn_id?, call_id, occurrence, name, phase, arguments?, result?, is_errorTool start/result pair
session-donesession, turn_id?, input/output/reasoning tokens, token_usage_knownSuccessful terminal state; a false known flag marks the counts as a subtotal
session-cancelledsession, turn_id, input/output/reasoning tokens, token_usage_knownCooperative Stop terminal state; a false known flag marks the counts as a subtotal
session-errorsession, turn_id?, error, input/output/reasoning tokens, token_usage_knownFailed terminal state; paid work completed before the failure remains visible as a complete tracked total or known subtotal
session-stop-rejectedsession, turn_id, errorStop control response; not a terminal transition
session-environment-changingsession, generationThe Session runtime is unavailable while an explicit change, Close/Delete, or cold reconstruction owns its lifecycle boundary
session-environment-settledsessionThe announced lifecycle owner exited on success, failure, or cancellation; re-read the canonical Session before exposing runtime-backed tools
workspace-attempt-changingworkspace, session, attempt_set_idThe exact Ways set is taking exclusive Workspace ownership; suspend primary runtime surfaces for every Session in that Workspace
workspace-attempt-settledworkspace, attempt_set_idThe exact set’s durable current pointer is gone; re-read and reconstruct the primary runtime before exposing it

occurrence distinguishes repeated provider-local call IDs. Correlate tool start/result with the run, Agent, turn, call ID, and occurrence rather than assuming call_id is globally unique. For coordinator work, agent is the logical declared Worker that executed the tool; workflow and turn_id retain the outer Session/turn ownership.

Environment lifecycle frames are broadcast to every connected client, not only the tab that issued an HTTP request. Suspend Files, Source Control, Preview, and Terminal work on session-environment-changing. The settled frame is not a success claim: the canonical Session may now be Ready, Failed, Closed, or deleted.

Workspace attempt frames are also broadcast before primary runtime teardown. Settlement is exact-set guarded, so a delayed frame from an older exploration cannot release a newer set’s suspension. A reconnecting client must replace its local ownership map from attempt_ownerships; an empty array can mean a whole start-to-Keep/Discard lifecycle completed while it was offline, so any runtime surface bound before the outage must still be revalidated. For the owning Session, an exact settlement also re-reads durable Results, canonical History, and current Git state before restoring the primary runtime; this clears a completed comparison and hydrates the kept Turn without trusting the event as the result itself.

kindImportant fieldsMeaning
lane-startedrun, attempt_set_id, session, index, model?, agentDurable identity for one Way’s live stream
lane-verifiedattempt_set_id, session, index, passed, changed_files, touched_testsOne Check result arrived
coordinator-planworkflow, coordinator, goal, subtasksCoordinator decomposition and auction outcome

Other Agent stream frames for an Attempt use the lane run key. Reject frames whose set ID belongs to a previous exploration.

Events and Automation compatibility frames

Section titled “Events and Automation compatibility frames”
kindImportant fieldsMeaning
eventtype, agent?, task?, name?, output?, tokens?, workflow?Typed lattice/runtime notification
workflow-doneworkflow, output, completed, tokens, token_usage_knownLegacy manual workflow terminal success; a false known flag marks tokens as a subtotal
workflow-errorworkflow, error, input/output/reasoning tokens, token_usage_knownLegacy manual workflow terminal failure; paid Agent work before the structural error remains visible

Canonical Automation run and node history should also be read through the HTTP run endpoints. The event frame is an integration feed, not a separate workbench timeline.

Coordinator Worker lifecycle events use AgentActivated, TaskCompleted, AgentFailed, AgentCancelled, and AgentPanicked. Their agent is the stable logical Worker id, not its Session-scoped actor/checkpoint id.

kindImportant fieldsMeaning
mcp-approval-requiredapproval_id, run?, agent_id, server, tool, tool_display, arguments_preview, requested_atA call is parked for a decision
mcp-approval-resolvedapproval_id, decisionClose the prompt in every connected client
mcp-approval-unknownapproval_idThis client tried to resolve a non-pending ID

Pending approvals are included in snapshot, including approvals that cannot be associated with a scoped run.

kindImportant fields
chat-startchat_id, turn_id, agent
chat-tokenchat_id, turn_id, delta
chat-reasoningchat_id, turn_id, delta
chat-tool-startchat_id, turn_id, agent, call_id, name, arguments
chat-tool-resultchat_id, turn_id, agent, call_id, name, result, is_error
chat-donechat_id, turn_id, input/output/reasoning/total tokens, token_usage_known
chat-stoppedchat_id, turn_id, input/output/reasoning/total tokens, token_usage_known
chat-errorchat_id, turn_id, error, input/output/reasoning/total tokens, token_usage_known

These are sent directly to the connection that issued the Chat command; common token/session projections can also appear on the shared bus. chat-stop requests cooperative cancellation of the current turn_id; the terminal frame is sent only after that run reaches a safe boundary and its queued deltas have drained. A false known flag marks the numeric fields as a known subtotal.

Interactive PTYs use a distinct endpoint:

GET /api/sessions/{id}/terminals/{tid}/ws

The server first sends retained scrollback, then raw terminal output as binary frames. Send keystrokes as binary or text. Send resize as JSON text:

{ "kind": "resize", "rows": 40, "cols": 120 }

An unknown terminal is rejected before upgrade with HTTP 404 JSON. If a connected client falls behind the bounded output broadcast, the server closes that socket with code 4001 and reason terminal-resync-required; clear the stale terminal view and reconnect for a fresh retained-scrollback snapshot instead of appending across the gap.