How to Run Claude Code Headlessly in CI/CD Pipelines
▶ Watch on YouTube & subscribe to The Stack Underflow
Claude Code is the interactive coding assistant you run in your terminal — but it has a second mode that most developers overlook. Pass the -p flag with a prompt and Claude runs once, outputs its result, then exits. No shell, no back-and-forth, no human in the loop. That single change is what makes Claude composable with any CI/CD system.
This tutorial walks through exactly what headless mode is, how it differs from interactive mode, where the guard rails live, and which automation tasks it handles best.
The one-sentence version:
claude -pturns Claude Code into a scriptable command that reads a prompt, runs the same full agent engine, and returns structured output — making AI review and codegen steps drop-in additions to any pipeline.
Interactive vs. Headless: The Two Modes
Think of Claude Code as having two operating modes on a spectrum:
Interactive (default) Headless (-p flag)
───────────────────── ──────────────────
Human types prompt Prompt passed as argument
Agent asks follow-ups One prompt, one run, then exit
Output: chat messages Output: structured JSON (or text)
Gate: the human Gate: your config / allow list
On the left, the familiar loop: you type into the Claude Code chat, the agent reads your CLAUDE.md context file, and you iterate. On the right, claude -p — one prompt, one run, then exit. No interactive shell.
The critical point the video makes is that headless is not a stripped-down mode. It is the same engine, the same tools, the same conventions. CLAUDE.md is loaded. Read, grep, and bash all work. The difference is purely in how input arrives and how output is consumed — structured JSON that can be piped into jq or any downstream script.
Running Claude in a CI Pipeline
The pattern is straightforward. On every pull request event, a CI step invokes claude -p with a prompt describing the review task. Claude reads the diff, produces a review.json file, and a later step picks up that file and posts it as a PR comment.
# Example GitHub Actions step
- name: AI PR Review
run: |
claude -p "Review the diff in this PR. Output a JSON object with keys: summary, concerns, suggestions." \
> review.json
- name: Post Review Comment
run: |
gh pr comment ${{ github.event.pull_request.number }} \
--body "$(jq -r '.summary' review.json)"
The headless run removes the human gate. Nobody is there to approve mid-run, so the gate moves into your configuration.
Guard Rails: How to Keep It Safe
Because headless runs are unattended, you need explicit boundaries. The video identifies four levers:
| Guard Rail | What It Does |
|---|---|
| Tool allow list | Scope which tools Claude can call (--allowedTools) so it cannot run arbitrary commands |
| Max iteration cap | Limit how many reasoning steps the agent takes before stopping |
| Fail closed | If something looks wrong or ambiguous, return a non-zero exit code rather than guessing |
| Structured output | Request JSON so downstream steps have a predictable schema to parse |
Scoping tools tightly is especially important in CI. If the task is “review a diff,” Claude does not need write access to the filesystem or the ability to run shell commands. Lock it down.
The Production-Shaped Fallback
One practical pattern the video highlights: make your pipeline resilient to Claude not being installed. A simple wrapper does this:
if command -v claude &> /dev/null; then
claude -p "$PROMPT" > output.json
else
echo "Claude not found, skipping AI step" >&2
echo '{"skipped": true}' > output.json
fi
Check if claude is on the path. If it is, run it. If not, log a skip and keep going. Your pipeline never breaks just because the binary is missing in a particular environment.
This is the “production-shaped fallback” the video mentions — treating the AI step as an enhancement, not a hard dependency.
Four Sweet Spots for Headless Claude
The video calls out four categories of tasks where headless mode earns its keep:
- PR triage — Classify incoming pull requests by size, risk, or affected area without a human skimming every diff.
- Changelog and release note drafts — Feed Claude the commit log between two tags and get a first draft of release notes in structured markdown.
- Code mods across the repo — Targeted refactors or migrations (rename a config key, update an API call signature) across many files in one unattended pass.
- “Is this doc still true?” checks — Compare documentation against the current codebase and flag divergence.
The common thread: anywhere a human would normally skim and make a judgment call, claude -p can do a first pass and produce a structured signal for the pipeline to act on.
ASCII Overview
Pull Request Event
│
▼
CI Step: claude -p "review diff"
│
├── CLAUDE.md loaded
├── Tools: read, grep (scoped by allow list)
├── Max iterations: N
│
▼
review.json ──► Post as PR comment
Common Misconceptions
- “Headless mode is limited — it can’t use real tools.” Wrong. The same tool set available in interactive mode is available headlessly. The allow list is there for safety, not capability.
- “
claude -pneeds a special server or API key beyond the normal Claude Code setup.” No. It uses the same binary and the same authentication. The-pflag is just a run-mode switch. - “JSON output means I have to write complex prompts.” Not really. A simple instruction like “output a JSON object with keys X, Y, Z” is usually enough. Claude Code follows output-format instructions reliably.
- “If Claude errors mid-run, the pipeline will hang.” Properly configured with a max iteration cap and
fail closedbehavior, the process exits with a non-zero code that your CI system can catch and handle like any other failed step.
Frequently Asked Questions
What does the -p flag actually do?
It puts Claude Code into “print” or “prompt” mode — you supply the prompt as a CLI argument, Claude runs the task to completion, writes output to stdout, and exits. There is no interactive session. This makes it usable anywhere you can run a shell command.
How do I control which tools Claude can use in CI?
Use the --allowedTools flag (or the equivalent config) to pass an explicit list of permitted tools. For read-only review tasks, something like --allowedTools read,grep prevents Claude from writing files or running arbitrary shell commands.
Can I use CLAUDE.md to configure headless behavior differently from interactive?
Yes. CLAUDE.md is loaded in both modes. You can add a section that applies context or constraints specifically relevant to CI runs — just document it clearly so interactive users are not confused by CI-specific instructions.
What happens if the AI step fails? Does it block the whole pipeline?
Only if you let it. The production-shaped fallback pattern (check for the binary, catch non-zero exits, default to a {"skipped": true} output) means the AI step degrades gracefully. Whether a failed AI review blocks a merge is a policy decision you control in your CI config, not something Claude forces.
Where This Fits in the Series
This tutorial is part of the How Claude Actually Works course on The Stack Underflow. It sits at the intersection of the agent architecture topics (how Claude reads context, calls tools, and iterates) and practical deployment — showing that the same engine powering your interactive sessions can be dropped into automation with minimal ceremony. See all tutorials for the full series, including the next installment on making Claude reliable in production contexts.
Found this useful? The deep version lives on YouTube — new breakdowns of how AI dev tools actually work, weekly.
Subscribe on YouTube →