Headless mode & CI automation
Headless mode turns Claude Code into a scriptable command. claude -p "prompt" runs once, prints a result, and exits — perfect for pipelines, batch migrations, and GitHub Actions.
The basics
Run a single non-interactive prompt:
claude -p "Summarize the changes in the last commit and flag anything risky."Pick a machine-readable output format when a script consumes the result:
# one JSON object with the result and metadata
claude -p "..." --output-format json
# incremental JSON events as they happen
claude -p "..." --output-format stream-jsonUse json when you just need the final answer and stream-json when you want to process events live (progress, tool calls) in a longer run.
Fan-out migrations
The headless pattern that pays off most: generate a list of files, then loop claude -p over each one. This parallelizes a mechanical change across a codebase.
# 1. Generate the work list
files=$(claude -p "List every file under src/ that still imports the deprecated 'moment' library. One path per line, no prose." \
--output-format json | jq -r '.result')
# 2. Apply the change file-by-file, scoped tightly
for f in $files; do
claude -p "In $f, replace moment usage with date-fns. Keep behavior identical. Commit with a clear message." \
--allowedTools "Edit,Bash(git commit:*)"
done--allowedTools is the safety boundary. Here Claude can only edit files and run git commit — it can't run arbitrary shell, push, or delete. Scope the allowlist to exactly the operations the task needs.
IMPORTANT
Test on a few files first, then run at scale. Point the loop at three files, inspect the diffs and commits, and only then unleash it on the full list. A mistake repeated across 200 files is expensive to unwind.
WARNING
In CI and unattended loops, Claude runs without a human approving each action. Keep --allowedTools minimal, run in a branch or git worktree, and review the resulting diff before merging.
GitHub Actions
Anthropic ships an official action for wiring Claude into your repo:
# .github/workflows/claude.yml
name: Claude
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
jobs:
claude:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}With this in place, mentioning @claude in a pull request or issue comment triggers Claude to act — answer a question, implement a requested change, or review the diff — and report back on the PR. Treat it as a teammate you delegate to in the open: scope the request, then review what it pushes.
NOTE
Keep the model choice deliberate in CI. Routine, well-specified jobs run fine on Sonnet; reserve Opus for genuinely hard automated tasks, since CI volume multiplies cost quickly.
Tips
- Be specific. Headless prompts get no follow-up. A vague instruction wastes a whole run and tokens; name files, interfaces, and the done condition.
- Make work verifiable. Have the prompt run tests or a build and fail loudly, so the pipeline catches bad output instead of merging it.
- Capture output. Pipe
--output-format jsonintojqto assert on results and gate the pipeline.
Why this works
Headless mode is the same engine as interactive Claude with the human loop removed, so the same rules apply harder: tight scope, explicit verification, and minimal tool permissions. The fan-out loop scales a single good prompt across an entire codebase.
Related: Cheatsheet · Best practices · Learning path
Source: Claude Code best practices; community practice.