Claude Headless Mode
Use claude -p (or --print ) for non-interactive execution in scripts, CI, and automation.
Basic Usage
Simple prompt
claude -p "Summarize this repo"
With file input
claude -p "Review this code" < file.py
Pipe output
claude -p "List all functions" | grep "def "
Output Formats
Format Flag Use Case
Text --output-format text
Human-readable (default)
JSON --output-format json
Single JSON result
Stream JSON --output-format stream-json --verbose
Real-time streaming
Text Output (Default)
claude -p "What is 2+2?"
Output: 4
JSON Output
claude -p "What is 2+2?" --output-format json
Returns wrapper with metadata:
{ "type": "result", "subtype": "success", "result": "4", "duration_ms": 1234, "total_cost_usd": 0.01, "session_id": "...", "structured_output": null }
Extract just the result:
claude -p "What is 2+2?" --output-format json | jq -r '.result'
Stream JSON Output
claude -p "Long analysis" --output-format stream-json --verbose
-
Streams newline-delimited JSON as execution progresses
-
Shows tool calls, messages, progress in real-time
-
Final line contains the result
-
Requires --verbose flag
Extract final result:
claude -p "Analyze code" --output-format stream-json --verbose
| tee /dev/stderr
| tail -1
| jq -r '.result'
Structured Output with JSON Schema
Force Claude to return data matching a specific schema:
claude -p "Extract function names from auth.py"
--output-format json
--json-schema '{
"type": "object",
"properties": {
"functions": { "type": "array", "items": { "type": "string" } }
},
"required": ["functions"]
}'
Result appears in structured_output field:
{ "result": "...", "structured_output": { "functions": ["login", "logout", "verify_token"] } }
Schema Examples
Simple object:
{ "type": "object", "properties": { "answer": { "type": "integer" } }, "required": ["answer"] }
Task result (success/failure):
{ "type": "object", "properties": { "status": { "type": "string", "enum": ["success", "failure"] }, "summary": { "type": "string" }, "files_changed": { "type": "array", "items": { "type": "string" } }, "error_category": { "type": "string" }, "suggestion": { "type": "string" } }, "required": ["status", "summary"] }
Extract from schema result:
OUTPUT=$(claude -p "$PROMPT" --output-format json --json-schema "$SCHEMA") STATUS=$(echo "$OUTPUT" | jq -r '.structured_output.status') SUMMARY=$(echo "$OUTPUT" | jq -r '.structured_output.summary')
Common Options
Option Description
-p, --print
Headless mode (required)
--output-format
text, json, stream-json
--json-schema
Enforce output schema
--verbose
Required for stream-json
--model
Select model (sonnet, opus, haiku)
--max-turns
Limit agentic turns
--permission-mode
bypassPermissions, plan, etc.
--allowedTools
Restrict available tools
Permission Modes
Skip all permission prompts (trusted environments only)
claude -p "Fix all linting errors" --permission-mode bypassPermissions
Plan mode (read-only exploration)
claude -p "Analyze architecture" --permission-mode plan
Examples
CI/CD Integration
Run tests and get structured result
RESULT=$(claude -p "Run tests and report results"
--output-format json
--json-schema '{"type":"object","properties":{"passed":{"type":"boolean"},"failures":{"type":"array","items":{"type":"string"}}},"required":["passed"]}')
if [ "$(echo $RESULT | jq '.structured_output.passed')" = "true" ]; then echo "Tests passed" else echo "Tests failed" exit 1 fi
Batch Processing
for file in src/*.py; do
claude -p "Review $file for security issues"
--output-format json
--json-schema '{"type":"object","properties":{"issues":{"type":"array"}},"required":["issues"]}'
| jq ".structured_output.issues"
done
Fresh Context Task Execution
Each invocation is independent (no conversation history)
claude -p "Task 1: Create migration" --output-format json claude -p "Task 2: Add model" --output-format json claude -p "Task 3: Write tests" --output-format json
Task Coordination
Share TaskList across headless invocations using CLAUDE_CODE_TASK_LIST_ID .
Environment Variable
All invocations share the same TaskList
export CLAUDE_CODE_TASK_LIST_ID="my-project" claude -p "Use TaskCreate to add: Setup database" claude -p "Use TaskCreate to add: Write migrations" claude -p "Use TaskList to show all tasks" # Shows both tasks
Pattern: Orchestrator + Workers
TASK_LIST_ID="epic-$(date +%Y%m%d)" export CLAUDE_CODE_TASK_LIST_ID="$TASK_LIST_ID"
Orchestrator creates tasks
claude -p "Use TaskCreate for each: Task 1, Task 2, Task 3"
Workers execute (each sees shared TaskList)
for task_id in 1 2 3; do claude -p "Use TaskUpdate to mark task #$task_id as in_progress, implement it, then mark completed" done
Check final state
claude -p "Use TaskList to show status"
Task Tools
Tool Purpose
TaskCreate
Create new task with subject, description
TaskList
List all tasks with status
TaskUpdate
Update task status (in_progress, completed) or add blockedBy
TaskGet
Get full details of a specific task
Dependencies
Task 2 depends on Task 1
claude -p "Use TaskUpdate on task #2 to set blockedBy: [1]"
Tasks persist to ~/.claude/tasks/ and survive session restarts.
Notes
-
Each -p invocation starts fresh (no context from previous runs)
-
Use --output-format json for programmatic parsing
-
structured_output field contains schema-validated data
-
result field contains raw text response
-
Stream JSON requires --verbose flag
-
Cost info available in JSON output: total_cost_usd