Codex vs Claude

Parallel Agents, Serial Reviewer: The Bottleneck Did Not Move

David Guzenburg/ / 11 min read

The dashboard shows four active sessions. It does not show the one person who has to read all four branches.

parallelismorchestrationreview processmeasurement

Parallelism multiplies production, not absorption

Running several agents at once is the most immediately compelling thing in this whole category. Four branches advancing simultaneously, four tasks you were not going to get to this week, one person nominally directing all of it.

The arithmetic that decides whether this works is not about the agents. It is that every branch has to be reviewed and merged by a person, that reviewing is serial, and that the review rate is a property of the human rather than of the fleet. Adding a fifth agent adds production. It adds nothing to absorption.

This is a well-understood shape in any system with a shared bottleneck, and the reason it catches teams out here is that the constraint is invisible from the side that got faster. The dashboard shows four active sessions. It does not show the reviewer.

The rough arithmetic

Suppose a task takes an agent forty minutes and takes you twenty-five minutes to review properly. Then one reviewer sustains about one and a half concurrent streams. Not four.

Run four and the queue grows by roughly two and a half tasks per cycle. That is not a backlog that stabilises — it grows without bound until something gives, and what gives is the review quality, because the reviewer adapts to the arrival rate rather than the arrival rate adapting to the reviewer.

Put your own numbers in. The exact values matter less than noticing that the sustainable concurrency is a small number, usually between one and three, and that it is set by review time rather than by anything about the agents.

What a growing queue actually costs

Branch rot. Work reviewed a week after it was produced is reviewed against a moved main branch. The rebase is unreviewed work that someone has to do, and conflicts resolved during it are the least scrutinised changes in your repository.

Context switching. Reviewing four unrelated branches in an afternoon means loading four different problems. That cost is real, it is borne entirely by the reviewer, and it does not appear anywhere in the accounting that made parallelism look attractive.

Degraded review. The adaptation nobody chooses. Faced with a queue, reviewers skim, trust the tests, and approve. The work still gets merged; it just stops being reviewed, and there is no moment at which anyone decides this.

The metric that tells you

Track the age of the oldest unreviewed agent branch. Under a day is healthy. Over a week means you are running more concurrency than the team can absorb, and the branches are now getting worse rather than waiting neutrally.

The counterintuitive advice

Run fewer agents. Not as a compromise — as the throughput-maximising choice, because a system operating past its bottleneck delivers less than one operating at it, and delivers it with worse quality.

Two concurrent tasks that get reviewed and merged today deliver more than five that produce a queue. This is the standard work-in-progress limit argument, and it lands awkwardly because reducing concurrency feels like declining free output. The output is not free; it is priced in review, and you have already committed the budget.

Make review cheaper, not generation faster

Once you see the bottleneck, the lever is obvious and it is not the one people pull. Every minute removed from reviewing a task raises sustainable concurrency; every improvement in generation speed raises the queue.

The levers that work, in rough order of effect: smaller scoped tasks, so each diff is small. Machine-checkable done conditions, so the correctness question is settled before review begins. Commits split by concern, so a mechanical rename is not mixed with a behaviour change. A pull request that carries the decisions and the unverified items, so the reviewer is not reconstructing intent. And the diff ranked by the agent's own confidence, so attention goes to the right three files first.

Those are the contents of the article on what an agent's pull request must carry, and the reason to invest in them is exactly this: they are the only things that move the constraint.

Small tasks beat large ones twice over

Worth isolating because it is the highest-leverage habit. A task scoped to one concern produces a diff that reviews in ten minutes rather than forty, which more than triples sustainable concurrency on its own.

It also fails better. A small task that comes back wrong costs a small amount to discard, and its failure is legible — you can see which assumption was wrong. A large one that comes back wrong is a day of work and an argument about which parts are salvageable.

Batch the reviews, do not interleave them

Given a queue, the cheaper way through it is a dedicated block rather than reacting to each branch as it lands. Interleaving means paying the context-switch cost twice per review: once out of your own work, once back into it.

A fixed review window — an hour in the morning, say — also makes the queue depth visible, which the interleaved version hides. If the window is not enough, you learn that on the first day rather than after three weeks of gradual accumulation.

Partition the work or pay in conflicts

Parallel agents editing overlapping files produce conflicts that a human resolves, which is more serial work added to the constrained resource. The mitigation is boring and effective: assign tasks that touch disjoint parts of the repository.

Where that is not possible, sequence the ones that overlap rather than running them together. Two agents refactoring the same module concurrently is a guaranteed conflict, and resolving it requires understanding both changes, which is more expensive than having run them one after the other. The broader mechanics of isolating concurrent sessions are covered in orchestrating parallel agent sessions.

Can an agent review the other agent's work?

Partially, and it does not move the bottleneck as much as you would hope. An agent reviewer is good at the mechanical layer — missing error handling, an unhandled case, a test that does not assert anything, an inconsistency with the surrounding code. Running one before the human sees the branch genuinely removes a category of comment.

What it cannot do is the thing the human is there for: deciding whether this change is the right change for a system whose purpose it does not know. So it reduces review time rather than eliminating a review, and the reduction is real but bounded. Treating it as a replacement produces a pipeline where nothing with judgement ever looks at the code.

Spread the reviewing

If the constraint is one person, the obvious structural fix is more than one person. Agent-authored branches are unusually well-suited to this, because a pull request that carries its own session has no missing context that only the originator holds.

The failure to avoid is the one where a single enthusiast runs five agents and reviews all of it, which is both a bottleneck and a single point of knowledge about what is being merged. Rotating review across the team is slower per branch and considerably better for the codebase.

Measure the whole loop, not the fast part

The number that matters is time from task defined to change merged, including review and rework. Generation time is a component of it and not the interesting one.

Teams that measure only generation conclude that parallelism is a large win, because the part they measured got much faster. Measuring the whole loop frequently shows a smaller improvement, sometimes a regression at high concurrency, and always identifies where the time actually goes — which is the input you need to decide what to fix. The broader case for measuring this honestly is in measuring agent contribution.

What a healthy setup looks like

Two or three concurrent tasks, not eight. Each scoped to one concern and one part of the repository. Each with a machine-checkable done condition, so the correctness question is closed before a human opens the branch. A daily review block rather than reactive interleaving. An agent review pass before the human one. Reviewing spread across more than one person. And the age of the oldest unreviewed branch kept under a day.

That produces less raw output than running the fleet flat out and delivers more merged work, which is the only number that matters. The version that fails is not the one with too few agents; it is the one where nobody noticed that the bottleneck stopped being generation some time ago.

The failure is silent, which is why it persists

Nothing announces that you have crossed the threshold. There is no error, no alert, no moment where the system reports being over capacity. Branches simply take longer to merge, reviews get shorter, and everyone stays busy.

That is what makes the oldest-branch metric worth keeping. It is the only cheap signal that distinguishes a system running at its constraint from one running past it, and both look identical from inside a working day.

The temptation to merge without review

The end state of an unmanaged queue is a policy change nobody proposes: some class of agent work starts going in on a green build alone. Dependency bumps first, then formatting changes, then small fixes.

Some of that may be correct — a well-gated mechanical change with strong tests is a reasonable candidate for automatic merge, and deciding it deliberately is fine. What is not fine is arriving there by attrition, where the policy is set by how tired the reviewer was rather than by an assessment of risk. If you are going to merge some things unreviewed, choose which, write it down, and gate it properly.

The number people should take away

Divide your typical review time by your typical generation time, add one, and that is roughly how many concurrent agents one reviewer sustains. For most teams the answer is under three, and most teams are surprised by that, having built tooling on the assumption that the answer was as large as they wanted.

It is a crude calculation and it is close enough to change decisions, which is all it needs to do.

One last framing that helps when arguing this internally. Nobody would buy a machine that produces parts four times faster than the one inspection station can check them and call the line four times more productive. Written down like that the conclusion is obvious; it is only unobvious when the fast part is new and exciting and the inspection station is a colleague who has always been there.

And be suspicious of any tooling improvement that promises to raise throughput without touching review. There are only two ways to move the number: produce work that is cheaper to check, or find more people to check it. Anything that claims a third way is describing a system in which some work stops being checked, whether or not it says so.

What to say when someone asks for more concurrency

The request usually arrives as an infrastructure question: can we run more sessions, can we raise the limit, can we get another runner. Answering it as an infrastructure question gets you more of the thing that was never scarce.

The useful reply is a number: here is our current review throughput, here is what we are producing, and here is the queue. If the queue is empty, more concurrency is fine. If it is not, more concurrency makes the queue longer and the reviews shorter, and the thing to add is review capacity or a reduction in what each review costs.

That conversation is short, it is grounded, and it moves the discussion to the constraint rather than to the part that is easy to scale.

Takeaway

Running more agents multiplies production and leaves absorption unchanged, because review is serial and set by the human. Do the arithmetic — review time over generation time — and the sustainable concurrency is usually one to three, not eight. Past that the queue grows without bound and the adaptation is silent: reviewers skim and approve. Run fewer agents, and spend the effort on making each review cheaper — small scoped tasks, done conditions settled before review, commits split by concern — because that is the only thing that moves the constraint.

Keep reading
Tooling & Integration

Orchestrating Parallel Agent Sessions Without Corrupting Your Repo

Why two agents in one checkout reliably interfere, three ways to isolate them, how to split work so it stays independent, and why parallelism often just lengthens the review queue.

Codex vs Claude

Plan Mode Is a Cheap Veto, Not a Design Document

The mechanical value of planning before implementation is moving the moment you can say no. What a plan should contain, why the assumptions list matters most, and why an unread plan is worse than no plan at all.

Codex vs Claude

The Reasoning Dial: Spend It Where There Is Something to Search

Extended reasoning is billed as output and defaults to on. Where the depth pays for itself, where it is latency you did not need, why both always-maximum and always-minimum fail, and giving delegated work its own setting.

Codex vs Claude

The Pull Request Has to Carry the Session You Did Not Watch

Review normally leans on the author's priors and signalled uncertainty. Neither exists for unsupervised agent work. What the description must contain, why the not-verified section matters most, and ranking the diff by the agent's own confidence.

← Fleet-Wide Maintenance: Generating Twenty Pull Requests Is the Easy Part  ·  The Price of Flagship Model Access →

All codex vs claude articles  ·  Every article