Glossary · agent replay

Headless agent

▸ Definition

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.

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.

Reelier · replay receipt
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
verbatim output

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.

Reading as an agent? This page has a markdown twin: /learn/headless-agent/md