claude -p)Verified against https://code.claude.com/docs/en/headless and https://code.claude.com/docs/en/cli-reference (June 2026).
claude -p runs the same agent loop as interactive Claude Code via the Agent SDK. For full programmatic control (callbacks, message objects, structured outputs API), use the Python/TypeScript Agent SDK — this page covers the CLI surface.
Billing note: from June 15, 2026,
claude -p/ Agent SDK usage on subscription plans draws from a separate monthly Agent SDK credit, not interactive limits.
| Flag | Purpose |
|---|---|
-p, --print |
Non-interactive mode; print result and exit |
--output-format |
text (default) | json | stream-json |
--input-format |
text (default) | stream-json (print mode) |
--json-schema '<schema>' |
Validated structured output (with --output-format json); result lands in structured_output |
--include-partial-messages |
Token-level streaming events (needs -p + stream-json) |
--include-hook-events |
Hook lifecycle events in the stream (needs stream-json) |
--replay-user-messages |
Echo stdin user messages back on stdout (stream-json in/out) |
-c, --continue |
Continue most recent conversation in this directory |
-r, --resume <id\|name> |
Resume a specific session |
--fork-session |
New session ID when resuming (don't mutate the original) |
--session-id <uuid> |
Pin the session ID |
--no-session-persistence |
Don't save the session to disk (print mode) |
--allowedTools / --allowed-tools |
Auto-approve matching tools (permission-rule syntax) |
--disallowedTools |
Deny rules; bare name removes the tool from context, Bash(rm *) denies matching calls only |
--tools "Bash,Edit,Read" |
Restrict available built-in tools ("" = none, "default" = all). MCP unaffected — pair with --disallowedTools "mcp__*" |
--permission-mode |
default | acceptEdits | plan | auto | dontAsk | bypassPermissions |
--dangerously-skip-permissions |
= --permission-mode bypassPermissions |
--permission-prompt-tool <mcp_tool> |
Delegate permission prompts to an MCP tool |
--max-turns N |
Cap agentic turns (print mode); exits with error at the cap |
--max-budget-usd N |
Spend cap (print mode) |
--model / --fallback-model sonnet,haiku |
Model + ordered fallback chain |
--effort low\|medium\|high\|xhigh\|max |
Effort level |
--system-prompt(-file) / --append-system-prompt(-file) |
Replace / append system prompt (replace drops ALL default guidance) |
--agents '<json>' |
Define session subagents inline (subagent frontmatter fields + prompt) |
--agent <name> |
Run a specific agent as the main session |
--settings <file\|json> |
Override settings for this invocation |
--setting-sources user,project,local |
Limit which settings files load |
--mcp-config <file\|json> / --strict-mcp-config |
Load MCP servers / ONLY those servers |
--add-dir <paths> |
Extra working directories |
--bare |
Minimal mode: skip hooks/skills/plugins/MCP/CLAUDE.md auto-discovery |
--bg |
Run as a background agent, return immediately (prints session ID); --bg --exec 'cmd' runs a shell job |
--verbose |
Turn-by-turn output (required for some stream-json modes) |
--init / --init-only / --maintenance |
Run Setup hooks (print mode); --init-only exits after hooks |
--exclude-dynamic-system-prompt-sections |
Move per-machine prompt sections to first user message (prompt-cache reuse across machines) |
Stdin is capped at 10MB (v2.1.128+); larger inputs go in a file referenced by path.
claude --bare -p "Summarize this file" --allowedTools "Read"
Skips auto-discovery of hooks, skills, plugins, MCP servers, auto memory, and CLAUDE.md — same result on every machine; only explicit flags apply. Tools available: Bash, file read, file edit. Pass context back in explicitly: --append-system-prompt(-file), --settings, --mcp-config, --agents, --plugin-dir/--plugin-url.
Caveat: bare mode skips OAuth/keychain reads — auth must come from ANTHROPIC_API_KEY or an apiKeyHelper in --settings. Docs state --bare will become the default for -p in a future release.
--safe-mode is the interactive cousin (troubleshooting, not speed): customizations off, auth/permissions normal. See debugging-reference.md.
json{
"type": "result",
"subtype": "success",
"result": "…final text…",
"structured_output": { },
"session_id": "abc-123",
"is_error": false,
"num_turns": 3,
"duration_ms": 12345,
"total_cost_usd": 0.0123,
"usage": { }
}
claude -p "Summarize this project" --output-format json | jq -r '.result'
session_id=$(claude -p "Start a review" --output-format json | jq -r '.session_id')
total_cost_usd includes a per-model cost breakdown — track spend per invocation.
--json-schema)claude -p "Extract the main function names from auth.py" \
--output-format json \
--json-schema '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}' \
| jq '.structured_output'
The agent completes its full workflow, then the response is validated against the schema; metadata (session ID, usage) wraps the structured_output field.
stream-jsonNewline-delimited JSON events. Token streaming needs --verbose --include-partial-messages:
claude -p "Write a poem" --output-format stream-json --verbose --include-partial-messages | \
jq -rj 'select(.type == "stream_event" and .event.delta.type? == "text_delta") | .event.delta.text'
Notable event types:
system / subtype init — first event; reports model, tools, MCP servers, plugins (loaded: name,path) and plugin_errors (plugin,type,message) — fail CI on plugin_errors.system / subtype api_retry — retryable API failure: attempt, max_retries, retry_delay_ms, error_status, error (rate_limit, overloaded, server_error, …).system / subtype plugin_install — with CLAUDE_CODE_SYNC_PLUGIN_INSTALL set: status started|installed|failed|completed.assistant / user message events; stream_event partial deltas; final result event mirroring the json payload.stream-json input--input-format stream-json accepts a stream of user messages on stdin for multi-turn programmatic driving; pair with --output-format stream-json --verbose (and --replay-user-messages for acks).
Pipe data:
cat build-error.txt | claude -p 'explain the root cause of this build error' > explanation.txt
git diff main | claude -p "you are a typo linter. report filename:line + issue per typo. nothing else."
Multi-turn:
claude -p "Review this codebase for performance issues"
claude -p "Now focus on the database queries" --continue
session=$(claude -p "Start a review" --output-format json | jq -r '.session_id')
claude -p "Continue that review" --resume "$session"
Scoped git permissions (note the space before * — Bash(git diff *) ≠ Bash(git diff*), the latter also matches git diff-index):
claude -p "Look at my staged changes and create an appropriate commit" \
--allowedTools "Bash(git diff *),Bash(git log *),Bash(git status *),Bash(git commit *)"
Locked-down CI:
claude --bare -p "Apply the lint fixes" --permission-mode acceptEdits
# dontAsk: deny anything not explicitly allowed — strictest non-interactive baseline
claude --bare -p "Audit only, change nothing" --permission-mode dontAsk --allowedTools "Read,Grep,Glob"
GitHub Actions review job (modernized):
- name: Claude review
run: |
gh pr diff "$PR" | claude --bare -p \
--append-system-prompt "You are a security engineer. Review for vulnerabilities." \
--output-format json --allowedTools "Read,Grep" > review.json
jq -e '.is_error == false' review.json
jq -r '.result' review.json > review.md
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR: ${{ github.event.pull_request.number }}
Error handling:
result=$(claude -p "Task" --output-format json) || { echo "claude exited non-zero" >&2; exit 1; }
if [[ $(jq -r '.is_error' <<<"$result") == "true" ]]; then
echo "Error: $(jq -r '.result' <<<"$result")" >&2; exit 1
fi
Background agents:
claude --bg "investigate the flaky test" # prints session ID
claude agents --json # list background sessions
claude logs <id>; claude attach <id>; claude stop <id>; claude respawn <id>
Skills in prompts: claude -p "/my-skill arg1" expands before running. Interactive built-ins (/config, /login) are unavailable in -p.
Background Bash tasks started during a -p run (dev servers, watchers) are terminated ~5s after the final result (v2.1.163+).
ANTHROPIC_API_KEY env var.claude setup-token generates a long-lived OAuth token for CI/scripts.For retries, hooks-as-callbacks, custom tools, native message objects, and structured outputs beyond --json-schema, use the Agent SDK packages: @anthropic-ai/claude-agent-sdk (TypeScript) / claude-agent-sdk (Python). Docs: https://code.claude.com/docs/en/agent-sdk/overview. The CLI flags above map 1:1 onto SDK options.