# Headless agent

> A headless AI agent is an agent that runs without a user interface: no chat window, no person watching the run, no one to ask mid-task. A machine starts it — a cron schedule, a CI pipeline, a webhook, another agent — and it does its work through tool calls and reports through machine-readable channels: an exit code, structured output, a pull request, a run record on disk. The name borrows from headless browsers, but the sense is different: a headless browser is a UI-less way to drive a website, while a headless agent is a UI-less way to run the agent itself. The same shape ships under adjacent names — background agents, scheduled agents, non-interactive mode.

Markdown twin of https://www.reelier.com/learn/headless-agent — one entry in Reelier's glossary of agent-replay terms. The blockquote above is the canonical definition; quote it with the link.

## One word, three machines

“Headless” predates agents by decades. A headless browser is a real browser engine running without a visible window — Playwright launches Chromium with `headless` defaulting to true, and CI has run browser tests that way since long before models could click anything. A headless CMS is a content backend with the presentation layer cut off. In both, the “head” is the UI, and removing it is what makes the thing scriptable.

Agents inherited the word along with a collision. Search results for “headless AI agent” mix two shapes: an agent that drives a headless browser (scraping and UI testing with a model in the loop), and an agent that is itself headless — no chat surface, started by a machine, finished before anyone looks. This page defines the second. The two compose without implying each other: a headless agent may hold a headless browser as one of its tools, and an engineer babysitting a Playwright script in a terminal is using a headless browser with no headless agent in sight.

The UI-less sense is now vendor vocabulary. Anthropic's docs for running Claude Code non-interactively — `claude -p`, built for scripts and CI — live at a URL slug named `headless`. Cursor ships Cloud Agents, formerly named Background Agents, in isolated cloud VMs. “Scheduled agents” and “background agents” name the same shape from the trigger side.

## The contract: decided before, reported after

An interactive agent can ask. A headless one cannot, so every judgment a person would supply mid-run moves to one of the two ends. Before the run: permissions and scope get decided upfront — Claude Code's non-interactive mode takes an explicit `--allowedTools` list because nobody sits at a prompt to approve a tool call. After the run: the result must be machine-readable, because the first consumer is a scheduler, a CI job, or another program. An exit code, structured JSON, a pull request, a run record on disk.

The triggers are mundane, which is the point: cron fires, a CI event lands, a webhook arrives, a parent agent delegates a subtask. A run is headless when no human sits in the loop between start and finish, wherever it happens to execute — your laptop, a CI runner, a vendor's VM.

## Where it breaks: nobody is watching

Interactive use hides a failure mode that headless use exposes. In a chat session, a person notices the odd tool call, the improvised workaround, the answer that smells wrong. Headless, the same behavior ships: an agent that quietly adapts to a changed API on Tuesday's 3am run produces a report nobody knows to distrust. The agent's own summary is no control, either — a model's account of its work is more model output, subject to the same failure modes as the work.

Writes raise the stakes. In the measured corpus behind Reelier's launch writing, only about 1.1% of scanned sessions were read-only end-to-end; nearly every real agent job writes somewhere. An unattended process that writes on every firing needs an explicit write policy more than an attended one, because no one is there to say stop. And each firing bills a full model session — tool definitions loaded, instructions re-read, the plan re-derived — so on a schedule the spend recurs whether or not anything changed since yesterday.

## The Reelier angle: remove the model from the part that repeats

A job put on a schedule was chosen because it repeats, and the repeating part is what deterministic replay covers. Record the job once: where the platform keeps a scannable history, `reelier scan` and `reelier from-session` read it directly (Claude Code's transcripts are the native format); Cursor keeps its history in a SQLite database, so there is no history scan for it — capture goes through the recording proxy `reelier mcp --wrap` while the job runs once as usual. Compile the recording into a SKILL.md with an assertion per step. Then put `reelier run my-job.skill.md` on the cron instead of the agent.

That replay is the strictest headless agent run you can schedule: no UI, no person, and at the default `--max-level 0` no model either — the runner never constructs an LLM client, so the receipt's 0-token line reports a code path that cannot spend. The process exits 0 when every asserted step passes and 1 when any step fails; a receipt lands in `.reelier/runs/` either way; `reelier diff` compares the last two receipts and gives CI a SAME-or-DRIFTED verdict. Model help exists and stays opt-in, BYOK, at `--max-level 1|2`. Replay is read-only by default: recorded write steps re-fire only behind `--allow-writes`.

The boundary, stated plainly: replay covers the deterministic core, never the judgment. Triage, synthesis, and prose need a model on every run, headless or not. Most scheduled jobs are a deterministic core in a thin judgment wrapper — keep the agent for the wrapper (`reelier serve` exposes replay over MCP, so an agent can call the frozen core as a tool) and let the core run at zero.

## A real receipt

The run below is a headless agent run in the strictest sense — a machine-startable command, no UI, no person mid-run, no model: the `hn-mention-radar` portfolio skill (one read-only HTTP GET against the Algolia Hacker News search API) replayed with the published CLI. The last line is the part a scheduler reads: exit code 0, because the asserted step passed.

```
npx -y reelier@latest run hn-mention-radar.skill.md

✓ Step 1 — Search HN for mentions [passed] 896ms

PASSED: 1/1 steps ok, 0 failed, 896ms total

echo "exit code: $?"

exit code: 0
```

Run for real on 2026-07-21 with the published CLI (`npx -y reelier@latest`, resolved to `reelier@0.13.0`) in a scratch directory holding a verbatim copy of `examples/portfolio/hn-mention-radar.skill.md` from seldonframe/reelier; the two commands ran as one shell line, output verbatim. The run record the replay wrote confirms `llmInputTokens: 0` and `llmOutputTokens: 0`. Read-only, no account, no key, no model in the loop.

## FAQ

**Is a headless agent the same as an agent that uses a headless browser?**

No. A headless browser is a tool: a browser engine with no window, driven programmatically. A headless agent is a way of running the agent itself: machine-triggered, no UI, machine-readable result. They compose — a headless agent can drive a headless browser — but neither implies the other, and most headless agent runs never touch a browser at all.

**Does running headless change what the agent can do?**

The capabilities are the same model, tools, and instructions as an interactive session. What changes is the contract around the run: permissions granted upfront instead of approved live, results read by machines instead of people, and no human backstop between a drifted input and a wrong write. That is why receipts and explicit write gates matter more on headless runs than interactive ones.

## Related

- [Deterministic replay — re-running recorded work without re-running the model](https://www.reelier.com/learn/deterministic-replay)
- [Run receipts — how a run nobody watched proves what it did](https://www.reelier.com/learn/run-receipt)
- [Level-0 (zero-token) replay — the no-model default, level by level](https://www.reelier.com/learn/level-0-replay)
- [From the blog: scheduled agents re-learn the job every run](https://www.reelier.com/blog/scheduled-agents-zero-token)
- [Agent cost calculator — re-run vs. record-once-replay, on your schedule](https://www.reelier.com/tools/agent-cost-calculator)

## Sources

- [Run Claude Code programmatically — Anthropic's non-interactive mode for scripts and CI; the docs URL slug is literally “headless”](https://code.claude.com/docs/en/headless)
- [Cursor Cloud Agents (formerly Background Agents) — the adjacent vendor term for agents in isolated cloud VMs](https://cursor.com/docs/background-agent)
- [Playwright BrowserType.launch — the browser sense of “headless”, defaulting to true](https://playwright.dev/docs/api/class-browsertype)
- [seldonframe/reelier — the open-source (AGPL-3.0) implementation whose replays run headless](https://github.com/seldonframe/reelier)

Other terms: [Deterministic replay](https://www.reelier.com/learn/deterministic-replay) · [Agent drift](https://www.reelier.com/learn/tool-call-drift) · [Run receipt](https://www.reelier.com/learn/run-receipt) · [Level-0 (zero-token) replay](https://www.reelier.com/learn/level-0-replay) · [Snapshot testing for AI agents](https://www.reelier.com/learn/agent-snapshot-testing) · [Session-to-skill (skill compilation)](https://www.reelier.com/learn/skill-compilation) · [Recording MCP tool calls](https://www.reelier.com/learn/mcp-recording) · [Regression testing for AI agents](https://www.reelier.com/learn/agent-regression-testing) · [Idempotent write gating](https://www.reelier.com/learn/idempotent-write-gating) · [Assertion grammar for agent outputs](https://www.reelier.com/learn/assertion-grammar) · [Agent memory vs deterministic replay](https://www.reelier.com/learn/agent-memory-vs-replay)
