Core concepts
Stream-JSON protocol
Integrate with the versioned line-delimited protocol for input, output, permissions, usage, and terminal events.
Splice uses JSON Lines for headless clients. Each nonempty line contains one JSON object.
Use schema version 2 for all input and output events.
{"schemaVersion":2,"type":"..."}
Output events also include runId. Splice redacts output fields before it writes
them to standard output.
Start a stream run
splice exec \
--input-format stream-json \
--output-format stream-json < request.jsonl
Use --output-format stream-json with ordinary text input when only the output
needs JSON Lines.
Input events
The input parser accepts message and prompt events.
{"schemaVersion":2,"type":"message","role":"user","content":"Inspect this repository."}
{"schemaVersion":2,"type":"prompt","content":"Report only blockers."}
Splice joins accepted content in input order with a blank line between items. At least one event must contain prompt text.
Unknown input fields fail validation. A client can therefore detect protocol drift instead of losing data silently.
Image input
A message event can include images. Each image contains a MIME type and
standard base64 data without a data-URL prefix.
{"schemaVersion":2,"type":"message","role":"user","content":"Explain this screenshot.","images":[{"mediaType":"image/png","data":"<base64>"}]}
Each decoded image has a 10 MiB limit. Unsupported media types and invalid base64 return a protocol error.
Output event types
A stream can emit these events:
run_start
reasoning
text
tool_call_start
tool_call_delta
tool_call
tool_result
permission_request
permission_decision
permission
usage
checkpoint
restore
warning
error
final
run_end
Clients must ignore output event types they do not recognize. Additive event types do not require a schema version change.
Run lifecycle
A normal stream begins with run_start and ends with run_end.
{"schemaVersion":2,"type":"run_start","runId":"run_20260810_abc123","sessionId":"session_abc123","cwd":"/repo","provider":"openai","model":"example-model","apiModel":"provider-model-name"}
{"schemaVersion":2,"type":"run_end","runId":"run_20260810_abc123","status":"success","exitCode":0}
The terminal run_end.exitCode is authoritative. An error event normally
precedes a non-successful run_end.
An interrupted run still attempts to emit its terminal events.
Pipeline progress
Headless splice exec runs the typed execution pipeline. Scheduled stages can
include:
- code writer;
- test generator;
- static analyzer;
- security auditor;
- test runner; and
- acceptance verifier.
The selected request tier determines the stage set. Design critique and step-back analysis are orchestration operations, not scheduled execution stages.
reasoning events carry status text, pipeline progress, and model-provided
reasoning text when a provider returns it.
{"schemaVersion":2,"type":"reasoning","runId":"run_20260810_abc123","delta":"Starting pipeline iteration 1\n"}
Reasoning events are progress data. Splice does not append them to the final answer.
Stage markers
Stage lifecycle markers are embedded in reasoning.delta. A marker starts with
\x00STAGE and ends with \x00.
The marker payload contains:
| Field | Meaning |
|---|---|
name |
Stage name |
status |
running, completed, failed, skipped, or incomplete |
detail |
A short status summary |
progress |
Integer progress from 0 through 100 |
changedFiles |
Paths reported by the stage |
The TUI uses these markers for its pipeline panel. Other consumers can ignore them.
Structured stage output
A model-backed stage returns typed data through a streamed tool-call envelope.
{"schemaVersion":2,"type":"tool_call_start","runId":"run_20260810_abc123","id":"call_0","name":"submit_code"}
{"schemaVersion":2,"type":"tool_call_delta","runId":"run_20260810_abc123","id":"call_0","delta":"{\"files\":["}
Concatenate tool_call_delta.delta values by id to reconstruct the complete
arguments.
These envelopes describe typed stage output. They do not execute a tool, so they
do not receive a tool_result event.
Tool execution
Real tool executions use a tool_call and tool_result pair.
{"schemaVersion":2,"type":"tool_call","runId":"run_20260810_abc123","id":"call_1","name":"read_file","args":{"path":"README.md"},"sideEffect":"read"}
{"schemaVersion":2,"type":"tool_result","runId":"run_20260810_abc123","id":"call_1","status":"ok","output":"...","truncated":false}
A tool result can also include changedFiles, a compact display object, and
redaction or truncation flags.
Permissions
A prompt-gated tool can emit a permission request.
{"schemaVersion":2,"type":"permission_request","runId":"run_20260810_abc123","id":"call_2","name":"write_file","action":"prompt","permission":"prompt","permissionMode":"ask","sideEffect":"write","reason":"Creates or overwrites files."}
An interactive surface can emit the decision:
{"schemaVersion":2,"type":"permission_decision","runId":"run_20260810_abc123","id":"call_2","name":"write_file","action":"allow","permissionGranted":true,"decisionReason":"approved in TUI"}
Headless exec has no interactive permission responder. A tool that lacks prior
approval can emit a request followed by a denied result.
A permission event can include risk, block, grant details, and an autonomy
value. Schema version 2 renamed the old sandbox violation field to block.
The bare permission event is a fallback for a permission action that does not
fit the request or decision categories.
Usage and cost
Splice emits one usage event for each model request when usage attribution is available.
{"schemaVersion":2,"type":"usage","runId":"run_20260810_abc123","provider":"openai","model":"example-model","stage":"code_writer","iteration":1,"usageSequence":1,"usageReported":true,"promptTokens":1200,"completionTokens":500,"totalTokens":1700}
Optional token fields are:
cachedInputTokens;cacheWriteTokens; andreasoningTokens.
Optional cost fields are:
costUsd;costStatus;costEstimated;costProvenance;pricingSource;pricingAsOf; andunpricedReason.
The provider and model fields identify the selected route. apiModel is a
run_start field and does not appear on usage events.
An unavailable price produces costStatus: "unpriced" and no costUsd. Clients
must not convert an unknown cost to zero.
Checkpoints
A checkpoint event reports file snapshots captured before a write.
{"schemaVersion":2,"type":"checkpoint","runId":"run_20260810_abc123","checkpoint":{"sequence":1,"tool":"submit_code","files":["README.md"]}}
restore is reserved for a future file-checkpoint restore event. Its checkpoint
object can include filesRestored, filesDeleted, and skipped paths.
Trajectory worktree recovery is separate from this reserved event.
Final result
Near the end of a pipeline run, text contains a short human summary. final
contains the serialized final result in its text field.
{"schemaVersion":2,"type":"final","runId":"run_20260810_abc123","text":"{\"run_id\":\"run-abc\",\"status\":\"completed\",\"tier\":\"light\",\"stages\":[]}"}
The event is a JSON object, but final.text is itself a JSON string for pipeline
and design-plan results. Decode text when the client needs result fields.
A pipeline result can contain run_id, status, tier, stage records, usage
totals, and abort_reason.
A design-plan run returns a design-plan result with completed, failed, and skipped task IDs. Each task runs as an independent pipeline run.
Worktree merge result
With --worktree --merge-back, Splice uses existing event types:
textfor a merge or a no-change result;warningfor a dirty-source skip or a merge conflict; anderrorwith codemerge_back_failedfor a merge operation error.
The worktree branch remains available when Splice does not merge it.
Errors
{"schemaVersion":2,"type":"error","runId":"run_20260810_abc123","code":"provider_error","message":"...","recoverable":false}
{"schemaVersion":2,"type":"run_end","runId":"run_20260810_abc123","status":"error","exitCode":3}
Clients should display the error message, retain the run ID, and use the final exit code for automation decisions.