The Number of Agents Is a Cost, Not a Capability
Two pieces ago I argued that the decisions you don't write down become debt. Last week, that a boundary you don't enforce is just a wish. Both are one idea in different clothes: complexity you don't govern doesn't disappear — it compounds.
This week it walked up to me wearing yet another costume.
A post about AI orchestration crossed my feed — a good one, built on the image of an orchestra: dozens of specialized agents, and a conductor to turn them into a symphony instead of noise. Elegant. It also smuggles in an assumption that costs real money — that the answer to a hard problem is more musicians.
I know that assumption well. I paid its bill once, and it took me the better part of a decade to pay it off.
The architecture I was asked to build
Early in my years as a technical architect for a large retailer, I was asked to lay the foundations of a new front-end platform — and, explicitly, to split it into separately-owned NPM modules: a build toolchain, a core of shared interfaces and abstract classes, an auth layer, an Angular ui-kit, a common layer for logging and notifications, and the apps on top. Each module was to have its own owner — a team — and be consumed by the apps as a versioned dependency.
If the client sounds familiar, it should: this is the same platform whose founding decisions opened this series, two pieces ago. This is what those foundations became.
On paper it's a clean diagram: clear boundaries, clear ownership, everything decoupled. I was never fully convinced, but the boxes looked right, and boxes that look right are persuasive.
At its peak the structure spanned twelve teams across two continents. It stood for nine years.
The bill arrives at change time
Here's what a diagram never shows you: decomposition looks free when you draw it. The bill arrives every time something has to change across the seams.
The most expensive line item was routine. Every time Angular or Angular Material shipped a major version, the upgrade touched every module at once. A framework bump — the kind of thing that should be one coordinated push — became a twelve-team negotiation across release calendars that never lined up.
Then there were the changes that simply got stuck. We had bugs sit open for a year because a shared UI component needed a fix, and the team that owned the ui-kit had no buffer and other priorities. Other teams had the skill to make the change. They didn't have the authorization. Ownership had quietly turned into a veto — and a veto with no cost to the one holding it is just a bottleneck with a name on it.
Underneath it all ran a game of telephone. Business requirements landed on the app teams, the teams closest to the actual need. But they couldn't act alone: they had to translate each requirement into an abstract request, hand it down to a module owner, and wait for a release cycle that ran on a different clock. Context leaked at every handoff. The people who understood the requirement weren't the people allowed to satisfy it.
None of this was any one team's fault. Everyone was competent and busy. The structure was the problem — and the structure was the decomposition itself.
Now say "agent" instead of "module"
Swap "NPM module owned by another team" for "autonomous agent". Same bill, new denomination.
Every seam between separately-owned units is a place where cost accrues, and today's multi-agent enthusiasm pays it in three currencies:
- Tokens — two agents talking is two context windows to fill, every turn. The context one loop establishes once gets re-passed and re-reasoned at each handoff. A fleet doesn't share a brain; it photocopies one, repeatedly.
- Latency — a chain of agents is a chain of round-trips: the same mismatched-release-cycle tax I paid for nine years, now measured in seconds instead of sprints, but structurally identical.
- Misalignment — the expensive one. Each agent decides on partial context. Agent A resolves an ambiguity one way; Agent B, which saw only A's output and never its reasoning, resolves it another. That is my game of telephone, compiled. No single agent is wrong; the system just quietly disagrees with itself — confidently, at scale.
"Concatenation" is just a pipeline
The orchestration post leaned on a word that's everywhere now: concatenation. Each agent's output becomes the next one's verified input; the whole chain replays from end to end. Traceable, reconstructable.
That's a good property. It's also the definition of a deterministic pipeline — something we've known how to build for decades, and which needs exactly zero autonomous agents to work. If the steps are fixed and the order is known, you don't have a multi-agent system. You have a workflow with good logging, and you should build it as one.
Orchestration is distributed systems in a nicer outfit
The orchestra metaphor hides the part that actually hurt. The moment your agents act asynchronously and depend on one another, you haven't built an orchestra — you've built a distributed system, and inherited every problem we've spent decades learning to respect: partial failure, retries, idempotency, message ordering, eventual consistency.
An agent calls a payment API. It times out. The agent retries. The payment goes through twice. That's not an AI problem you fix with a smarter model; it's a distributed-systems problem you fix with idempotency and transaction design. The conductor doesn't make coordination disappear. The conductor is the coordination problem, handed a baton.
When a second agent actually earns its place
None of this means "always one agent." It means a second one has to earn its cost, and the honest test is short. Reach for another agent only when a subtask is:
- Genuinely independent — it runs in parallel without waiting on the others, so you're buying wall-clock, not just spending it.
- Context-isolated — it needs its own working memory, and folding it into the main loop would pollute both.
- Differently privileged — it needs tools or permissions the main agent should never hold.
- Bigger than one context window — the work genuinely doesn't fit.
Breadth-first research, map-reduce over a large corpus, a step that needs credentials the main loop must never see — those pay for themselves. "It felt more modular" and "it mirrors our org chart" do not. That last one is exactly the mistake I helped build: an architecture shaped like the org, not like the problem.
How the story ended
It took years to unwind, but the modules eventually collapsed into a single, well-governed Nx monorepo. Notice what did not happen: I didn't throw the boundaries away. core, auth, ui-kit still exist — as projects inside one repo, sharing a single release.
What went away was the autonomy: separate owners, separate release calendars, authorization as a gate. A change to the ui-kit is now reviewed by whoever knows it best — not blocked because they aren't the one team allowed to touch it. An Angular upgrade is one pull request again. The specialization survived; the coordination tax did not.
That's the whole lesson, and it's the same one for agents: keep your concerns separate — don't make them autonomous.
The rule I'd leave you with
Decisions you don't write down become debt. Boundaries you don't enforce become wishes. And units you make autonomous without a reason — modules, services, agents — become a distributed system you never meant to build, and a coordination bill you pay at every change for as long as it stands.
The number of agents is a cost, not a capability. The best conductor is the one who keeps the orchestra small.
Before you split a problem across a fleet of agents, ask whether you actually have a fleet of independent problems — or one problem and a pipeline you haven't written down yet.
Where in your system are you paying for autonomy you never needed?