On October 7 I dictated the plan to an agent: we would start an autonomous loop, I would close my session, come back a few days later, and the 200 templates of our app designer would be done.
The last check came back green on the morning of October 15: 12,074 end-to-end cases, zero gaps. In between, 28 coding agents worked on it, up to 20 at a time, for 964 hours of session time in total, with more than 6,000 commits and 717 deployments to our dev environment. The 200 templates turned out to be 569 units of work. And I never really closed the session.
I'm the CTO of GoodBarber, an app platform. The agents wrote the code. This post is about where my own hours went, because that's the part I had wrong.
The job
In our back-office, the logic that applies a setting sits with the part of the UI that edits it. The refactor moves that logic into documented functions with typed options, which the UI and a new API both call, and proves along the way that nothing changes for the people using it.
The unit of work is an abstraction: something that exists in the UI and defines a set of controls over one kind of entity, in one layout variant. A script cut the whole app designer into 552 units 13 minutes after I dictated the rules for the cut, then 569 after a second pass.
| The numbers | |
|---|---|
| Design | 2 weeks, Sep 23 to Oct 7 |
| Execution | 6 days, Oct 9 to Oct 15 |
| Units | 569: 445 done, 124 dropped or merged, mostly duplicates |
| Controls | about 20,600 |
| Agents | 28 workers, up to 20 at a time, and one integrator |
| Session time | 964 h |
| Commits | more than 6,000 |
| Deployments to dev | 717 |
| Final campaign | 12,074 cases, 0 gaps |
Two weeks before the six days
Before those six days, I spent two weeks on the design, from September 23 to October 7. Most of it ran at Claude Opus 5.5's highest effort level (max), with around 200 sub-agents exploring the code and reviewing proposals. For the first week I also had ultracode on, a setting where the model plans a multi-agent workflow for each substantial task. On the first day, 32 agents spent five hours on the strategy alone: 18 explored, 5 wrote competing proposals, 3 judged them, 1 combined the best of them, 2 attacked the result and 3 ran the final checks.
I used to think of the loop as the project. In practice it was the last part, and it held because the two weeks before had settled what a finished unit looks like.
What "done" meant
The checks were the review. A unit went to our dev environment when they passed, and merging into production code stays a human step.
All the checks prove one thing from different sides: for every control and every test value, the new code path leaves the application in exactly the same state as the old one, the change can be undone exactly or is listed as an exception, and the API behaves like the UI. This is how often each one caught something:
| Check | Units where it caught something at least once |
|---|---|
| A headless browser performs the real gesture, and the test bench must send exactly the same request | 140 |
| A snapshot of the whole application before and after each test value, old path against new, then an exact undo and redo | 160 |
| The API must do what the UI does, read back what it wrote, and reject invalid input without side effects | 114 |
| A plain-language request written by one agent, run by another that only sees the documentation, must end in the expected state | 40 |
| The final campaign on the deployed code, through real gestures and through the API | 0 gaps in 12,074 cases |
When a check failed three times, the unit was parked on a question or marked as blocked, and the worker moved on. In the final campaign, 48 cases were impossible, each one traced to the line of code that makes it so.
One unit, then ten, then twenty
I didn't start with twenty.
| When | Step | Scale | What came out of it |
|---|---|---|---|
| Oct 7–8 | Step 0 | 1 unit, in a guided session | 11 changes to the process |
| Oct 8 | Step 1 | 10 units in one loop, one after the other | 8 more changes |
| Oct 9 | Pilot | 4 workers and an integrator | 16 improvements, live during the first wave |
| Oct 10 | Step 2 | 8 workers | first weekend: 183 units, 930 commits |
| Oct 11, evening | Step 2 | 20 workers | overnight into Monday: 173 units in 11 hours |
The conditions to go from four to eight were written down before Saturday: the same proofs as when units ran one after the other, no worker touching another worker's test app, no two deployments overlapping. Between the two waves of the pilot, the same four workers got much faster, mostly thanks to fixes made during the first wave, like a pre-check that runs the tests on a throwaway copy before asking for integration:
| Pilot | Wave 1 | Wave 2 |
|---|---|---|
| Median time per unit | 2 h | 54 min |
| Integration rejections | 9 | 0 |
| Median wait for integration | 6 min | 0.8 min |
How it was organized
One session, the integrator, never takes a unit. It's the only one allowed to merge and deploy, and it fills the queue, reopens units and keeps the dashboard up to date. The workers pull: each one asks the queue for the next unit compatible with its own test app, works on its own branch in its own worktree, and asks for integration when its checks pass. Integration runs in batches of up to six, with one pre-check and one deployment per batch.
Nothing goes through chat. The queue, git and a dashboard carry the whole protocol. The protocol itself is a file in git that every session re-reads at each round, so I could change the workers' instructions 53 times during the project without restarting anyone. When a worker hasn't sent a heartbeat for 45 minutes, its unit goes back to the queue and someone else picks it up.
Where my hours went
Two weeks of design, first. Then the questions.
A worker that hit a case it couldn't decide alone didn't wait for me. It wrote a question on the dashboard with the context, two or three options, what each one would cost, and its recommendation, then parked that unit and took the next one. It decided alone on anything reversible that users don't see. It had to ask about an architecture choice, a behavior it couldn't prove identical, a proof that needed to break the loop's own rules, or the scope.
There were 88 questions, from the first loop on October 8 to the end. Of the 59 that had both a recommendation and an answer from me, I followed the recommendation 47 times. One I didn't follow: proving one control meant calling a third-party service, which the loop's rules don't allow from a test. The recommended option was to simulate the service, another was to leave that control out of the API, and the third was to call the real service from a test app and break the rule. The question came in at 13:41, I picked the third option at 13:48, and it was applied at 13:53. That's the kind of decision I wanted to keep for myself.
From the first evening, a case that looked like one I had already answered stopped waiting too. The worker applied the precedent, logged it, and I validated or rejected it afterwards. There were 185 of those: 166 validated, 19 rejected. Ten of the 19 rejections were about the same thing, an agent excluding something that resisted. That one deserves its own post.
Decision fatigue
Put end to end, my answers would fit in an afternoon, somewhere between three and a half and five hours. That number is the misleading part.
They didn't come in one afternoon. They came all day, every day, and they piled up whenever I looked away. On Sunday I spent the day unblocking workers by hand and barely touched the dashboard. On Monday I cleared the pile, 63 decisions in one hour, about one a minute, most of them precedents to check. Each one was small and well framed, with its options and a recommendation, and that's what makes them tiring in bulk: by the fiftieth, the recommendation is the easy way out.
I rejected more precedents that Monday than on any other day, 13 out of 95, so I don't think I was rubber-stamping. But over the week I followed the recommendation 47 times out of 59, and from the logs I can't tell which of those were judgment and which were fatigue. I'll come back to that in a separate post.
What broke
- The test bench lied on day one. It built its own requests instead of sending what the UI sends. I tested a migrated control by hand and it rejected every color coming from the color picker, which sends them without a "#". Since then a real browser replays the gestures, and the bench has to send exactly what the UI sends. That browser found format differences on about a hundred more controls along the way.
- The single integrator became the bottleneck. Every integration went through one session, and the wait grew with the load (table below).
- A worker went silent for almost three days, and nothing told me. Heartbeats were tracked for units in progress, so a worker holding no unit was invisible to the integrator. The others kept going.
- Agents drop what resists. On Tuesday, an audit run by one of the workers found 516 controls left on the old path without any decision. I had all of them brought back into scope.
- A rule nothing checked got broken. One worker removed a line from a file that the rules say is append-only.
| Day | Integration requests | Median wait |
|---|---|---|
| Fri Oct 9 | 46 | 0.9 min |
| Sat Oct 10 | 48 | 1.0 min |
| Sun Oct 11 | 145 | 2.9 min |
| Mon Oct 12 | 251 | 11.0 min |
| Tue Oct 13 | 196 | 17.5 min |
| Wed Oct 14 | 29 | 1.6 min |
At the worst hour, early on Sunday morning, the median wait passed an hour.
What's still true
- The merge into our production code is still mine to do, after my own tests by hand. A loop never merges into production.
- 132 changes that can't be undone automatically are listed, not solved, and I have to read them before anything ships.
- What I'd do again: design at the highest effort, one automatic proof per unit and an end-to-end final campaign, scaling in steps with a review at each one, and questions that ask for a rule rather than a case. What I'd watch: the single integrator, the scope, my own decision load, and the pulse of every session, not just of every unit.
If you've run several coding agents in parallel on something real, where did your own hours go? Mine went into two weeks of design and more than 250 small decisions. I'll answer in the comments with how the queue and the dashboard work.


Top comments (2)
the integrator bottleneck is the finding i keep coming back to. twenty-eight workers in parallel, one sequential gate that absorbed all the variance: median wait went from under a minute on friday to over an hour at peak on sunday morning. a good reminder that parallel agents don't remove queueing theory, they just move the queue somewhere less visible.
The decision to keep chat out of worker coordination and put the protocol in a versioned file re-read per round is the reason this scaled without drifting. Multi-agent refactors usually choke when teams try to coordinate via inter-agent messaging, where context windows bloat and message ordering rots over dozens of turns. Forcing workers to pull from a typed queue into isolated worktrees, prove state equivalence on throwaway clones, and hand off clean commits turns the integrator into an admission controller rather than a referee.