Claude Code Headless Mode: The Definitive Guide to claude -p
How to run Claude Code non-interactively with claude -p — output formats, jq parsing, stdin piping, permission flags, and when to reach for the Claude Agent SDK instead.
Pare de configurar. Comece a construir.
Templates SaaS com orquestração de IA.
Claude Code headless mode runs the same agent non-interactively: add the -p (or --print) flag to any claude command, pass a prompt, and Claude Code runs its full agent loop, prints a result, and exits — no terminal UI. It supports --output-format text|json|stream-json, reads stdin so you can pipe data in and redirect out, and pre-approves tools with --allowedTools and --permission-mode so unattended runs never block on a prompt. For production automation in your own process, the Claude Agent SDK (Python/TypeScript) wraps the same engine as a library.
This post covers the flags that matter, real shell snippets with jq parsing, the CLI-vs-SDK decision, and the billing situation after June 15, 2026.
Table of Contents
- What Is Claude Code Headless Mode?
- Output Formats: text, json, stream-json
- Piping, Parsing, and Streaming with jq
- Running Unattended: Permissions and Limits
- Sessions, System Prompts, and Bare Mode
- Interactive vs claude -p vs the Claude Agent SDK
- Billing After June 15, 2026
- Frequently Asked Questions
Pare de configurar. Comece a construir.
Templates SaaS com orquestração de IA.
What Is Claude Code Headless Mode?
Interactive Claude Code is a terminal UI with a human in the loop. Headless mode is the same tool with the UI removed. You add -p (or the long form --print) to a claude command, hand it a prompt, and it runs the same agent loop — reading files, running shell commands, calling tools — then prints the result and exits (code.claude.com/docs/en/headless).
That single behavior change is what makes Claude Code scriptable. The minimal invocation:
claude -p "What does the auth module do?"Give it tools and a real task:
claude -p "Find and fix the bug in auth.py" --allowedTools "Read,Edit,Bash"Headless mode is built for three places: shell scripts, cron jobs, and CI. Anywhere a human cannot sit and click "approve." It runs the same models as interactive Claude Code — the mid-2026 lineup is Claude Opus 4.8 ($5 input / $25 output per million tokens), Claude Sonnet 4.6 ($3 / $15), Haiku 4.5, and Fable 5.
For scheduled runs that fire on a clock, this pairs naturally with Claude Code Routines and scheduled tasks. For CI, it underpins the Claude Code GitHub Actions integration.
Output Formats: text, json, stream-json
--output-format accepts exactly three values (cli-reference). Pick by how you plan to consume the result.
| Value | Behavior | Use when |
|---|---|---|
text | Default. Plain text result. | You want the answer printed for a human or piped to another text tool. |
json | Structured JSON: result, session_id, metadata, total_cost_usd, per-model cost breakdown (and structured_output when --json-schema is set). | A script needs to parse the result or track spend per call. |
stream-json | Newline-delimited JSON, one event per line, emitted in real time. | You want to display progress live or process events as they arrive. |
The json format is the workhorse for automation. Every invocation reports its own cost:
claude -p "Summarize the changes in the last commit" \
--output-format json | jq '{ result, cost: .total_cost_usd }'stream-json has a requirement that trips people up: it needs --verbose. Passing --output-format stream-json alone is not enough. For token-level deltas, add --include-partial-messages on top (headless):
claude -p "Refactor the user service" \
--output-format stream-json --verbose --include-partial-messagesThere is also an --input-format, accepting text (default) or stream-json (cli-reference). The stream-json input format enables programmatic bidirectional streaming — feeding the agent a stream of messages rather than one prompt.
Piping, Parsing, and Streaming with jq
Non-interactive mode reads stdin, so claude -p behaves like any Unix filter. Pipe in, redirect out:
cat build-error.txt | claude -p 'concisely explain the root cause of this build error' > output.txtOne caveat with size: piped stdin is capped at 10MB as of Claude Code v2.1.128. Exceed it and the command exits with a clear error and a non-zero status. For larger inputs, write to a file and reference the path in the prompt instead of piping the bytes (headless).
The json format plus jq is how you wire Claude Code into a pipeline. Capture just the result text:
result=$(claude -p "Generate a one-line release note from the staged diff" \
--output-format json | jq -r '.result')
echo "$result"For live output, filter the stream-json event stream down to text deltas as they stream:
claude -p "Write the migration" \
--output-format stream-json --verbose --include-partial-messages \
| jq -rj 'select(.type == "stream_event" and .event.delta.type? == "text_delta") | .event.delta.text'A CI-friendly one-liner you can drop straight into package.json as a typo linter (headless):
{
"scripts": {
"lint:claude": "git diff main | claude -p \"you are a typo linter, report any typos in this diff\""
}
}And a PR security review that pipes the diff in and emits JSON for the CI step to parse:
gh pr diff "$1" \
| claude -p --append-system-prompt "You are a security engineer. Review for vulnerabilities." \
--output-format jsonRunning Unattended: Permissions and Limits
The whole point of headless mode is that nothing waits for a human. That means you have to tell Claude Code up front which tools may run without asking.
--allowedTools (alias --allowed-tools) lists tools that execute without a permission prompt:
claude -p "Run the test suite and fix any failures" --allowedTools "Bash,Read,Edit"Two gotchas live here. First, the flag is --allowedTools (camelCase), not --allow-tools or --tools. --tools is a different flag that restricts which built-in tools exist at all; --allowedTools pre-approves tools so they skip the prompt. Second, scoped rules use prefix matching and the space before the wildcard matters: Bash(git diff *) matches git diff ..., but Bash(git diff*) would also wrongly match git diff-index (headless).
--disallowedTools (alias --disallowed-tools) are deny rules. A bare tool name removes the tool from context entirely ("Edit", "*", "mcp__*"); a scoped rule like Bash(rm *) leaves the tool available but blocks matching calls (cli-reference).
--permission-mode sets a session-wide policy. It accepts six values (cli-reference):
| Mode | What it does |
|---|---|
default | Standard prompting behavior. |
acceptEdits | Auto-approves file writes plus common filesystem commands (mkdir, touch, mv, cp). |
plan | Plan-only; no execution. |
auto | Automatic approvals within configured rules. |
dontAsk | Denies anything not in permissions.allow or the read-only command set. Good for locked-down CI. |
bypassPermissions | Skips all permission checks. Use with extreme care. |
For CI, dontAsk is usually the right default: it runs read-only commands and your explicit allow-list, and refuses everything else rather than blocking.
Spend and turn limits. Two flags keep an unattended run from running away (both print-mode only):
--max-turnscaps agentic turns and exits with an error when the limit is reached. There is no limit by default.--max-budget-usdcaps dollar spend before stopping.
claude -p "Triage open issues and propose fixes" \
--allowedTools "Read,Bash" \
--max-turns 12 \
--max-budget-usd 0.50Exit codes. There is no published single global exit-code table. The documented pattern is non-zero on error: --max-turns exits with an error at the limit, a 10MB stdin overflow exits non-zero, and claude auth status exits 0 if logged in and 1 if not (cli-reference). Check for a non-zero status in your scripts; do not assert specific codes beyond what individual commands document.
Sessions, System Prompts, and Bare Mode
Resuming a conversation. Headless runs are stateless by default, but you can thread them. Capture the session ID from a JSON run, then resume it (headless):
session_id=$(claude -p "Start a code review of the payments module" \
--output-format json | jq -r '.session_id')
claude -p "Now check the same module for missing tests" --resume "$session_id"--continue / -c loads the most recent conversation in the current directory; --resume / -r resumes a specific session by ID or name; --session-id sets a specific UUID. One trap: session lookup is scoped to the current project directory and its git worktrees. Run the capture and the resume from the same directory or --resume by ID will not find the session.
System prompts. Four flags work in both interactive and headless modes (cli-reference):
--system-prompt— replace the entire prompt--system-prompt-file— replace from a file--append-system-prompt— append text--append-system-prompt-file— append from a file
The two replace flags are mutually exclusive; append can combine with either.
Bare mode. For deterministic CI, add --bare. It skips auto-discovery of hooks, skills, plugins, MCP servers, auto memory, and CLAUDE.md, which makes runs faster and reproducible. In bare mode Claude has Bash, file read, and file edit tools, and auth must come from ANTHROPIC_API_KEY or an apiKeyHelper — it does not use OAuth or the keychain (headless).
The surprise is intentional: a teammate's ~/.claude hooks or a project .mcp.json will not run under --bare. That is the point for CI, but unexpected if you assumed your local config would carry over. Anthropic recommends --bare for scripted and SDK-style calls, and it is slated to become the default for -p in a future release.
Structured output. Combine --output-format json with --json-schema (a JSON Schema definition) and Claude Code returns output conforming to your schema in a structured_output field alongside request metadata. Print-mode only (headless).
Slash commands. User-invoked skills and custom commands work in -p mode — include /skill-name in the prompt string and it expands. Built-in interactive commands like /config and /login do not work headless (headless).
Auth for CI. claude setup-token generates a long-lived OAuth token for CI and scripts (requires a Claude subscription) (cli-reference).
Interactive vs claude -p vs the Claude Agent SDK
All three run the same engine — Claude Code's tools, agent loop, and context management. The difference is the interface and where the control lives.
| Dimension | Interactive Claude Code | Headless claude -p (CLI) | Claude Agent SDK (TS/Python) |
|---|---|---|---|
| Interface | Terminal TUI, human in the loop | Single shell command, no UI | query() in @anthropic-ai/claude-agent-sdk / claude-agent-sdk |
| Best for | Daily development, one-off tasks | Shell scripts, cron, simple CI | CI/CD pipelines, custom apps, production automation |
| Input | Typed prompts | Prompt arg + optional stdin pipe | prompt param (string or async stream) |
| Output | Rendered in terminal | --output-format text|json|stream-json | Native message objects / async iterator |
| Permissions | Interactive prompts | --allowedTools, --permission-mode, no prompts | allowed_tools/allowedTools, permission_mode, callbacks |
| Tool approval | Asks each time | Pre-approved via flags or aborts | Programmatic callbacks + hooks |
| Same engine? | Yes | Yes | Yes |
Anthropic's own guidance: the SDK for CI/CD pipelines, custom applications, and production automation; the CLI for interactive development and one-off tasks. Because they share capabilities, logic translates directly between them (agent-sdk/overview).
The SDK was renamed from the Claude Code SDK to the Claude Agent SDK. If you wrote against the old packages, this is a breaking change (migration-guide):
| Aspect | Old | New |
|---|---|---|
| npm package | @anthropic-ai/claude-code (^0.0.42) | @anthropic-ai/claude-agent-sdk (^0.2.0) |
| Python package | claude-code-sdk | claude-agent-sdk |
| Python import | from claude_code_sdk import query, ClaudeCodeOptions | from claude_agent_sdk import query, ClaudeAgentOptions |
| Python options type | ClaudeCodeOptions | ClaudeAgentOptions |
| Default system prompt | Claude Code's preset | Minimal (opt in to the preset) |
That last row is a silent trap. After upgrading, the SDK no longer uses Claude Code's system prompt by default — it ships a minimal prompt. Agents that depended on Claude Code's coding instructions must opt back in (migration-guide):
from claude_agent_sdk import query, ClaudeAgentOptions
async for message in query(
prompt="Find and fix the bug in auth.py",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Bash"],
system_prompt={"type": "preset", "preset": "claude_code"},
),
):
print(message)The Python SDK requires Python 3.10 or later. The TypeScript SDK bundles a native Claude Code binary as an optional dependency, so you do not have to install Claude Code separately. Auth is via ANTHROPIC_API_KEY or the Bedrock/Vertex/Foundry/AWS env vars (agent-sdk/overview).
If you are deciding between billing your automation against a subscription versus an API key, that tradeoff is covered in Claude Code Max plan vs API.
Billing After June 15, 2026
Here is the part the rumor mill got wrong. The widely reported "separate Agent SDK credit pool at full API rates starting June 15, 2026" did not go live. As of June 15, 2026, Anthropic paused that change. Claude Agent SDK usage, claude -p, and third-party app usage still draw from your subscription's usage limits — nothing changed about how programmatic usage is billed (Claude Help Center, article 15036540).
So June 15 is the date a change was paused, not the date it took effect. Do not architect around a credit pool that is not currently in force.
Two things are still worth knowing for production planning:
- Under the now-paused plan, when the monthly Agent SDK credit ran out, additional usage would have flowed to usage credits at standard API rates only if usage credits were enabled; otherwise Agent SDK requests would stop until the credit refreshed. Claude Platform accounts using an API key never received a credit (Help Center).
- For shared production automation, Anthropic recommends Claude Platform with an API key for predictable pay-as-you-go billing.
The practical takeaway: if you run a personal cron job or a side-project GitHub Action, your subscription still covers it today. If you run shared, always-on automation where predictable billing matters, an API key on Claude Platform is the cleaner foundation regardless of how subscription billing shifts. For the full timeline and what to watch, see Claude Code costs after June 15. Re-check the Help Center article before you rely on any specific number — Anthropic can change this without warning.
Frequently Asked Questions
What is Claude Code headless mode?
Headless (print) mode runs Claude Code non-interactively. You add the -p or --print flag to any claude command, pass a prompt, and it runs the same agent loop as interactive Claude Code, prints a result, and exits — no terminal UI. Example: claude -p "What does the auth module do?". It is built for shell scripts, cron jobs, and CI.
What output formats does claude -p support?
Three, via --output-format: text (default plain text), json (structured JSON with the result, session_id, metadata, and total_cost_usd), and stream-json (newline-delimited JSON, one event per line, for real-time streaming). stream-json requires --verbose, and token-level deltas additionally require --include-partial-messages.
How do I run Claude Code in a script without permission prompts?
Pre-approve tools with --allowedTools "Bash,Read,Edit" (or scoped rules like Bash(git diff *)), or set a session-wide --permission-mode such as acceptEdits or the locked-down dontAsk. For deterministic CI runs add --bare so the run ignores local hooks, MCP servers, and CLAUDE.md.
Can I pipe data into Claude Code?
Yes. claude -p reads stdin, so you can pipe and redirect like any CLI tool: cat build-error.txt | claude -p 'explain the root cause' > output.txt. Piped stdin is capped at 10MB (v2.1.128+); for larger inputs, write to a file and reference its path in the prompt.
What is the difference between ClaudeCodeOptions and ClaudeAgentOptions?
They are the same thing, renamed. ClaudeCodeOptions (old Python claude-code-sdk) became ClaudeAgentOptions (new claude-agent-sdk). One behavior change shipped with the rename: the SDK no longer uses Claude Code's system prompt by default — opt back in with system_prompt={"type":"preset","preset":"claude_code"}.
How is claude -p billed on a Claude subscription after June 15, 2026?
As of June 15, 2026, programmatic usage (Claude Agent SDK, claude -p, and third-party apps) still draws from your subscription's usage limits. Anthropic paused the previously announced separate Agent SDK credit pool on that date. For predictable pay-as-you-go production automation, Anthropic recommends Claude Platform with an API key, which bills at standard API rates.
Wrapping Up
Headless mode is the difference between Claude Code as a tool you sit at and Claude Code as a building block in your scripts. The mechanics are small: -p to go non-interactive, --output-format json plus jq to parse, stdin to pipe data in, --allowedTools and --permission-mode dontAsk to run unattended without blocking, and --bare for reproducible CI. The Agent SDK is the same engine when you want it inside your own Python or TypeScript process, with the rename and the minimal-default-prompt trap as the two things to watch.
Start with a one-liner: a git-diff typo linter in package.json, or a build-error explainer piped from a log file. Get the parsing right with jq, add a --max-budget-usd guardrail, then graduate to the SDK when you need callbacks and structured message objects. And ignore the credit-pool rumor — that change was paused on June 15, 2026, so your subscription still covers programmatic usage today.
Posted by @speedy_devv
Pare de configurar. Comece a construir.
Templates SaaS com orquestração de IA.
Claude Code GitHub Actions Setup Guide (@claude + Cron)
Wire Claude Code into GitHub Actions with real .github/workflows YAML: PR review on @claude mention, a scheduled review, secrets table, and the security gotchas.
Run a Team of AI Agents in Parallel with Git Worktrees
A hands-on workflow for running multiple Claude Code agents at once using git worktrees: real commands, a directory layout, the merge strategy, and the practical 5-7 agent ceiling.