Skip to content

Protocol Overview

Unofficial Documentation

This documents Claude Code's stream-json NDJSON protocol as observed in production. This is not an official Anthropic specification — the protocol is undocumented and can change between releases.

What is Stream-JSON?

Claude Code supports a machine-readable I/O mode where:

  • stdout emits one JSON object per line (NDJSON) — the output protocol
  • stdin accepts NDJSON messages — the input protocol (undocumented by Anthropic)

This is activated with --output-format stream-json and --input-format stream-json.

Invoking Claude Code

bash
claude -p \
  --input-format stream-json \
  --output-format stream-json \
  --verbose \
  --permission-mode default \
  --session-id <uuid>
FlagPurpose
-pNon-interactive / pipe mode
--input-format stream-jsonAccept NDJSON on stdin
--output-format stream-jsonEmit NDJSON on stdout
--verboseInclude full message snapshots (not just deltas)
--permission-modedefault | plan | acceptEdits | bypassPermissions | dontAsk
--session-idResume or tag a session

Protocol Architecture

┌──────────────┐         stdin (NDJSON)          ┌──────────────────┐
│              │  ───────────────────────────────>│                  │
│  Your Code   │                                  │   Claude Code    │
│              │  <───────────────────────────────│                  │
└──────────────┘         stdout (NDJSON)          └──────────────────┘

stdin messages:                    stdout events:
  user message                       system/init
  approve tool                       assistant (cumulative)
  deny tool                          user (tool results)
  tool result                        result (turn complete)

Event Lifecycle

A typical interaction follows this sequence:

1. Process starts           →  system/init (session_id, model)
2. Your code sends message  ←  {"type":"user","message":{...}}
3. Claude thinks            →  assistant (thinking block)
4. Claude responds          →  assistant (thinking + text blocks)
5. Claude calls a tool      →  assistant (thinking + text + tool_use blocks)
6. You approve the tool     ←  {"type":"approve","tool_use_id":"..."}
7. Tool executes            →  user (tool_result block)
8. Claude processes result  →  assistant (new text + possibly more tools)
9. Turn finishes            →  result (cost, tokens, duration)

Steps 3-8 may repeat multiple times in a single turn (agentic loop). The result event marks the end of a turn.

Key Concepts

Cumulative Snapshots (--verbose)

With --verbose, every assistant event contains all content blocks accumulated so far — not just the new ones. See Deduplication for how to handle this.

Double-Encoded Results

The result field in result and system/result events is a JSON string inside JSON:

json
{"result": "\"The actual text is inside escaped quotes\""}

You must JSON.parse() the result value to get the actual text.

Polymorphic Content

The content field in tool_result blocks can be a string, an array of text blocks, or null. See Gotchas for details.

Multi-Agent

Claude Code can spawn sub-agents, which produce their own interleaved events on the same stdout. See Multi-Agent for how the translator handles this.

Not affiliated with or endorsed by Anthropic.