C Claude Cert Prep All Claude Certifications

CI/CD and Headless Claude Code

Running Claude Code non-interactively in pipelines, and why permissions must be fully configured before the run starts.

Claude Code·Lesson 6 of 6·7 min

Headless mode runs Claude Code non-interactively — no terminal session where a human is watching and available to answer prompts. This is the mode used to embed Claude Code into CI/CD pipelines: a build step that asks Claude to review a diff, generate release notes, fix a failing test, or perform some other bounded task as part of an automated workflow, triggered by something like a pull request or a scheduled job rather than a person typing at a prompt.

The core constraint: no fallback prompt

In an interactive session, when Claude Code hits a permission rule set to ask, it pauses and waits for you to type yes or no. In headless mode, there is no one there to answer. This is the single most important operational fact about CI/CD usage: permissions must be fully configured up front, before the run starts, because there's no interactive fallback mid-run. An ask rule that would have paused politely in your terminal instead becomes a stall or a failure in a pipeline — the run has no mechanism to resolve it.

Practically, this means a headless configuration needs its allow and deny rules to be exhaustive enough that the pipeline's task can complete without ever hitting an unresolved ask. This pushes teams toward being more deliberate about scoping permissions for CI-specific settings.json than they might be for an interactive developer session, precisely because there's no human safety net available if the scoping is wrong.

Exam trap A common distractor suggests that headless/CI usage is just "the same as interactive Claude Code but automated," implying permission prompts still function the same way. They don't functionally resolve the same way — an unanswered ask prompt in a non-interactive run doesn't get politely deferred, it blocks progress or causes the run to fail outright, since nothing is listening for a reply. Another trap: suggesting the fix for CI is to allow everything to avoid stalls. That reintroduces the blanket-allow problem from permission design, just in a higher-stakes environment (an unattended pipeline with write access to your repo and possibly your infrastructure). The correct answer is precise upfront scoping, not blanket allow and not leaving ask rules in place.

What headless runs are good for

Bounded, well-defined tasks with a clear success condition work best: automated PR review comments, generating a changelog from commits, running a fix-and-verify loop against a failing test where success is objectively checkable, or triaging an issue and proposing a labeled response. Open-ended, judgment-heavy tasks are a worse fit for headless mode precisely because there's no human present to redirect Claude if its approach goes sideways mid-task — which is also why plan-mode-style human checkpoints don't translate directly into a headless pipeline; the checkpoint has to be replaced by tight upfront scoping instead.

Subagents in pipelines

CI/CD tasks are also a natural place to use subagents — separately configured agents with their own system prompt and restricted tool access, delegated a scoped piece of work by a main agent. A pipeline might use a narrowly-scoped subagent purely for running and interpreting test output, with no permission to touch deployment configuration, keeping the blast radius of that piece of the pipeline small even within an already-headless run.

Scenario: A team wants to add a CI step where Claude Code automatically reviews every pull request and posts a comment, but their existing settings.json has several permission rules set to ask because that's fine for their local interactive workflow. What breaks when they wire this into CI as-is, and what's the fix? The ask rules will stall or fail the pipeline step since there's no one to answer the prompt in a CI runner. The fix is a CI-specific settings.json (or override) that converts every rule the pipeline actually needs from ask to a precise allow, and leaves genuinely dangerous operations as deny rather than defaulting to allow just to unblock the run.

Try it

Run Claude Code in headless mode locally against a small, bounded task (check your CLI's non-interactive invocation flag), using a settings.json where every permission the task needs is explicitly allowed and everything else is denied. Confirm the run completes without ever needing you to answer a prompt, then deliberately remove one needed allow rule and observe how the run fails or stalls instead of asking you.

← Plan Mode and Human Review System Prompts vs. User Messages →