# Claude Code Stream JSON

> Use Claude Code CLI in stream-json mode for real-time bidirectional JSON communication. Enables agents to pipe JSON messages to Claude and receive streaming JSONL output with full session observability including tool calls, deltas, and results.

- Skill: `tankygranny05/claude-code-stream-json` (Agent Skill)
- Install (CLI): `npx skillmds@latest add tankygranny05/claude-code-stream-json`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tankygranny05/claude-code-stream-json/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: tankygranny05 (https://skillmd.com/u/tankygranny05)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/tankygranny05/claude-code-stream-json

---


# Claude Code Stream-JSON Mode
*[Created by Opus: 134bdda1-e4e8-45b4-ab3a-666a2d89509c]*

## TL;DR - Quick Start

```bash
echo '{"type":"user","message":{"role":"user","content":"Hello, what is 2+2?"}}' | \
  claude --print --input-format=stream-json --output-format=stream-json \
    --verbose --dangerously-skip-permissions | jq
```

**Required flags:**
- `--print` (`-p`) - Non-interactive mode
- `--input-format=stream-json` - Accept JSON input from stdin
- `--output-format=stream-json` - Emit JSONL output
- `--verbose` - Required when using stream-json output

**Common optional flags:**
- `--include-partial-messages` - Emit assistant message snapshots as content accumulates
- `--replay-user-messages` - Echo user messages back to stdout for acknowledgment
- `--dangerously-skip-permissions` - Skip permission dialogs (use in trusted environments)

---

## Full Sample Command

This example pipes a user prompt requesting project analysis and report generation:

```bash
echo '{"type":"user","message":{"role":"user","content":"Tell me about this project. '\
  'Tell me what the nearest commit implemented. '\
  'Also, are there committed code? What are they for? '\
  'Write a report to /tmp/throwaway/"}}' | \
     ~/symlinks/claude --print --input-format=stream-json --output-format=stream-json \
    --verbose --include-partial-messages --replay-user-messages \
    --dangerously-skip-permissions | tee /tmp/sample_output.jsonl | jq
```

## Input Format

Send newline-delimited JSON objects to stdin. Each message must have this structure:

```json
{"type":"user","message":{"role":"user","content":"Your prompt here"}}
```

### Multi-turn Conversations

Send multiple user messages sequentially. Each becomes a new turn:

```bash
cat << 'EOF' | claude -p --input-format=stream-json --output-format=stream-json --verbose
{"type":"user","message":{"role":"user","content":"What is Python?"}}
{"type":"user","message":{"role":"user","content":"Show me a hello world example"}}
EOF
```

## Output Format (JSONL)

Claude emits newline-delimited JSON. Each line is a complete JSON object with a `type` field.

### Message Types

| Type | Description |
|------|-------------|
| `system` | Session initialization with metadata (subtype: `init`) |
| `user` | User message (echoed back when `--replay-user-messages`) |
| `assistant` | Complete or partial assistant message snapshot |
| `stream_event` | Raw streaming event from Claude API |
| `result` | Final session result (subtype: `success` or `error`) |

### 1. System Init Message

First message emitted, contains session metadata:

```json
{
  "type": "system",
  "subtype": "init",
  "cwd": "/Users/sotola",
  "session_id": "d4b6edfb-892e-419d-b725-7fbf0fc2fc30",
  "tools": ["Task", "Bash", "Read", "Edit", "Write", ...],
  "mcp_servers": [{"name": "browser", "status": "connected"}],
  "model": "claude-opus-4-5-20251101",
  "permissionMode": "bypassPermissions",
  "claude_code_version": "2.1.2",
  "uuid": "08d0607a-64c0-446c-be61-4e5a741792bf"
}
```

### 2. Stream Events

Raw API streaming events. Useful for real-time UI updates:

```json
{"type":"stream_event","event":{"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello"}},"session_id":"...","uuid":"..."}
```

Event subtypes:
- `message_start` - New message begins (includes model, usage)
- `content_block_start` - New content block (text or tool_use)
- `content_block_delta` - Incremental content (`text_delta` or `input_json_delta`)
- `content_block_stop` - Block completed
- `message_delta` - Message-level update (stop_reason)
- `message_stop` - Message completed

### 3. Assistant Messages

Complete assistant message snapshots (emitted when `--include-partial-messages`):

```json
{
  "type": "assistant",
  "message": {
    "model": "claude-opus-4-5-20251101",
    "id": "msg_01MTUH7myRjkMoTtTtuvPWUF",
    "type": "message",
    "role": "assistant",
    "content": [{"type": "text", "text": "I'll help you with that."}],
    "stop_reason": null,
    "usage": {"input_tokens": 2, "output_tokens": 15}
  },
  "session_id": "...",
  "uuid": "..."
}
```

### 4. User Messages (Tool Results)

Tool results appear as user messages with `tool_result` content:

```json
{
  "type": "user",
  "message": {
    "role": "user",
    "content": [
      {
        "tool_use_id": "toolu_01ChoXFfg2mf7vJisCeFMd7T",
        "type": "tool_result",
        "content": "file contents here",
        "is_error": false
      }
    ]
  },
  "tool_use_result": {
    "stdout": "file contents here",
    "stderr": "",
    "interrupted": false
  },
  "session_id": "...",
  "uuid": "..."
}
```

### 5. Result Message

Final message indicating session completion:

```json
{
  "type": "result",
  "subtype": "success",
  "duration_ms": 12345,
  "cost_usd": 0.05,
  "session_id": "...",
  "uuid": "..."
}
```

## Control Messages (Advanced)

For interactive streaming control, you can send control requests:

### Interrupt Generation

```json
{"type":"control_request","request_id":"abc123","request":{"subtype":"interrupt"}}
```

### Cancel Request

```json
{"type":"control_cancel_request","request_id":"abc123"}
```

Responses come back as `control_response` messages.

## Flag Reference

| Flag | Description |
|------|-------------|
| `--print` / `-p` | Required. Non-interactive print mode |
| `--input-format=stream-json` | Accept streaming JSON input |
| `--output-format=stream-json` | Emit streaming JSONL output |
| `--verbose` | **Required** with stream-json output |
| `--include-partial-messages` | Emit assistant message snapshots during streaming |
| `--replay-user-messages` | Echo user messages back with `isReplay: true` |
| `--dangerously-skip-permissions` | Bypass all permission dialogs |
| `--json-schema <schema>` | Validate structured output against JSON schema |

## Constraints & Validation Rules

1. **`--output-format=stream-json` requires `--verbose`**
   - Error: `--output-format=stream-json requires --verbose`

2. **`--input-format=stream-json` requires `--output-format=stream-json`**
   - Error: `--input-format=stream-json requires output-format=stream-json`

3. **`--include-partial-messages` requires both `--print` and `--output-format=stream-json`**
   - Error: `--include-partial-messages requires --print and --output-format=stream-json`

4. **`--replay-user-messages` requires both stream-json formats**
   - Error: `--replay-user-messages requires both --input-format=stream-json and --output-format=stream-json`

## Use Cases

### 1. Agent Orchestration
Parent agents can spawn Claude Code as a subprocess and communicate via JSON:

```python
import subprocess
import json

proc = subprocess.Popen(
    ['claude', '-p', '--input-format=stream-json', '--output-format=stream-json', '--verbose'],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    text=True
)

# Send prompt
msg = {"type": "user", "message": {"role": "user", "content": "List files"}}
proc.stdin.write(json.dumps(msg) + '\n')
proc.stdin.flush()

# Read streaming output
for line in proc.stdout:
    event = json.loads(line)
    if event['type'] == 'stream_event':
        # Handle real-time updates
        pass
    elif event['type'] == 'result':
        break
```

### 2. Real-time UI Updates
Stream text deltas to a web UI:

```bash
claude -p --input-format=stream-json --output-format=stream-json --verbose | \
  while read -r line; do
    echo "$line" | jq -r 'select(.type=="stream_event") | .event.delta.text // empty'
  done
```

### 3. Session Logging & Observability
Capture full session for replay/analysis:

```bash
echo '{"type":"user","message":{"role":"user","content":"..."}}' | \
  claude -p --input-format=stream-json --output-format=stream-json \
    --verbose --include-partial-messages \
  | tee session.jsonl | jq
```

### 4. Daemon Mode (SDK Integration)
The `--daemon` flag automatically enables stream-json mode:

```bash
claude --daemon  # Implies: --output-format=stream-json --verbose
```

## Extracting Specific Data

### Get Final Text Output

```bash
cat session.jsonl | jq -r 'select(.type=="assistant") | .message.content[]? | select(.type=="text") | .text' | tail -1
```

### Get All Tool Calls

```bash
cat session.jsonl | jq 'select(.type=="assistant") | .message.content[]? | select(.type=="tool_use")'
```

### Get Session ID

```bash
cat session.jsonl | jq -r 'select(.type=="system" and .subtype=="init") | .session_id' | head -1
```

### Calculate Total Cost

```bash
cat session.jsonl | jq -r 'select(.type=="result") | .cost_usd'
```

