A small thing I've been noticing: the claude CLI's headless mode — running with -p for a single prompt, piping a file in, writing output to disk, exiting — has quietly moved from "neat capability" to "this is how the work actually gets done." Not for everyone. But for a growing set of operators who run agents on a schedule rather than in a conversation, the dashboard is no longer the centre of gravity.
I've been reading the GitHub Issues, the tool reference docs, the changelogs across Claude Code, Codex CLI, Aider, and the wave of headless-first wrappers built on top of them. The shape that emerges is consistent. The interactive REPL is still where most people first meet the tool. The CLI is where the people who shipped something with it last week are spending their time.
Why the CLI grew first
The interactive chat surface is hard to formalise. Each session is a new conversation, the context window is fresh, the user's intent has to be re-established, the agent's behaviour calibrates to whatever the operator types in the moment. That's a fine product for exploration. It's a terrible product for recurrence.
Headless mode inverts those properties. The prompt is in a file. The context is loaded from a known location. The output is structured (JSON if you ask for it). The exit code tells you whether the run succeeded. The whole thing composes with cron, with systemd timers, with CI pipelines, with Make. The agent stops being a colleague you converse with and starts being a tool you invoke.
The analogy I keep reaching for: this is the same shift git went through when GitHub Actions started being more central to teams' workflows than the GitHub web UI. The web interface was where people learned git. The YAML files were where production lived.
What this is actually used for, today
From what I can tell from the tooling that's been built recently — the CLI scheduling wrappers, the agent-runner frameworks, the GitHub Actions integrations — the dominant headless workloads are recurring writing and analysis tasks (newsletter digests, blog drafts, content moderation passes), automated codebase grooming (dependency updates with structured rationale, doc generation against changelogs), and operational triage (issue classification, log summarisation, alert deduplication).
What they share: a predictable cadence, an inputs-to-outputs contract that can be written down, and a tolerance for the run failing occasionally without the world ending. The same shape that made early cron jobs work.
What it doesn't yet handle well
The CLI's maturity is uneven. Output structure varies between vendors — Claude Code's JSON output schema is one thing, Codex CLI's is another, no one agrees on what a "result" looks like, and operators end up writing thin wrappers to normalise. Error handling is still mostly "did the process exit zero." Long-running tasks are hostile to the model — you want them to take an hour, the model wants to finish in thirty seconds and stop.
And the genuine new problem: when a run produces output you don't fully verify before it ships, you've quietly built a system where the model writes and the model checks. The same verification tax I've been writing about for months reappears here as a substrate problem — you can't read every output of a daily run forever.
The practical takeaway
For a small team thinking about whether to adopt headless agent runs: the CLI tooling is now mature enough to be worth learning. The contract is real. The composition with existing infrastructure is genuine. What's not yet mature is the operational layer above it — the dashboards, the alerting, the audit logs, the "this run produced output that diverged from the last fourteen runs" pattern detection. That tooling exists in pieces. It's not yet a category.
Which means right now is the productive window for small teams to learn the substrate before the substrate gets a UI that hides what it's doing.
When the dashboard catches up, the operators who learned the CLI first will have something the new arrivals won't: a working model of what the agent is actually doing when no one is watching.