Skip to content

JSONL events

wuu exec --json writes one JSON object per stdout line. Every object has a type; diagnostics go to stderr. This stream describes an execution run, rather than exposing the app-server’s wire messages unchanged.

Dispatch on type, tolerate additional fields and unknown event types, and keep reading until result. Track a session by thread_id, a turn by turn_id, a tool call by item_id, and a subagent by agent_id. run_id is included on result and the structured-output error event, not on every progress event.

One run can contain several turns. Neither a final message replacement nor turn_completed is the run’s terminal signal. Check the process exit code too: invalid CLI input can fail before emitting JSONL, and a killed process or broken output pipe may leave no complete result. See wuu exec for exit codes.

SIGINT, SIGTERM, and timeouts attempt to emit a terminal result after cancelling execution. This cannot be guaranteed when the output consumer is stalled or disconnected. Input collection can also be cancelled before JSONL begins. Drain the stream continuously: pending events are bounded, and subscription overflow is a protocol failure rather than a successful but incomplete stream.

{
"type": "result",
"status": "completed",
"thread_id": "thread-id",
"turn_id": "turn-id",
"run_id": "run-id",
"final_message": "The report is ready.",
"trace_path": "/path/to/trace.jsonl"
}

status is completed, failed, permission_denied, timeout, or interrupted. Failures can include an error string. Identifiers can be empty when setup failed before a session or run existed. final_message on failure can be partial; it is not proof that the requested work finished. With --output-schema, successful validation also supplies structured_result, the parsed JSON value.

The separate error event currently reports a disagreement between the CLI’s final schema validation and the server’s completed run. It includes error and retrying: false. It is not a general error channel: inspect result even when no error event appeared.

TypePayload and meaning
session_configuredprotocol_version, provider, model, max_parallel, workspace_root, permissions after initialization
thread_started, thread_resumed, thread_forkedthread_id, provider, model, cwd for the acquired session
turn_startedthread_id, turn_id; begins a new turn’s message state
agent_message_deltaAppend delta to the current message
agent_message_finalReplace the accumulated message with message; this is a replacement event, not a guaranteed end marker
usage_updatedCumulative input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens for the turn
turn_completedToken counts, trace_path, and awaiting_auto_continuation
turn_failederror for the failed turn
turn_interruptedreason, such as timeout or interrupted

thread_started also occurs for ephemeral sessions, so it does not imply durable storage. Usage snapshots are not deltas: use the latest snapshot per turn rather than summing every event. When awaiting_auto_continuation is true another turn is expected; even when it is false, wait for result to determine run settlement.

session_configured describes runtime defaults. On resume or fork, the acquired thread event reports the session’s actual model route after any explicit CLI selection; it may differ from those defaults.

{"type":"tool_started","thread_id":"thread-id","turn_id":"turn-id","item_id":"item-id","name":"read_file","arguments":"{\"path\":\"README.md\"}"}
{"type":"tool_output_delta","thread_id":"thread-id","turn_id":"turn-id","item_id":"item-id","delta":"output fragment"}
{"type":"tool_completed","thread_id":"thread-id","turn_id":"turn-id","item_id":"item-id","name":"read_file","status":"completed","error":""}

arguments is a JSON-encoded string, not an object. tool_completed supplies the call status and error; it does not repeat the full result. Accumulate output deltas if your client needs that content. tool_removed withdraws an item by item_id.

For bash, the stream additionally emits command_started, command_output_delta, command_completed, and command_removed. These refer to the same item, so do not count them as separate tool calls. Command events add name, command, and arguments when available; completion adds status and error. Background-process control calls also use this family. Completion of the tool call does not necessarily mean the underlying background process has exited.

file_changed is derived from structured file-tool results, not a filesystem watcher. It carries tool_name, path, and action, with available hashes and workspace_revision; it does not include full file contents or diffs. Do not use it as a complete list of every write made by shell commands or external processes.

subagent_started, subagent_updated, and subagent_completed carry agent_id, thread_id, agent_type, status, and task metadata. Available fields include task_name, agent_profile, agent_path, parent_id, description, result, result_path, result_bytes, result_truncated, error, and token counts. A first observed update may already be terminal, so a client must not require a preceding subagent_started. Use result_path when the inline result is truncated.

todo_updated carries the task-list payload in todo. These progress events depend on the active tools and plugins; a run need not emit every event family.

provider_state describes one provider step: step_index, provider, protocol, transport, replay and connection reuse, fallback state, failure phase, and input item counts. Fallback fields include fallback_active, fallback_reason, fallback_transport, fallback_pin_status, fallback_retry_after_ms, and fallback_ttl_ms. They describe transport behavior, not task completion.

request_context describes the composed request through counts, byte sizes, segment categories, hashes, and cache metadata. It includes message and tool counts; system, stable-prefix, turn-prefix, and tool-surface hashes; prompt_cache_key; and, when available, system_sections. It is diagnostic metadata, not a full request body from which the model input can be reconstructed.

The CLI omits provider reasoning notifications. Tool argument redaction is best effort; the stream can still contain private source, prompts, paths, and tool output. Treat it as sensitive task data and review it before publishing logs.

The field mapping is implemented in internal/exec/runner.go. For clients that need direct session control, use the app-server protocol.