--- title: "Run Claude Code Programmatically (CLI / Headless)" aliases: [headless-mode, claude-p-flag, programmatic-claude] tags: [claude-code, cli, headless, automation, ci-cd, agent-sdk] sources: [raw/Run Claude Code programmatically.md] created: 2026-04-17 updated: 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|Agent SDK]] packages instead. --- ## Basic Usage ```bash 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. ```bash 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 ` | | MCP servers | `--mcp-config ` | | Custom agents | `--agents ` | | Plugin directory | `--plugin-dir ` | --- ## Structured Output ```bash # 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 ```bash 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 ```bash # 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 ```bash # 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 ```bash 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 - [[wiki/claude-code/skills|Skills]] (`/commit`, etc.) and built-in commands are **only available in interactive mode** — describe the task in plain language instead - [[wiki/claude-code/agent-teams|Agent teams]] and channels require interactive or SDK sessions --- ## 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|Agent SDK]] --- ## Sources - `raw/Run Claude Code programmatically.md`