# 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](/docs/advanced/headless).

---

## 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 |

```bash
# 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.

```bash
# 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.

```bash
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`](https://jqlang.org/):

```bash
# 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

```bash
#!/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.

```bash
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:

```bash
# 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)"'
```

```bash
# 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

```yaml
- 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)

```bash
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

```bash
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](/docs/getting-started/endpoints-and-api-paths).

---

## 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

- [Automation & CI/CD](/docs/advanced/headless) — full headless flag reference and CI/CD recipes
- [Subagents](/docs/advanced/subagents) — have Claude Code orchestrate background agents in parallel
- [Cost optimization](/docs/usage/cost-optimization) — manage cost with `total_cost_usd`
- [Endpoints & API formats](/docs/getting-started/endpoints-and-api-paths) — the four domains and protocol paths

> Once Claude Code is wired into your pipeline, cost is right there in the output — [see QCode plans & pricing](https://qcode.cc/pricing) and pick a tier that fits your automation volume.