Overview
Claude Code runs non-interactively when you pass -p (or --print) with a
prompt. This headless mode is how you use Claude Code in scripts, build steps,
and CI pipelines: pipe data in, get structured output back, and pre-approve the
tools the job needs. It uses the same agent loop and tools as an interactive
session.
Basic usage
claude -p "What does the auth module do?"
All CLI options work with -p, including --continue, --allowedTools, and
--output-format.
Bare mode for reproducible runs
--bare skips auto-discovery of hooks, skills, plugins, MCP servers, auto
memory, and CLAUDE.md, so a job behaves the same on every machine. Pass only the
context you need:
claude --bare -p "Summarize this file" --allowedTools "Read"
In bare mode, authentication must come from ANTHROPIC_API_KEY or an
apiKeyHelper in --settings; it skips OAuth and keychain reads. Load extra
context with flags like --append-system-prompt, --settings, --mcp-config,
--agents, or --plugin-dir. Bare mode is the recommended mode for scripted
calls.
Pipe data through Claude
cat build-error.txt | claude -p 'concisely explain the root cause of this build error' > output.txt
Piped stdin is capped at 10MB; for larger inputs, write to a file and reference
its path in the prompt.
Structured output
# JSON with result, session id, and metadata (including total_cost_usd)
claude -p "Summarize this project" --output-format json | jq -r '.result'
# Conform to a 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'
Use --output-format stream-json --verbose --include-partial-messages for
newline-delimited streaming events.
Auto-approve tools safely
claude --bare -p "Run the test suite and summarize any failures" \
--permission-mode dontAsk \
--allowedTools "Bash(npm test),Bash(git diff *)"
For a locked-down CI baseline, use --bare so repository-local instructions,
hooks, skills, plugins, MCP servers, and CLAUDE.md cannot change the run. Pass a
permission mode: --permission-mode dontAsk denies anything not in your allow
rules or the read-only command set. --allowedTools uses permission-rule syntax,
so Bash(git diff *) allows a prefix (note the space before *). Avoid broad
rules such as Bash,Read,Edit in CI because they allow arbitrary shell commands
and broad repository reads or edits.
Continue conversations
session_id=$(claude -p "Start a review" --output-format json | jq -r '.session_id')
claude -p "Continue that review" --resume "$session_id"
Note: user-invoked skills like /code-review are interactive-only; in -p mode,
describe the task directly.
Source