Non-interactive mode turns Claude Code into a building block for scripts, git hooks and CI jobs.
claude -p "prompt" (long form --print) runs one task without the interactive screen, prints the result and exits. Exit code 0 means success, so scripts can branch on it. It reads standard input, so you can pipe data in: cat build.log | claude -p "explain the root cause".
Output formats with --output-format:
text(default): just the answer.json: one object withresult,session_id, cost and usage; add--json-schema '<schema>'to get validated data instructured_output.stream-json: one JSON event per line as work happens (use with--verbose).
In a script or a CI job (continuous integration: automated checks that run on every push) nobody is there to approve prompts, so decide permissions up front:
--allowedTools "Read,Edit,Bash(npm test *)"pre-approves exactly what the task needs,--permission-mode dontAskdenies anything else that would have asked; good for locked-down CI,--permission-mode acceptEditsallows file edits as a baseline.
For reproducible runs, add --bare: it skips auto-discovery of hooks, skills, plugins, MCP servers, auto memory and CLAUDE.md from the machine and repo, so a teammate's personal hook can't change the result. Bare mode needs an API key (ANTHROPIC_API_KEY), and you pass anything required explicitly (--settings, --mcp-config, --append-system-prompt).
Conversations continue with --continue or --resume <session_id>. --max-turns caps how many steps a run may take.
Important: without --bare, a -p run in an untrusted repository loads that repo's hooks and MCP servers without the usual trust prompt. Only run headless Claude in repositories you trust.
Example
# explain a failure from a log file
cat build-error.txt | claude -p "concisely explain the root cause" > why.txt
# structured output for a script
claude -p "List the HTTP routes in src/api" --output-format json \
--json-schema '{"type":"object","properties":{"routes":{"type":"array","items":{"type":"string"}}},"required":["routes"]}' \
| jq '.structured_output.routes'
# locked-down CI run: only these tools, everything else denied
claude --bare -p "Run the unit tests and fix failures in src/" \
--allowedTools "Read,Edit,Bash(npm test *)" \
--permission-mode dontAsk --max-turns 20
# continue a specific session
sid=$(claude -p "Start a review of src/auth" --output-format json | jq -r .session_id)
claude -p "Now list only the high-severity issues" --resume "$sid"Remember
- claude -p runs one task, reads stdin and exits with a status code
- --output-format text|json|stream-json; --json-schema for validated data
- Pre-approve with --allowedTools, deny the rest with dontAsk; --bare for reproducible runs
Watch out for
- Running claude -p in CI without limiting tools or turns, so an unexpected path can run arbitrary commands for a long time.