obsidian/wiki/claude-code/headless-cli.md
2026-04-17 13:08:46 +01:00

5 KiB

title aliases tags sources created updated
Run Claude Code Programmatically (CLI / Headless)
headless-mode
claude-p-flag
programmatic-claude
claude-code
cli
headless
automation
ci-cd
agent-sdk
raw/Run Claude Code programmatically.md
2026-04-17 2026-04-17

Run Claude Code Programmatically (CLI / Headless)

The -p (or --print) flag runs Claude Code non-interactively. It was previously called "headless mode." All CLI options work with -p.

For structured outputs, tool-approval callbacks, and native message objects use the full wiki/agent-sdk/_index packages instead.


Basic Usage

claude -p "What does the auth module do?"
claude -p "Find and fix the bug in auth.py" --allowedTools "Read,Edit,Bash"

Bare Mode (--bare)

Skips auto-discovery of hooks, skills, plugins, MCP servers, auto memory, and CLAUDE.md — so every machine gives the same result.

claude --bare -p "Summarize this file" --allowedTools "Read"
  • Use for CI/scripts — teammate's ~/.claude hooks or project .mcp.json won't interfere
  • Auth must come from ANTHROPIC_API_KEY or apiKeyHelper in --settings JSON (no OAuth/keychain)
  • In bare mode, Claude has Bash, file read, and file edit tools by default
  • --bare will become the default for -p in a future release
Need Flag
System prompt additions --append-system-prompt / --append-system-prompt-file
Settings --settings <file-or-json>
MCP servers --mcp-config <file-or-json>
Custom agents --agents <json>
Plugin directory --plugin-dir <path>

Structured Output

# JSON with session metadata; result in `.result` field
claude -p "Summarize this project" --output-format json

# Schema-constrained output; result in `.structured_output` field
claude -p "Extract function names from auth.py" \
  --output-format json \
  --json-schema '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}'

# Parse with jq
claude -p "Summarize" --output-format json | jq -r '.result'

Output format options:

  • text (default) — plain text
  • json — structured JSON with result, session ID, metadata
  • stream-json — newline-delimited JSON for real-time streaming

Streaming Responses

claude -p "Explain recursion" \
  --output-format stream-json --verbose --include-partial-messages \
  | jq -rj 'select(.type == "stream_event" and .event.delta.type? == "text_delta") | .event.delta.text'

Key stream events:

  • system/init — session metadata: model, tools, plugins loaded. Use plugin_errors field to fail CI on bad plugin load
  • system/api_retry — emitted before each retry; fields: attempt, max_retries, retry_delay_ms, error_status, error
  • system/plugin_install — emitted when CLAUDE_CODE_SYNC_PLUGIN_INSTALL is set; statuses: started, installed, failed, completed

Auto-Approve Tools

# Approve specific tools
claude -p "Run tests and fix failures" --allowedTools "Bash,Read,Edit"

# Permission mode — broader baseline
claude -p "Apply lint fixes" --permission-mode acceptEdits
  • acceptEdits — auto-approves file writes plus mkdir, touch, mv, cp
  • dontAsk — denies anything not in permissions.allow or the read-only command set (useful for locked-down CI)
  • --allowedTools uses permission rule syntax: Bash(git diff *) — note the space before * for prefix matching

Continue Conversations

# Continue most recent conversation
claude -p "Review codebase for perf issues"
claude -p "Now focus on database queries" --continue

# Resume a specific session
session_id=$(claude -p "Start a review" --output-format json | jq -r '.session_id')
claude -p "Continue that review" --resume "$session_id"

Customize System Prompt

gh pr diff "$1" | claude -p \
  --append-system-prompt "You are a security engineer. Review for vulnerabilities." \
  --output-format json
  • --append-system-prompt — adds to default behavior
  • --system-prompt — fully replaces default prompt

Limitations


Key Takeaways

  • Use -p for any non-interactive/scripted Claude Code call
  • Always add --bare in CI — prevents local config bleed and speeds up startup
  • --output-format json + jq is the idiomatic way to extract structured results
  • --allowedTools and --permission-mode are the two levers for controlling what Claude can do without prompting
  • Capture session_id from JSON output to resume multi-step pipelines
  • For Python/TypeScript with callbacks and typed messages, use the full wiki/agent-sdk/_index

Sources

  • raw/Run Claude Code programmatically.md