Autonomous agents are the easy part
One morning last week I opened my inbox to a hundred emails, all sent from me, to me, most of them stamped within the same two minutes of the night before. That is the end of the story. To make it mean anything I have to start with how I work, because most of what broke came from the shape of the setup, not from the AI.
Ten projects and no idea where to look
I am one person with about ten live projects, ten folders on a Mac Studio, one iTerm tab and one Claude Code session each. Two or three do real work at once while I move between them. I have written about that part before. It works.
The coding was never the problem. Knowing what to code next was. When an idea hit me away from the desk I emailed it to myself, project name and one line. When I was deep in a project and noticed something, I told Claude Code to put it on the to-do list, and it did, in that project’s own list.
After a few months I had ten to-do lists. Every morning started with the same useless question: which of ten projects deserves the next hour, and which of these tasks could a machine just do without me. Ten lists cannot answer that. They are not a list, they are ten little piles, each blind to the other nine.
One list instead of ten
So in mid-July I made a new project whose only job is to look at the other ten. The master-supervisor. It started as nothing clever, a script that walks every repo, reads a small status file, and builds one ranked overview so I open one thing in the morning instead of ten.
Then the move that actually mattered. I deleted all ten to-do lists on the same day and replaced them with one system-wide list the supervisor owns. And I stopped calling the entries to-dos. They are orders now, as in work orders, because the rename was the point: these are not notes to myself anymore, they are units of work something can pick up and execute.
The label that decides everything
An order is a small block of markdown: a title, a couple of fields, a line or two of description. One looks roughly like this:
## ORDER update-mcp-server
art: autonomous
prio: medium
Bump the MCP server to the current major version
and re-run the integration tests.
Two of those fields do the work, and the first is the one that matters. It is a field called art, with three possible values:
- autonomous: Claude Code can just do this, unattended, and ship it.
- dialog: I want to be in the loop while it happens.
- decision: only I can make the call. A payment going live, a domain purchase, a public announcement.
No AI decides which bucket an order goes in. I would love to tell you the machine reads the task and works out for itself whether it is safe to run alone, and I built the opposite on purpose. Whoever writes the order sets the label, right then, with the full context of having just thought of it. The dispatcher is not allowed to guess later, because a script reading a title cannot judge difficulty. It can only pretend to.
And the default, when the field is missing or unclear, is dialog, never autonomous. That asymmetry is the whole safety model in one line. An order that sits and waits for me costs a little time. An order that runs on its own when it should not have costs work on production. So the machine leans toward asking, and autonomous has to be earned, not assumed.
The second label is a priority, and I will admit straight out that this is the part I have least figured out. I set it by hand, high, medium or low, and every few days I still sit down and re-sweep the whole queue by hand because the automatic ordering is not good enough yet. Forty-one autonomous orders in one sweep, of which I freed thirteen and held fourteen. That is not an algorithm, that is me with a highlighter. It is the honest state of it.
Where the orders come from, and the one rule I will not bend
Orders arrive three ways, and most of the machinery around them exists to keep one door shut. Ideas I email myself and alerts my systems raise both land in the same inbox, but nothing there becomes an order on its own. They turn into orders during triage, when I am reading the inbox anyway and I am the one filing them. That is a fixed rule, not laziness: a mail that could promote itself into an autonomous task is an open door, because anyone who can email me could hand my machine instructions, and the AI reading the mail cannot tell my intent from an attacker’s paragraph. Mail stays a human gate.
The third way is me, in a project, saying “put that on the list,” and that goes through a shared, append-only mailbox the supervisor turns into real orders in its own files, one writer per file. It sounds like bureaucracy and it is what keeps the history readable. As I found out last time, the version of that rule which actually holds is a hook that returns an error, not a line in a document.
The five-minute night shift
Now the part that runs while I sleep. A script fires every five minutes. It looks at the queue, takes the top orders that are both approved and marked autonomous, and for each one it does something I should have done from the start: it creates a fresh git worktree, a clean checkout of the project’s main branch in a scratch directory of its own. Not my working copy, with its half-finished edits and open files. A clean, isolated copy, so the machine can never collide with me or with another session already working in that repo. The old version of this skipped any project that was “busy” and in practice never got a turn. The worktree fixed that by refusing to share.
Inside that worktree it runs Claude Code headless, gives it the order, and lets it work, with a wall-clock timeout and a limit of a handful of orders per cycle so a runaway cannot eat the night. When it finishes, it tries to merge. If the merge is clean, a straight fast-forward with nothing to reconcile, it does it alone. If there is any conflict, it does not get clever. It leaves the branch sitting there, pings my phone, and tells me to open that project and resolve it with the context only a human has. Clever conflict resolution is where the subtle bugs live, so it is banned. After a clean merge a second, independent review runs, and if that passes, it deploys to production. Approved means live.
That is the machine. On a good night it is genuinely good. Then I turned it all the way on, and found out what “good” was hiding.
The night it ran itself, and the cracks
Overnight it built, merged and deployed sixty-six orders across sixteen repositories, the ten I think of as my projects plus the smaller and infrastructure repos around them. The language banner shipped. A dependency got patched. An MCP server got built. Work I would have taken a week to grind through, gone by morning. I was impressed for about four minutes, and then every crack showed itself, and every one was in the same place: not the work, but what the machine told me about the work.
Start with the hundred emails. I had given it a friendly habit: mail me when an order finishes, mail me when one needs a decision. Overnight it cleared a backlog, so I woke to seventy-two “done” and twenty-eight “needs you”. Those twenty-eight were the entire point, the orders where the machine had correctly stopped and asked. They sat buried under seventy-two messages whose only content was that I had not been needed. At 01:44 I emailed myself one more time, half asleep and annoyed, and it is the sharpest design review I have written in months: turn the done-emails off, failure case only. Successes go to a log now. The classification had been right all along. I was just shouting the boring ninety-nine percent and the vital one percent at the same volume.
Meanwhile my phone was buzzing red all day. Acceptance failed, over and over, on deploys that had gone through perfectly. One order was a cleanup task that ships nothing to production; the checking layer did not know that, demanded a deploy that could never come, and screamed every five minutes for a day. Another whole batch came down to one character. A ! in front of a shell pipeline negated the exit code of the wrong part of it, so a check that had passed came back looking failed. The agents had done the work correctly. The layer I wrote to verify the work was the buggy part, and every one of its bugs pointed the same direction: it called good things bad.
Then the one that made me stop patching and think. Two nights earlier the same layer had failed the other way round. A typo killed the review script, and a crashed script returns the same exit code as a script that runs fine and says no. The machine could not tell “the reviewer objects” from “the reviewer fell over”, so it did the safe-looking thing and held. Quietly. Eighteen orders sat marked finished without ever reaching production. A crash, an objection and a pass are three separate signals now, and a crash never again looks like a considered no.
What the hard part actually is
Put them next to each other and it is one problem in several costumes. A day of “everything failed” that meant nothing. A night of “everything is done” where the eighteen that mattered had not happened. A hundred emails hiding twenty-eight. Every time the work itself was fine, and the thing that decides what reaches me was where it went wrong.
Whether an agent can do the task is mostly settled, and it settled faster than I expected. Sixty-six deploys in a night is not the impressive part anymore. What is unsolved is the channel back to me: can I trust it when it says all clear, and does its “I need you” reach me instead of drowning in its own applause. Get that wrong and autonomy is not autonomy, it is a machine working in a room you are now afraid to leave.
None of the safety here lives in prompts, incidentally. It lives in exit codes, file locks, and a default that refuses to run when in doubt.
Mine is a few days into the fixed version and nothing is proven. But the ratio is the real news. The doing came almost for free. Two nights of my life went to teaching the thing how to tell me the truth about what it had done. If you are running more than one project through Claude Code, that is where your time is going too, whether you have found out yet or not.
Get new posts by email
One mail when a new post is out. Nothing else: no drip campaign, no tracking, no "quick question" follow-ups. Unsubscribe with one click, any time.
Double opt in: you get a confirmation mail first. Your address is used only to send these posts. Controller: Martin Schenk S.L. · Privacy