This is a follow-on to Set It and Ship It: How I Let AI Agents Build My Java Services While I Sleep -start there if you haven't.
Last time, the whole thing came down to a setup I still run every day: a builder agent and a separate critic, working one service at a time against requirements written tightly enough that a machine could grade them. It works, and I wasn't planning on a sequel.
Then I tried to scale it, and something broke. It wasn't the loop - the loop held up fine. The problem was everything happening between the loops, which, it turned out, I'd never really thought about.
Parallel isn't the same as connected
That first setup once ran three agents at once - a reconciliation service, a Kafka consumer, a cache - and by morning I had three clean reports. What I skipped over, mostly because I hadn't clocked it myself, is why that worked: none of those three tasks touched the others. Three strangers in three separate rooms, basically.
Most real work isn't like that. Sooner or later one agent needs a contract that doesn't exist yet because the agent writing it is still going. Or two of them open the same file and the second one quietly paves over the first. Every loop passes its own gate and the feature is still broken, because each gate only ever looks inward, at its own little job.
A refund flow, and where it fell apart
Let me make this concrete with an engineer I'll call Loknath - really a stand-in for a few good people I've watched hit this same wall.
Loknath has the one-loop workflow down cold, so he reaches for something bigger: a refund flow. It touches a lot of the stack - a schema change to store refunds, an API endpoint to kick one off, auth so not just anyone can, and the actual write against the ledger. Same move as before. Four requirement lists, four agents, into the always-on box overnight.
He comes back to a mess. The API agent had built its endpoint against a refunds table the data agent hadn't shipped yet, so half of it was wired to a schema that moved underneath it. Two agents had both been editing the ledger module. And one of them, doing its honest best to satisfy "trigger a refund," had gone and issued a real refund against a test account, just to prove the path worked end to end. Four green reports. One broken feature, and one transaction nobody could take back.
Here's what stuck with me: none of that was a bad loop. Every agent did solid work inside its own room. What went wrong was that nobody had decided who owned what, who was allowed to talk to whom, or which step needed a person to look at it first.
Loknath hadn't been running workers. He'd been running an organization, and no one had drawn the org chart.
The rung above the loop
There's a ladder people talk about that helps here. A prompt controls a single response. Context controls what the model sees. A loop controls one agent's cycle of doing and checking its own work. My first post lived entirely on that loop rung.
The rung above it is the topology - which agents exist, what each one owns, who's allowed to talk to whom, how the work moves through them. Not one loop running well, but a bunch of them wired together on purpose. And if you don't wire it on purpose, it still gets wired; it just takes the shape of whatever order you happened to launch things in.
Give every agent a mandate
The thing that helped Loknath most was to stop launching anonymous agents at "the repo" and start handing each one a mandate - one narrow thing it owns, which quietly defines the much larger set of things it has no business touching.
security-agent owns auth, permissions, audit logs
data-agent owns schema, migrations
api-agent owns endpoints, request/response contracts
An agent with no mandate is basically an intern with commit access to prod and a lot of enthusiasm. It'll help everywhere, including the places you didn't want helped. Once the lines are drawn, the API agent that needs the refunds table can't just conjure one up - that's the data agent's turf, so the request has to cross an edge and wait its turn. The "who talks to whom" question I couldn't answer earlier stops being a question, because ownership went and answered it. It's the same fix testable requirements gave me inside a single loop, just one floor up.
The one edge where you put a human
In the first post I was pretty adamant about turning the permission prompts off, and I still am - asking a human to approve every step is how you turn an overnight run back into a full-time babysitting job.
Scaling up taught me the more careful version of that rule. Not zero gates, but zero gates in the boring places and one real gate in the place that counts. The edges in a graph aren't equal. Most of them carry cheap, reversible stuff. A few carry the things you can't undo - the payment, the migration, the deploy - and those tend to sit right where one agent hands off to the next.
data-agent ──► api-agent ──► [ refund write ] ◄── human approves here
(auto) (auto) (gated)
That's the exact spot Loknath's phantom refund would have died. One approval on the irreversible edge, hands off everywhere else. You've got one interruption to spend - spend it there.
"The graph did it" is not an audit answer
Getting it to work is half the job. Being able to see what happened afterward is the other half, and I underrated it badly until the first time something broke and I couldn't tell which agent had done it.
- Give each agent its own identity. When five of them act as the same account, "who did this" has no answer, and you find that out at the worst possible moment.
- Decide which agent can reach which tool, on purpose. Saying the frontend agent can't touch payments is dull work, and it's most of your safety.
- Tag every request with the graph, the run, and the node. That's how you hold what actually happened up against what you meant to happen, and the space between those two is where the real bugs live.
- Budget each agent, not just the project. Graphs fan out, and the token cost I flagged last time doesn't quietly add up here so much as multiply.
The ways this goes wrong
Nearly every failure I've seen comes back to a handful of things. The topology was never designed, so it's just whatever fell out of the launch order. Everything shares one identity, so there's nothing to grab when it breaks. Fan-out and retries run the bill up without anyone noticing. A bad instruction slips into one agent and rides the edges straight into the next. Or there's simply no gate on the one step you'd have most wanted to catch.
What the bottleneck becomes
The first post moved my bottleneck from writing code to writing contracts. This one moved it again - from writing a contract to designing an organization: who exists, what they own, where the boundaries sit, and which single edge out of fifty is worth a person's attention. If you've ever watched a team go from three people to thirty, none of this will feel new. It's an old problem in different clothes, and about the only thing that's really changed is that the org I'm designing now is made of agents.
The usual disclaimer, and it matters more here than it did last time. Everything above is what's worked for me, and none of it is a promise - the more agents you wire together, the more ways there are for the arrangement itself to be the thing that's wrong. Watch the cost especially: a graph multiplies token usage in ways a single loop never did. Give each agent a scoped identity and scoped tools, meter every one of them, cap the whole run, and keep a human on the edges you can't undo. Start with two connected agents before you try ten. The structure lowers the risk; it doesn't erase it.
Top comments (0)