Verified against Claude Code · 2026-08-07
Script a Claude Code headless run that a CI pipeline can actually trust
A prompt structured for Claude Code's non-interactive headless invocation — explicit output-format contract and exit-condition rules — so a CI step gets a parseable, deterministic result instead of conversational prose no script can act on.
The prompt
Ready to copy — highlighted parts are example details you can swap.
This prompt is invoked headlessly in print mode inside a CI pipeline, with no human present to answer a permission prompt or clarify an ambiguous instruction. Because of that, resolve ambiguity using the stated defaults below rather than asking a question that would never be answered, and never wait on approval before completing the task.
TASK
Run the full lint and typecheck suite against the current branch, and if there are auto-fixable lint violations, apply the fixes and commit them with message 'chore: auto-fix lint violations'.
DEFAULTS TO USE WHEN THE TASK IS AMBIGUOUS
If a lint rule violation is not auto-fixable, leave it unfixed and list it rather than guessing at a manual fix.
TOOLS AVAILABLE IN THIS RUN
Bash(npm run lint:*), Bash(npm run typecheck:*), Bash(git commit:*), Edit
OUTPUT CONTRACT — THE PIPELINE PARSES THIS PROGRAMMATICALLY
Produce exactly one JSON object as the final output, matching this shape, and nothing after it:
{ status: "success" | "blocked" | "needs_human", lint_violations_fixed: number, lint_violations_remaining: string[], typecheck_errors: string[], reason: string | null }
Do not wrap it in a markdown code fence, do not add commentary before or after it, and do not emit partial JSON if the task fails partway — emit a complete object with a status field describing the failure instead.
EXIT CONDITIONS
- If the task completes successfully against its stated definition, set status to success and populate every other field.
- If the task cannot be completed for a reason the pipeline should surface to a human later, such as a missing file or a test that fails for reasons outside this task's scope, set status to blocked and put the specific reason in the reason field — do not attempt an unrequested workaround just to force a success status.
- If a step in the task would normally require a permission prompt that cannot be answered in this unattended context, such as installing a new dependency, do not attempt it silently and do not fail silently either — set status to needs_human and name the exact action that needed approval.
CONSTRAINTS
- Do not produce output that reads well to a human but cannot be parsed by a script; the JSON object is the actual interface here, and a pipeline that fails to parse it fails the whole run regardless of whether the underlying work was correct.
- Do not retry a failed step more than 1 times before reporting blocked; an unattended run that loops indefinitely on a step that will not succeed wastes CI time with no path to resolution without a human anyway.
- Log a brief plain-text trace of what was attempted, in order, before the final JSON object, so a human reading CI logs later has a narrative to check against the machine-readable result.
- Only use the tools listed in Bash(npm run lint:*), Bash(npm run typecheck:*), Bash(git commit:*), Edit; if the task as described would require a tool outside that list to complete fully, report that gap through the needs_human status rather than attempting the closest available substitute silently.
Begin the task now.Customize
Optional — swap in your own details for the highlighted parts above.
Why this works
Claude Code's print mode genuinely removes the interactive human loop that ordinary sessions rely on for permission prompts and clarifying questions, so a prompt written for headless use has to pre-resolve every ambiguity the model would normally ask about, because there is no one there to answer — this is a structurally different authoring problem than an interactive-session prompt, not just a shorter version of one. The single-JSON-object-and-nothing-else contract matters because a headless run's output is consumed by a script, not read by a human — Claude's default conversational register, which explains, hedges, and adds a caveat, is actively harmful in this context because it breaks a naive JSON parse the same way one stray character would; a structured output flag on the CLI is designed exactly for this, and calibrating the prompt itself to that contract matters just as much as the flag does. Distinguishing 'blocked' from 'needs_human' as separate statuses acknowledges a real asymmetry unattended runs face: some failures are inherent to the task, such as a test that genuinely fails, while others are failures of authority, such as an action needing a permission grant nobody is present to give, and collapsing both into one generic failed status loses information a human triaging CI failures the next morning actually needs in order to act efficiently rather than re-diagnose from scratch. Bounding retries matters because an unattended agent looping on a step with no possible resolution is a pure CI cost with no corresponding chance of success, unlike an interactive session where a human might notice and intervene mid-loop before it burns through the same budget. Restricting the run to exactly the tools named for it, rather than whatever the agent's default permissions would otherwise allow, matters more in headless mode than in an interactive one specifically because there is no ask step available to catch an over-broad action before it executes — a permission that would merely prompt a human in an interactive session executes silently and irreversibly in an unattended one, so the tool list here is doing the safety work an ask list cannot do when nobody is present to answer it.
Verified against
Claude Code Sonnet 4.6 · 2026-08-07
Changelog
- 2026-08-07 — Initial publish, verified against Claude Code headless print mode (Sonnet 4.6).
Building this for real?
This is a free starting point. If you'd rather have custom software built and running for your business, that's Scult's day job.
EXPLORE CUSTOM SOFTWARE
