Skip to content

JSON Stream Protocol

When you run Wayland Core with --json-stream, it speaks a line-based JSON protocol over stdin and stdout instead of rendering a terminal UI. This is how a host process (an Electron app, a Node service) drives the engine: one process per conversation, kept alive across turns. stderr stays out of the protocol and carries diagnostic logs.

Terminal window
wayland-core --json-stream --provider anthropic

Transport is JSON Lines: one UTF-8 JSON object per line, each with a type field.

The engine emits a ready event once initialization finishes. The host must wait for it before sending anything. ready carries the protocol version, a session_id, and a capabilities object announcing which event variants this run will emit (tool approval, thinking, MCP, and more).

{ "type": "ready", "version": "0.2.0", "session_id": "a1b2c3", "capabilities": { "tool_approval": true, "mcp": true } }

The engine streams a turn as events: stream_start, text_delta, thinking, tool_request, tool_running, tool_result, tool_cancelled, and stream_end, among others. A tool_request pauses execution and waits for the host to approve or deny.

The host writes commands to stdin. The core set:

CommandPurpose
messageSend a user message (with optional attached files)
stopAbort the current response stream
tool_approveApprove a pending tool call (scope once or always)
tool_denyDeny a pending tool call, with a reason
set_modeSwitch approval mode: default, auto_edit, force (yolo is an accepted alias)
set_configChange model, thinking, effort, or compaction at runtime
add_mcp_serverInject an MCP server before the first message
pingHeartbeat; the engine replies with pong
{ "type": "message", "msg_id": "m1", "content": "Read src/main.rs and explain it" }

A tool_request blocks until the host answers with tool_approve or tool_deny. Approving with scope: "always" adds the tool’s category to the session allow-list so later calls skip the gate.

add_mcp_server injects a server during the pre-message window: after ready and before the first message. The engine replies with mcp_ready listing the new tools. The first message closes the window, and later injection attempts are rejected.

The host should tolerate event types it does not recognize. New variants stay off in config until a release enables them, and default-off capability flags are omitted from ready, so older hosts see the shape they expect. The full wire format lives in docs/json-stream-protocol.md in the engine repository.