Tom Stagl

< Back to Blog

Published

Agent Fleet: Autonomous 3 Days, Active 3 Hours

Thirteen days of an agent fleet across five repos: 188 merged PRs, one cost lever that matters more than model choice, and a ceiling that turned out to be bookkeeping rather than intelligence.

Org chart of the agent fleet: Tom above lead-operator and lead-auditor, ten project leads feeding a shared queue, and 42 IC roles split across four execution pools
Who dispatches whom: two leads, ten project leads, 42 IC roles, four substrates

I scaled the April agentic-workspace idea to four repos, ten projects and forty-two agent roles, then ran it for thirteen days. Here is what it cost, which part of the architecture a platform limit chose for me, what 188 merged pull requests actually looked like, and why the real constraint was never capability.

The fleet has been alive for thirteen days now, and the first thing it taught me — on day one, before it had shipped anything at all — is still the thing I'd lead with: the number that matters isn't how long an agent runs. It's how long it's actually working.

Back in April I wrote about turning my personal site into an agentic workspace — an Obsidian vault dropped into the repo, three agents with defined jobs, everything landing in a durable file instead of a chat window that disappears when you close the tab. That setup was small on purpose. One human, one session, three agents taking turns.

In May I wrote about the next step — a self-hosted runtime and a twelve-agent fleet that ran on its own clock instead of waiting for me — and then about clawctl, the wrapper I built to talk to it. So "agents with their own schedule" is not the new thing here; I've had that since spring, and if you read those posts you already know the shape.

What's new is scale and, more to the point, what breaks at scale. This month I pushed the same idea a lot further: four repos, ten projects, forty-two defined agent roles, one operating document instead of a vault. Not because bigger is better — because the thing I actually run day to day (an engineering org, a product, a personal brand, a pile of infrastructure) is not one project. It's ten. And the same argument that worked for a personal site — write things down somewhere durable, give each role a narrow job, let the human decide what ships — either holds at that scale or it doesn't. I wanted to find out which.

I wrote most of what follows eleven hours in, when I had a design and no output, and I've left those parts standing because they turned out to be the durable ones. At the bottom I've added what thirteen days actually produced — including one number I got wrong about my own work by a factor of two.

The number that actually matters is active hours, not wall-clock hours

Here's the one that changes how I think about "autonomous." A Claude Code session costs roughly $2 an hour — but only while it's doing something. Idle, it costs nothing. I have one observed session that ran for 9.2 hours and cost $2.31, because it spent almost all of that time waiting. I have another that ran for 4.4 hours and cost $10.05, because it worked the entire time.

That second number is the honest one. "This agent has been running autonomously for three days" sounds impressive and tells you almost nothing about what it cost or what it did. Three days is lifetime. It is not burn. The agents that actually save money are the ones that never sit around polling — they subscribe to the event that matters and end the turn until it fires. An agent that sleeps to check on something every five minutes is paying full session rates to do nothing, over and over, and it doesn't ship any faster for the privilege. That's a 24x cost difference between an agent that waits well and one that doesn't, on the same task, doing the same amount of real work. It's the single biggest lever in the whole design, and it has nothing to do with which model you pick.

The topology wasn't a decision. It was a workaround.

I wanted the ten project leads to wake themselves on a schedule — Tuesday morning, check the queue, do the week's work. The mechanism for that is a scheduled trigger. What I found, only after building against it, is that a trigger-fired session comes up with no tools beyond the basics: it can read files and run shell commands, but it cannot open another session, cannot call GitHub, cannot do any of the things a lead actually needs to do its job. The parameter that's supposed to fix this — grant it the same tool access as whatever created it — returned an error saying it isn't available on this account's plan.

So the architecture that came out isn't the one I would have drawn on a whiteboard. Every lead has to be started once, by hand, from a session that already has full access — and a session made that way inherits its parent's tools, which does work. After that, a trigger is bound not to a fresh session but to that exact one, so it wakes the same conversation instead of creating a hollow new one. Ten leads, ten one-time hand-starts, ten triggers each pointed at a specific, already-alive session id. Nobody chose that shape. One undocumented limit on a scheduling primitive did, and the whole supervision structure had to fold around it.

Most of what people picture as "an agent" doesn't need a session at all

Forty-two roles are defined across this fleet. Eighteen of them run as Claude Code sessions — the expensive, capable, $2-an-hour kind that can hold a conversation, write code, open a pull request. The other twenty-four don't. They're scheduled jobs that read something, produce one document, and stop. A competitor scan. A release-notes draft. A weekly cost report. Those don't need a persistent agent that can reason across a conversation — they need a cron job and an API call, and routing them onto the expensive substrate would be pure waste, not capability.

That split didn't come from a strong opinion about agent design. It came from looking at what each role actually produces and refusing to pay session prices for a role that's really just a document generator with a schedule attached. I'd guess most people building agent fleets right now default every role to a full session because that's the interesting-looking option. It's the wrong default for two-thirds of the roster.

The baseline I quoted first was wrong

Before any of this, I wanted a number for how much this shop already ships, so I'd have something to measure against later. First pass: a shallow clone covering the last ten days, ninety commits. I nearly wrote that number down as the baseline.

Then I re-ran the same query against the full, unshallowed history over a fixed window — May 24 to August 22 — and got 323. Not ninety. The difference wasn't noise, it was a shallow clone quietly lying about how much history it actually held, plus a relative date range (--since="90 days ago") that would have returned a different number every day I ran it, making the baseline unfalsifiable by design. The fix was boring: pin absolute dates, write down the exact command, and don't trust a number you can't reproduce. It's the least exciting fact in this whole post and probably the one I trust most, precisely because it's the one that caught itself being wrong.

What thirteen days actually produced

Here is the part I couldn't write on day one.

Across the five repos, since the fleet started on August 23: 188 merged pull requests, 134 of them in the trailing week. Ninety-six in the main product repo, forty-seven in the workspace that coordinates the fleet, thirty-three in the enrichment service, the rest scattered. On the coordination side, 141 work items closed, 33 still open.

The number I would have told you before I checked was "nearly a hundred." I was off by half, about my own work, over a fortnight, while running the system whose entire purpose is to keep track of it. I'm including that because it's the same failure as the baseline I got wrong on day one, and it rhymes in a way I don't love: the count you carry in your head is not a measurement. Every figure in this post came out of a command I can re-run, and the one time I trusted memory instead, memory was wrong by 88 pull requests.

Twenty new customers signed up in the same fortnight.

I'm not going to tell you the fleet did that. I have no cohort, no counterfactual, and two weeks in which roughly fifteen other things also changed. What I have is adjacency, and adjacency is what everyone else writing this genre of post quietly sells you as causation. The honest version: the number is real, the mechanism is real, and the line between them is still unmeasured. Ask me again when I can show you a cohort.

The thing that actually limited output

If you'd asked me on day one what would cap this system's throughput, I'd have said model capability, or the concurrency limit, or my own review time. It was none of those. It was whether the system could read its own reasons for being stuck.

Of the 33 open items, 15 are blocked. Five of them wait on a single GitHub issue — ordinary dependency, the kind any tracker handles. Four wait on another item in the queue. The remaining six wait on something that is not a ticket and never will be: an environment that injects AWS credentials it cannot actually use, an API key with no billing behind it, a verification query with no data to return yet because nothing has synced. Each of those six files carries a note, written by the agent that hit the wall, saying in effect: this blocker has no issue number, so I am inventing a name for it.

That turned out to matter more than any capability question, for a dull mechanical reason. One item had its blocker recorded correctly — in a prose comment, one line above the field the scheduler actually reads. So the scheduler kept picking the item up, kept dispatching it, and it kept failing the same way, at full session rates, for days. And when I finally audited the whole blocked list, most of the blockers had already cleared; nothing was watching for the condition to lift, so "blocked" had quietly become a one-way door and my queue had been turning into an archive.

The fix in both cases was the same shape, and it isn't clever: make the condition a parsed field rather than a sentence, let that field name a state of the world and not just a ticket, and have something re-check it on a schedule. A rule that lives in a document gets worked around at 2am. A rule that fails a test does not.

That's the thirty-times-agent-hours target from the design document, met by an answer I didn't expect. The hours were never the constraint. Legibility was.

What this still hasn't proven

The 30x figure in the design doc is an input — hours of agent time applied, up from roughly six a week. It was never a promise of thirty times the output, and the document says so in writing. Thirteen days in I can tell you the hours got applied and that 188 PRs came out the other side. I cannot yet tell you how much of that work was worth doing, which is a different and much harder question, and the one I'd actually want answered before recommending any of this to anyone.

So: the mechanism exists, it's cheaper to run correctly than I expected, one undocumented platform limit shaped more of the architecture than any decision I made on purpose, and the ceiling I hit was bookkeeping rather than intelligence. Whether it's worth ten times what three agents in one repo were worth — I'm closer to knowing than I was, and still not there. Ask me after a quarter.