$ backgroundclaude
guide · 01

Headless mode: Claude Code without the TUI

The fastest way to run Claude Code in the background is also the oldest: the -p flag. No interactive prompt, no TUI, no human watching. Just Claude Code, a task, and an exit code.

The one-liner

claude -p "Summarize what changed in the last 10 commits on this branch"

That's the whole API. -p (short for --print) tells Claude Code to skip the interactive session, process the prompt, print the result to stdout, and exit. Everything else is guardrails.

The four flags that matter in production

A bare claude -p call will cheerfully spend your entire monthly budget debugging one stubborn typo. You want these four flags on every unattended invocation:

--allowedTools

By default Claude Code will ask before running any tool. In headless mode, there is no “asking.” Either you pre-authorize the tools you trust, or it freezes. Be specific:

claude -p "Run tests and fix anything that breaks" \
  --allowedTools "Bash(npm test),Edit,Read"

Note the scoped bash — Bash(npm test) allows only npm test, not arbitrary shell. Scope aggressively.

--max-turns

Caps how many tool calls Claude can make before giving up. 40 is a sane ceiling for a CI job. 5 for a pre-commit hook. 120 for an overnight refactor. Pick a number you'd be okay wasting.

--max-budget-usd

A hard dollar ceiling. The run aborts when it hits the cap. Set it to the cost of the mistake you can tolerate, not the cost of the happy path.

--output-format json

Without this, stdout is human-readable prose and you'll end up parsing it with regex. With it, you get a structured envelope: messages, tool calls, tokens, final answer. Pipe it to jq and your automation stops being hostage to prompt wording.

claude -p "Review this diff" \
  --output-format json \
  | jq -r '.messages[-1].content'

A production-shaped invocation

claude -p "$PROMPT" \
  --allowedTools "Bash(git:*),Bash(npm test),Edit,Read,Grep" \
  --max-turns 40 \
  --max-budget-usd 2 \
  --output-format json \
  > result.json \
  2> claude.err

Stdout is your structured result. Stderr is Claude's progress log — archive it, don't grep it for control flow. Exit code tells you success vs. budget/turn limit vs. hard failure.

Where headless mode ends

Headless mode is a single process, one prompt in, one result out. That's the right tool for:

It is the wrong tool for:

For those, you want either scheduled tasks with real guardrails or a full background agent loop.

Further reading

skip the scaffolding

Cyrus wraps all of this for you.

Allowed-tool scoping, budgets, isolation, audit logs, approvals, two-way sync with Linear and GitHub — the stuff you'd otherwise script yourself, already shipped. Setup in minutes.

Try Cyrus free →