Output formats: json / text / stream-json

Use claude -p's --output-format to handle Claude Code output in scripts and CI — structured json parsing, real-time stream-json event streams, default plain text, with jq and pipe recipes

Output formats: json / text / stream-json

In scripts, CI/CD, and automation pipelines you need more than a human-readable answer — you need structured data a program can parse. Claude Code's headless mode (claude -p) offers three output formats via --output-format, letting you wire Claude Code into a pipeline like any ordinary CLI tool.

This is a Claude Code capability and is independent of the upstream: whether Claude Code points at the official API or at QCode, --output-format works the same. This page focuses on output formats; for the full headless flag reference and CI templates, see Automation & CI/CD.


1. The three formats at a glance

Format Flag Output shape Use case
Plain text --output-format text (default) A single block of plain text Human reading, simple pipes
JSON --output-format json One structured JSON object Script parsing, reading cost/usage/session ID
Streaming JSON --output-format stream-json A newline-delimited JSON event stream Live progress, step-by-step consumption, long tasks
# text is the default, so these two lines are equivalent
claude -p "Explain idempotence in one sentence"
claude -p "Explain idempotence in one sentence" --output-format text

2. text: the default plain text

Without --output-format you get text: stdout is simply the model's final answer — good for reading directly or feeding a simple pipe.

# Read directly
claude -p "Rewrite this function to be async"

# Pipe to another tool
claude -p "Generate 5 candidate commit messages" | head -5

# Write to a file
claude -p "Write a short README intro for this repo" > intro.txt

Limitation: text gives you only the "answer" — no cost, token usage, or session ID metadata, and multi-step tasks can't be distinguished from the final result. When you need that, switch to json or stream-json.


3. json: a single structured object

--output-format json emits one JSON object after the task completes, containing the final result plus a batch of metadata fields. This is the format scripts use most.

claude -p "Count how many TODO comments are under src/" --output-format json

Common fields in the returned object (the actual fields depend on your version's output):

Field Meaning
result The final answer text
total_cost_usd Cost of this call (USD)
usage Token usage (input / output / cache, etc.)
session_id Session ID, usable with --resume to continue

Parsing with jq

The json format is a natural fit for jq:

# Just the final answer
claude -p "Summarize this change in one sentence" --output-format json | jq -r '.result'

# Pull out the cost of this call
claude -p "Review auth.py" --output-format json | jq '.total_cost_usd'

# Grab several fields at once
claude -p "Analyze the architecture" --output-format json \
  | jq '{cost: .total_cost_usd, session: .session_id, tokens: .usage}'

Branching and accumulating cost in a script

#!/usr/bin/env bash
set -euo pipefail

out=$(claude -p "Write unit tests for UserService" \
        --output-format json --max-turns 8)

result=$(echo "$out" | jq -r '.result')
cost=$(echo "$out"   | jq -r '.total_cost_usd')
sid=$(echo "$out"    | jq -r '.session_id')

echo "Result: $result"
echo "Cost this call: \$$cost"
echo "Session ID: $sid (resume with claude --resume $sid)"

Tip: json emits the whole object in one shot after the task ends — there is no output while a long task runs. To watch progress live, use stream-json below.


4. stream-json: a real-time event stream

--output-format stream-json breaks execution into newline-delimited JSON events (NDJSON), one event per line, written out immediately. It suits live progress for long tasks, streaming UIs, or pipelines that consume output as it's produced.

claude -p "Refactor the whole utils directory and add tests" \
  --output-format stream-json --max-turns 20

The output looks like (each line is independent JSON; fields depend on your version):

{"type":"system","subtype":"init","session_id":"..."}
{"type":"assistant","message":{...}}
{"type":"assistant","message":{...}}
{"type":"result","result":"...","total_cost_usd":0.0123,"usage":{...}}

Consuming line by line

Every line is valid JSON, so you can process it as it streams:

# Print the type of each event in real time
claude -p "Migrate to the new API" --output-format stream-json \
  | jq -r '.type'

# Pull result and cost only when the final event appears
claude -p "Migrate to the new API" --output-format stream-json \
  | jq -r 'select(.type == "result") | "\(.result)\nCost $\(.total_cost_usd)"'
# Process line by line with a while loop for live progress feedback
claude -p "Repository-wide code review" --output-format stream-json | \
while IFS= read -r line; do
  type=$(echo "$line" | jq -r '.type')
  case "$type" in
    system) echo "▶ Starting…" ;;
    assistant) echo "… thinking" ;;
    result) echo "✓ Done: $(echo "$line" | jq -r '.result')" ;;
  esac
done

json vs stream-json: json waits for the task to finish and gives you one complete object — simple to parse; stream-json streams multiple events throughout, enabling live feedback but requiring line-by-line parsing. In CI, use json for the final result and stream-json for progress logs.


5. CI / pipeline recipes

Grab the result and post a comment in GitHub Actions

- name: Claude review
  env:
    ANTHROPIC_BASE_URL: https://api.qcode.cc/api
    ANTHROPIC_AUTH_TOKEN: ${{ secrets.QCODE_API_KEY }}
  run: |
    out=$(claude -p "Review this PR's diff and list issues" \
            --output-format json --max-turns 6 --allowedTools Read,Glob,Grep)
    echo "$out" | jq -r '.result' > review.md
    echo "This review cost \$$(echo "$out" | jq -r '.total_cost_usd')"

Add a cost gate (fail if over budget)

out=$(claude -p "Generate release notes" --output-format json)
cost=$(echo "$out" | jq -r '.total_cost_usd')
# Float comparison with awk: fail CI if over $0.50
awk -v c="$cost" 'BEGIN{ exit (c > 0.5) ? 1 : 0 }' \
  || { echo "Cost \$$cost over budget"; exit 1; }
echo "$out" | jq -r '.result'

Accumulate cost across multiple calls

total=0
for f in src/*.py; do
  out=$(claude -p "Write docstrings for $f" --output-format json)
  c=$(echo "$out" | jq -r '.total_cost_usd')
  total=$(awk -v t="$total" -v c="$c" 'BEGIN{ printf "%.4f", t + c }')
done
echo "Total cost across all files: \$$total"

Pointing at QCode: the commands above are identical for the official API and QCode — just point ANTHROPIC_BASE_URL at https://api.qcode.cc/api (note: no trailing slash) and put your cr_ key in ANTHROPIC_AUTH_TOKEN. CN users can use asia.qcode.cc. See Endpoints & API formats.


6. Common pitfalls

  • json is silent during long tasks: it outputs once, at the end — seeing no progress is normal; use stream-json for progress.
  • You can't jq stream-json as one blob: it's NDJSON; multiple objects don't form a single JSON document. Use line-by-line jq, jq -c, or --stream — don't run jq '.' over the whole stream.
  • Don't forget --max-turns: cap turns in automation to keep a task from running away and burning money.
  • No trailing slash on BASE_URL: https://api.qcode.cc/api is correct; an extra / builds a wrong path.
  • Metadata fields vary by version: trust the real output of claude -p ... --output-format json on your machine — run jq 'keys' first to see what's there.

Next steps

Once Claude Code is wired into your pipeline, cost is right there in the output — see QCode plans & pricing and pick a tier that fits your automation volume.

Related Documents

Use QCode with 9router
Add QCode.cc as a custom provider in 9router, a local multi-provider router, for cross-provider fallback and unified management
gpt-image-2 Image Generation and Editing
OpenAI-compatible gpt-image-2 text-to-image + image-edit API: drop in by switching base_url, multi-region endpoints, unified billing with your QCode key
Image Input (Vision)
Feed images to Claude Code: paste, drag-and-drop, or reference a file path so the model can read screenshots, mockups, architecture diagrams, and charts. Powered by QCode.cc vision models — one API Key works across every endpoint.
🚀
Get Started with QCode — Claude Code & Codex
One plan for both Claude Code and Codex, Asia-Pacific low latency
View Pricing Plans → Create Account
Team of 3+?
Enterprise: dedicated domain + sub-key management + ban protection, from ¥250/person/mo
Learn Enterprise →