By default, claude opens an interactive REPL. Add -p (or --print) and it becomes a one-shot command. Claude runs the prompt, completes all agentic turns, prints the result to stdout, and exits. This makes it composable in scripts and CI pipelines.
Piping is first-class. You can feed any text directly into Claude:
cat build-error.txt | claude -p 'explain the root cause'
git diff | claude -p "summarize what changed"
Output format is controlled with --output-format:
# text (default): plain stdout
claude -p "Summarize" --output-format text
# json: structured result, session_id, cost metadata
claude -p "Summarize" --output-format json
# stream-json: newline-delimited JSON in real-time
claude -p "Summarize" --output-format stream-json
Extract just the result text with jq:
claude -p "Summarize" --output-format json | jq -r '.result'
Auto-approve tools for CI/CD so Claude doesn't stop to ask:
claude -p "Run tests and fix failures" --allowedTools "Bash,Read,Edit"
Sessions persist across headless calls. Use --continue to resume the most recent session, or capture and resume by ID:
session_id=$(claude -p "Start review" --output-format json | jq -r '.session_id')
claude -p "Continue that review" --resume "$session_id"
You can also add Claude to a package.json script:
"lint:claude": "claude -p 'look at the changes vs. main and report typos. filename and line number on one line, description on the second. no other text.'"
flags let you cap what Claude can do in a run:
--max-turns Nstops after agentic turns--max-budget-usd 0.50stops after spending that budget--tools ""disables all tools
Permission rules use a specific syntax: Bash(git diff *) with a space before * allows any command starting with git diff . Without the space, Bash(git diff*) also matches git diff-index, which you likely don't want.