§04.05

How to Run Claude Code Headless in a Script or CI

Run Claude Code non-interactively with claude -p, get JSON back, pre-approve tools, and wire it into a CI job. Copy-paste.

published 06 Sept 2026 checked against docs 06 Sept 2026 4 min in Workflows Markdown

Step 5 of 6 · Try the other coding agents

On this page4 sections
  1. 1. One prompt, one answer
  2. 2. Pre-approve the tools it needs
  3. 3. Get JSON out
  4. 4. Harden it for CI

claude -p runs a single prompt and exits. No TUI, no approval prompts to click — which is exactly what a script or a CI job needs.

1. One prompt, one answer

claude -p "What does the auth module do?"

-p (long form --print) is the whole trick. Claude Code exits with code 0 on success and non-zero when the run fails, so your script can branch on $?.

It also reads stdin, so it composes like any other command-line tool:

cat build-error.txt | claude -p 'concisely explain the root cause of this build error' > output.txt

2. Pre-approve the tools it needs

Without permission to act, a headless run can only talk. --allowedTools grants tools up front:

claude -p "Run the test suite and fix any failures" \
  --allowedTools "Bash,Read,Edit"

You can scope Bash down to specific commands using permission rule syntax:

claude -p "Look at my staged changes and create an appropriate commit" \
  --allowedTools "Bash(git diff *),Bash(git log *),Bash(git status *),Bash(git commit *)"

The space before * matters: Bash(git diff *) matches git diff …, while Bash(git diff*) would also match git diff-index.

3. Get JSON out

claude -p "Summarize this project" --output-format json | jq -r '.result'

--output-format takes text (default), json (result plus session ID, cost, and metadata), or stream-json (newline-delimited events). The JSON payload includes total_cost_usd, so a script can log spend per invocation.

4. Harden it for CI

Add --bare. It skips auto-discovery of hooks, skills, custom commands, subagents, plugins, MCP servers, and CLAUDE.md, so the run behaves the same on every machine instead of picking up whatever is in the repo or a teammate’s ~/.claude. Bare mode doesn’t use your subscription login, so set ANTHROPIC_API_KEY:

claude --bare -p "Summarize README.md" --allowedTools "Read"

A wrapper in package.json turns this into a project-specific reviewer:

{
  "scripts": {
    "lint:claude": "git diff main | claude -p \"you are a typo linter. for each typo in this diff, report filename:line on one line and the issue on the next. return nothing else.\""
  }
}

Tip: in an unattended job, nobody can answer a permission prompt. Pass --permission-prompts none so anything that would prompt is denied and the run continues instead of hanging.

Next: set up the Claude Code GitHub Action or tighten Claude Code permissions.

← All Workflows plates · Search all guides

↑↓ move↵ openalt+↵ copy first command

Keyboard

⌘/ctrl+K or /
Search all guides
alt+↵
In search: copy the guide's first command
j / k
Move through a list of guides
c
On a guide: copy its first command
t
Toggle light / dark
?
This list