Course · Lesson 18 of 30
Headless Runs
Pro · 5 min read
Headless is Claude Code without the conversation: claude -p "task"
runs one prompt to completion — reading, editing, executing — then
exits with output and a status code. It's the bridge between "a tool
I talk to" and "a component I build with": once an agent is a
process, it composes with everything that runs processes — CI,
cron (lesson 17), other programs, a hundred parallel lanes
(lesson 19). The flags take ten minutes; the substance of this
lesson is what removing the human actually removes, and the contract
that has to be added back before a headless run is a component
rather than a liability.
The invocation, annotated
claude -p "Fix the failing tests, then summarize \
what you changed and why" \
--output-format json \
--allowedTools "Read,Edit,Bash(npm test:*)" \
--max-turns 25
--output-format json(orstream-jsonfor incremental consumption) makes the result parseable: final text, cost, turn count, session id. Non-negotiable for machine consumers — screen-scraping prose is how brittle pipelines are born.--allowedTools/--disallowedToolsscope capability per run, with pattern precision on shell (Bash(npm test:*)allows the test runner and nothing else). Headless grants are narrow by default: the CI fixer gets the test command, notBash(*). The interactive permission prompt is gone, so the grant list is the entire permission decision, made up front (lesson 6's boundary, compressed into a flag).--max-turnscaps the loop. Always set it. It converts "agent wandering in circles" from an unbounded spend (lesson 5) into a bounded, visible failure.- For full autonomy inside a container or sandbox,
--dangerously-skip-permissionsexists and means what it says: the name is the documentation. Contained environments only.
What the human was silently providing
In an interactive session, you are three pieces of infrastructure without noticing. Headless work is the discipline of replacing each one explicitly:
The approver. Permission prompts are meaningless with nobody at the keyboard — so grants are decided entirely up front (above), and invariants that used to rely on your veto move into hooks (lesson 15), which run headless exactly as they do interactively and are most of why headless is safe at all.
The judge of "done." Interactively, you eyeball the result. Headless, done must be checkable by machine: tests pass, build exits zero, output validates against a schema. The strongest pattern has the run prove itself before exiting — make the change, run the check, exit accordingly — with the agent producing evidence and deterministic code issuing the verdict (a division of labor lesson 28 hardens into law).
The handler of surprises. Interactively, a missing credential becomes a question to you. Headless, there is no asking — so every "ask if unsure" in your prompts and configs is a hole. Each ambiguity needs a policy: proceed with this stated default, or fail with this explanatory error. Audit for the holes before the first scheduled run; writing those policies down is most of the work of headlessing a workflow, and it's good work — it's your process's undocumented judgement, finally documented (and it's exactly the material lesson 8 and lesson 9 files are made of).
The process contract
A headless run should behave like any well-built Unix citizen, because that's what it now is:
- Exit status tells the truth. Zero means verified done — not "finished talking." Non-zero means not-done, including "refused for a good reason" (a clean refusal is a success of the safety system, encoded as a failure of the task — downstream must be able to tell). A run that exits zero after quietly failing poisons every step after it; this is the single most important line of the contract.
- Output is an artifact. A structured result — what was done, what was touched, what was skipped and why — to stdout or a file. Runs that leave artifacts can be audited, diffed, aggregated (lesson 19), and debugged on Tuesday. Runs that leave vibes cannot. This artifact is also lesson 17's heartbeat, for free.
- Guardrails assume no attendance. The tripod: narrow tool grants + enforced invariants (hooks) + a turn cap. Add a sandbox for the fully-autonomous end. Nothing in the tripod depends on a human noticing anything — which is the design criterion for every piece of it.
Where headless earns its keep
- CI repair: tests fail → a headless run with repo context proposes the fix as a PR (propose-don't-dispose, lesson 17; gates, lesson 28).
- Batch transformation: one debugged prompt × 400 files, dispatched as processes (lesson 19's fan-out; sample three outputs before running four hundred).
- Glue with judgement: the pipeline step that was always "a human reads this and decides" — triage, categorize, summarize, route — becomes a process with a JSON contract.
- Anything on a timer: lesson 17, which is precisely this lesson plus a scheduler plus stop rules.
The mental shift to take with you: interactively, quality comes from your steering — you interrupt, redirect, refine (lesson 6). Headless, all of that is gone, and quality comes entirely from the environment: the briefing files, the constraints, the checks — the harness (lesson 16). When a headless run disappoints, the fix is almost never a cleverer prompt. It's a stronger harness around a simpler one — and every improvement you make there pays in your interactive sessions too, because it's the same environment. That convergence is the tell that you're building the right things.
A personal teaching project, in development. The registry it builds is a teaching artifact and is not an assurance opinion about any issuer. Not affiliated with or endorsed by any employer, or by any vendor whose tools it describes. Where a unit depends on a specific flag or path, it names the version it was verified against. All units.