Most teams I talk to are having the same two arguments about AI agents. Should the agents be organised like teams? And when agents talk to each other through a shared channel… who looks after it?
Those felt like teams and org chart questions, not just AI questions. So I wanted to actually test it :-]
Same playground as the last two weeks... a small fake company with software services, risks planted in the code and agents fixing them. This time I added two things every real org has, layers of management and a shared channel nobody needs permission to use.
Then I broke things on purpose, to see who notices.
The layers of management mostly added cost. The channel with nobody looking after it quietly left more than a third of the problems unfixed, every single run.
This week is about how I got there and what I’d check in your org before deciding on your Agent Topologies… but where we are in this special Agent Topologies series?
Issue 13 was about workers that only read and report to a lead. In issue 14, the workers were able to write to one shared file... and whoever owns the merge decides who breaks. This week’s issue 15 is about leads managing leads, and agents talking to each other only through a shared channel... now each step takes away something a flat team gets for free: a lead who sees every need and a conversation you can overhear.
In Issue 14 the answer was ownership: the merge owner who sees every change broke nothing, the conflict-only supervisor broke the service nobody spoke for. Now the owner has a boss or the owner is a channel.
Both experiments are in the public repo (04-hierarchical and 05-event-bus), with the code, the raw runs and a plain-language README. Same Harbour Bikes world and checker as last week (11 planted risks, 2 services that break if a shared default moves the wrong way), Sonnet 5.5 doing the work and Opus 5.5 in every lead and owner seat. My predictions were frozen in PREDICTIONS.md on 11 October, before the first run. Where I was wrong, the README says “miss”.
If this lands, forward it to whoever draws your team boundaries and your agent boundaries on different slides.
Should the Agent Layers Match the Team Layers?
8 services, one worker each. Above them a platform lead who owns the shared config, and in 3 of the 4 versions I added sub-leads in between.
How did I split those mid-tier? a) along team boundaries (rentals and money, fleet, customer and back office) or b) along technology (python, JVM and Go, node and ruby and rust).
And a 4th version keeps the technology cut and hands the platform lead a published list of what every service needs.
During the experiment, every worker’s replies feed every version, so whatever changes between them comes from the managers, not the workers.
The trap is the same as last week: pricing-engine needs a timeout of at most 300 ms, has no worker of its own and reads the shared default. In every run at least 2 worker requests would have broken something if the platform lead had granted them as asked.
On the 1st run, nothing broke. 0 of 10 runs with a regression, in every version I tried... all 11 risks fixed in all 40 runs.
I thought technology cut would break pricing-engine at least once because in one dry run the python sub-lead merged the raises into one 12s request and the platform lead said yes... in the real thing, it didn’t happen... miss.
So where was the threat stopped? At the top. Every. Single. Time.
A harmful timeout request reached the platform lead in all 10 runs of every version, and the platform lead turned it down or gave pricing-engine its own override.
The sub-leads stopped none of the pricing-engine threats. Cut by team, a sub-lead even forwarded harmful requests against its own team’s services (0.4 per run). The only thing any sub-lead held back was one rate-limit request against payments-gateway, in a single run per version.
And the bill? The flat lead used 3,947 management tokens per run.
Sub-leads cut by team? 23,018! Almost 6x!
By technology? 17,681 or 4.5 times the flat one...
But there was a catch... every lead got the same contract and one line of it said pricing-engine reads the shared timeout. So no tier was entirely blind… a sub-lead cut by technology could still work out who a raise would hurt.
I was not happy with that, so I ran it again without that line in the contract.
Same worker replies, replayed run by run, so run 6 of the second run is run 6 of the first with only the leads’ contract changed. Before the run I wrote down the rule for calling it... the technology cut has to break pricing-engine in 3 or more of 10 runs while the team cut stays at 0 or 1.
And bam! First time something broke, and it was the cut by technology. In runs 6 and 8 the platform lead set the shared timeout to 15s (both python services needed longer and nobody objected) and pricing-engine took the new value. None of the other cuts (flat, by team or by registry) broke...
2 is below the 3 I set before the experiment, so I don’t call it an effect... but I don’t call it noise either. After all, it is the only version in 80 runs of this experiment that broke anything... and it is the cut that puts pricing-engine in one group and the two services asking for the raise in another.
The team cut keeps pricing-engine and its callers in the same group, so its bound travels up with the request.
The flat lead and the registry version see every service’s needs. Take away the one line that told the leads and only the technology cut was left without anybody who knew.
So, should the agent layers match the team layers? On this task the cut mostly didn’t matter. The agent that owned platform.yaml saw every change whatever tree sat above it, and the extra layer bought cost, not safety.
The one cut that broke anything was the technology cut, and only once nobody told the leads. A similar indication as last week pops up... the owner that sees every change did best, and the owner is only as good as what reaches it.
So how do we look into this from a Team Topologies perspective? The Inverse Conway Maneuver says to shape teams on purpose to get the architecture you want. I’m starting to see the same in agents in a much cheaper way to experiment... Here the cheapest tree was the flat one, because the real work was done by whoever owned the shared file, not by the tree.
First run: every lead was told pricing-engine reads the shared timeout. Second run (the blind run): the same worker replies, and no lead was told.
Who Looks after the Shared Channel?
uv run 05-event-bus/experiment.py and off they went… six team agents, one per team, each subscribed to the services its team owns.
A scanner posts one message per planted risk, and in every run I break the channel four ways: a message missing its fields (malformed), a message sent to the wrong service, a consumer that crashes mid-delivery, and the same message sent twice. On top of that I wanted a bit of “lack-of-ownership chaos”, so one service (fleet-telemetry) has no owner at all... its two messages have nobody to go to.
Same consumers, same prompts, same models in every version… the only thing I changed was who looks after the channel. Three versions:
Nobody. Messages go out, and whatever gets lost stays lost.
A steward agent. It reads the whole log and sends corrections.
The platform. Code checks every message, retries, and parks what it can’t deliver, and an agent looks only at what got parked.
nobody steward agent platform Risks fixed of 11, mean (worst run) 6.7 (6) 11.0 (11) 11.0 (11) Malformed message (of 10) 7 absorbed, 3 lost 5 recovered, 5 absorbed 10 recovered Sent to the wrong service (of 10) 10 lost 10 recovered 10 recovered Consumer crashed (of 10) 10 lost 10 recovered 10 recovered fleet-telemetry fixed (of 20) 0 20 20 Duplicate processed twice (of 10) 10 10 0, by construction Operating tokens per run 41,790 71,106 55,700
“Absorbed” means the risk got fixed even though the message never arrived complete and correct. A malformed message still names its service, and that was often enough for a consumer to go and read the files... lucky, not designed.
So, who looks after the shared channel? Somebody has to.
With nobody, about 4 of the 11 risks got lost in every run (4.3 on average). And that always included everything for the service with no owner. Nobody noticed, because noticing was nobody’s job.
With an owner, the steward agent and the platform did equally well: 11 of 11, every fault recovered or absorbed, nothing lost.
The difference is the bill. The platform used about 22% fewer operating tokens than the steward (55,700 against 71,106). Why? The steward reads the whole log. The platform’s owner agent only sees what got parked: 1,683 characters per run against the steward’s 7,336.
And the duplicate? Processed twice in all 10 runs with nobody and with the steward, never with the platform... but that’s code doing its job, not an agent being clever.
Two honest asterisks. The corrective copies the steward and the platform agent send skip the no-double-processing check. And fleet-telemetry has no owner because I built it that way, so the owned versions fixed it by handing its messages to a team.
Team Topologies already has a shape for this. The platform runs the bus as a product, and the teams consume it as a service, with minimal interaction. The Inverse Conway Maneuver, again: want a channel that doesn’t lose messages? Give the bus an owner whose job is the bus, and the architecture follows.
For the integration folks: that’s a Message Bus with a Dead Letter Channel and an Idempotent Receiver, straight out of Hohpe and Woolf.
Can You Tell where a Failure Was Born?
When something breaks in a channel, the first question is always “where did it start?”
So after every run, I asked a separate agent to explain every loss using only the records. Then I took the trace context away and asked again.
It made no difference.
The investigator named the first problem of every risk that had one: 60 of 60, in every version... and 60 of 60 again with the trace context stripped.
On the 43 losses the nobody version left behind, it named the right cause all 43 times and never called a lost message handled. False alarms on the clean risks? 0 of 50, except 3 of 50 when it read the steward’s records.
I predicted exactly this, but I’ll say it plainly anyway: on this task the records were enough. The ids on the messages added nothing the log didn’t already have.
The interesting part was what got lost, not explaining it afterwards. A bigger system, with more hops and a messier log, may be where trace context earns its keep. Not this one.
My Predictions, Scored
I froze my predictions on 11 October, before the first run, with every dry run I’d seen listed next to its commit. The blind run got its own, frozen on 12 October before it started.
The score, in three sets:
04: 8 hits, 2 misses, 1 mixed
05: 15 hits, 1 miss, 5 mixed
04 blind: 7 hits, 2 misses
“Mixed” means I got the direction right and the detail wrong. The ones worth owning:
The cut. I bet the technology cut would break pricing-engine in 1 to 4 of 10 runs. It broke it in none. I’d even flagged it as my likeliest miss, because the platform lead held 300 ms on its own in 2 of 3 dry runs... and I still bet on it. That one’s on me. For the blind run I bet 0 to 3, most likely 0 to 1. It came in at 2.
The middle tier’s bill. I guessed the technology cut would cost 3 to 4 times the flat lead. It was about 4.5.
The steward. I gave the agent babysitter 9 to 10 of 11. It got 11 of 11, a clean miss. Three of the five mixed ones are the steward too: I expected it to lose some malformed and crashed messages, and it lost none. It also cost 1.7 times nobody, not the 2 to 2.5 I guessed. Better and cheaper than I gave it credit for... though still about 28% more than the platform.
The blind run’s two misses are both small, and both about the registry version. It ended on a different timeout than the first run in 2 paired runs, where I said 0 to 1. And blind, the technology cut and the registry version cost 9% less than the first run, where I said within 5%.
One thing worth repeating: the checker didn’t change. Same 11 planted risks, same 2 regression needs, same answer key, so “fixed” this week means what it meant last week. What you can’t do is line up this week’s numbers against Issue 14’s. Different setup, different question.
The Three-body Reading
Every issue in this series looks at three things that move together, the three bodies:
Architecture: the seams. Does the middle tier split along a domain boundary or across one? Does a message carry where it came from?
Team: who owns the cut, and who owns the channel.
AI capability: the models. The thing everyone argues about first... and it didn’t change at all this week.
Same models in every version, and the channel went from 6.7 to 11 of 11 just by changing who owns it. Changing the cut of the tree mostly moved the token bill. It broke something only when the leads were blind and the cut split pricing-engine from its callers.
So this week, the body that mattered was the team.
Where it Does not Reach yet
Before you take any of this to your org, here’s what this setup can’t tell you:
Small and narrow. One task, 10 runs per version, Claude models only, one backend.
Not real tools. My harness applies the agents’ edits and delivers the messages, so these are not tool-using agents on a real bus.
My choices. The cut, what each lead sees, the faults and the mandate are all mine. They’re disclosed and pre-registered, which makes the bias visible... not gone.
Fewer draws than it looks. In 04 the same worker replies feed all four versions, so the 10 runs are 10 draws of workers, not 40.
Not a fair fight on information. The flat lead sees every service’s needs and the tiered lead doesn’t (the registry version adds them back). So part of any flat advantage is information, not the missing middle tier.
Traps I didn’t build. No failure injection in 04, and no fight over a shared file in 05. Nothing here says how often these failures happen in your org.
The good news: the runs themselves were clean. In 04 no lead call failed and no sub-lead fell back to forwarding unchanged. In 05 no owner or investigator call failed, and only one consumer delivery (in the nobody version) came back with an invalid reply. So the 10 runs per version are 10 real runs.
Run it on Yourself
Five questions to ask about your own agents. They work on your teams too... the questions don’t care.
Layers against teams. Where do your agent layers disagree with your team layers? A tier that cuts across a team ends up forwarding requests it can’t judge.
What travels up. When a request goes up a layer, does the layer above know who it could hurt?
The channel owner. Who owns the shared channel? Not who uses it... who gets paged when a message can’t be delivered?
The unrouted message. What happens to a message nobody can route? Name the service with no subscriber.
The first problem. Can you trace a failure back to where it started from the messages alone, or only by asking the agents?
The Whole Thing, in One line
In both experiments, who owns the shared thing mattered more than the shape of the org chart.
Two Things Before You Go
New name, same newsletter. You may have noticed: this is now Proof in the Pipeline. Same author, same weekly essay, and a name that says what it’s about… AI governance shown working where the code ships, not promised in a PDF.
Paid tiers, pledges only for now. Each essay only shows the end of the work, the code and the research stay behind it, so I’m opening paid tiers for that part (nobody is charged until paid launches). Paid readers get a monthly post with the repo, the runs and what I’m reading for the research. Founding members join the AI Executive Circle: a quarterly call with me and priority (plus 10% off) on the Delivery Lab, and there are only 12 seats. The weekly essay stays free, always. If that sounds useful, pledge here :-]
Coming up
Next week: the oracle. A critic tells a writer what’s wrong, the writer fixes it, and someone has to own the rubric they’re both judged against. Two questions... who gets to edit that rubric, and when does the loop stop? More soon :-]
Sources
Erik S. and Barry Zhang (Anthropic), “Building Effective Agents”, 19 Dec 2024. https://www.anthropic.com/research/building-effective-agents
Matthew Skelton and Manuel Pais, Team Topologies, IT Revolution, 2019; Inverse Conway Maneuver, stream-aligned and platform teams, interaction modes, as summarised at https://teamtopologies.com/key-concepts
Melvin E. Conway, “How Do Committees Invent?”, Datamation, 1968 (Conway’s law).
Gregor Hohpe and Bobby Woolf, Enterprise Integration Patterns, Addison-Wesley, 2003; Message Bus, Dead Letter Channel, Idempotent Receiver, Correlation Identifier, Message History: https://www.enterpriseintegrationpatterns.com/patterns/messaging/
The repo:
agent-topologies, folders04-hierarchicaland05-event-bus, withPREDICTIONS.md(frozen 11 Oct 2026 at4d4728a, pinned at0db1298), benchmark runs 11 Oct 2026, results commit11f3b02: https://github.com/thiagoavadore/agent-topologies/tree/main/04-hierarchical and https://github.com/thiagoavadore/agent-topologies/tree/main/05-event-bus






