DEV Community

One author, one reviewer

One author, one reviewer

The business problem

Most of a software ticket is not architecture. It’s finding the file, reading the caller, grepping for the other two implementations, writing the patch, running the tests, fixing the import you broke. A strong junior can do that all day. A few moments decide whether the PR is a gift or an incident: which module owns this, migrate or dual-write, fix-forward or revert, is this flake or a real race, are we about to break a public API.

Put a senior on those forks, leave the junior in the seat, and you get a better merge and a bill that matches the work. That’s how we already run engineering teams. The junior keeps the Jira. The staff engineer who has seen this movie sits with them for ten minutes before they cut the wrong abstraction. The junior ships. The senior’s calendar goes where it changes the outcome. Nobody pretends the distinguished engineer should type every test fixture.

We have not been staffing coding agents that way. The default has been “put the best model on the whole ticket.” Eng wants the agent to handle messy refactors and half-migrated modules. Finance wants the unit cost to look like autocomplete, not a staff engineer pair-programming every ls. Those are not opposite goals. They are a staffing problem. If I put a frontier model on every token, we get quality and a painful invoice — I’m paying staff rates for grep. If I put a cheap model on every token, the invoice looks great until it “fixes” the bug in the wrong layer, CI is green on a lie, and a human spends the afternoon reverting. The win is not picking a side. The win is putting judgment where the work gets hard.

So the business question, as I’d put it to a CFO and a VP of engineering in the same room:

How do we give the agent a staff-level review at the forks, keep a single author on the diff, and measure dollars per merged ticket — not dollars per thousand tokens?

A green PR that actually fixes the issue. A migration that doesn’t page on-call. That’s the unit. Tokens are a bad proxy. A cheap model that retries four tool loops and still needs a human is not a saving. A frontier model that types “got it” and rewrites a file it didn’t need to touch is not quality. Quality is how often we land cleanly. Cost is what we paid to get there.

The ticket I keep using: “timeouts on checkout after the payments refactor.” Most of the work is mechanical — find the client, read the retry config, grep for the old deadline, patch, run tests. The fork is: is this a timeout, a queue backup, or a contract change in the new SDK? Dual-write for a week, or cut over? Give the greps to the model that’s already in the repo. Give that fork a senior read before anyone writes. That’s a strategy. “Always expensive” and “always cheap” were just two incomplete buttons.

The third button people reach for is a router: easy ticket, cheap model; hard ticket, expensive model. It sounds like triage from the ticket title. Real bugs get interesting after you’ve read the code. “Fix the timeout” is easy until you see three retry wrappers and a feature flag. A router has already committed, and it never saw the grep results. I’d rather spend that engineering time making the working model good at asking for a review.

Support agents have the same shape — lookups versus refunds — but I came to this as a software problem first. Coding agents are the one-author, one-reviewer story. We already know how to staff it. We just kept buying the senior to type the patch.

We’ve run this with humans for years

The thought is not new. On every engineering team I’ve been on, a junior performs better with a senior in the loop — not because the senior writes the diff, but because the junior keeps the PR and gets a second brain at the forks. That’s code review, office hours, and “hey, look at this before I push,” not a staff engineer hijacking the branch.

Junior owns the ticket
    → greps, reads, writes the first patch, runs tests
    → gets stuck, or is about to do something irreversible
      (schema change, public API, delete the fallback)
    → asks senior
Senior reads the branch — not a Slack summary, the actual diff and the failures
    → “don’t dual-write here; the old path is already dead.
       extract the retry, don’t copy-paste it. write the test first.”
    → does not take the laptop, does not force-push
Junior lands the PR
    → still the author in git blame
Enter fullscreen mode Exit fullscreen mode

A good senior does not snatch every ticket because they’re faster. They make the person who already has the checkout cheaper and better. That’s the whole economic argument, dressed as mentorship. It’s also why “I’ll just write it myself” is a smell: you got the merge, you lost the owner.

What we traditionally built with agents was the opposite shape, and we called it grown-up. Put the frontier model on the ticket. It plans, it opens files, it writes the patch, it is the author. Sometimes we got fancier: the big model becomes an EM, chops the job into tasks, hands “go grep this” to a smaller model, stitches a PR back. That’s not code review. That’s a staff engineer who can’t stand to let go of the keyboard, plus interns who never see the whole bug.

Traditional agent (what I kept reaching for)
    Senior drives. Junior fetches.
    Frontier model is the author: plans, edits, opens the PR.
    Or: frontier model is the EM, small model does chores, frontier model merges the story.

What I want now
    Junior drives. Senior reviews.
    The working model owns the repo tools and the commit.
    The stronger model reads the transcript — files, test output, dead ends —
    returns a review comment, sits down.
Enter fullscreen mode Exit fullscreen mode
How we staff a coding team Traditional agent Junior drives, senior reviews
Who owns the work Junior, author of the PR Frontier model The cheaper model already in the repo
Who has the context Junior, in the checkout and the failing tests Split across EM + workers, or only the big model The working model, in the live transcript
When the senior shows up Design check, when stuck, before merge Every turn, or up front as the orchestrator When the executor asks for a review
What the senior is allowed to do Review comments. Force-pushing the branch is the failure mode. Everything: edits, plan, the commit message Advice only. No tools. No commit.
What gets better This PR, and eventually the junior The bill, until it doesn’t This run. The model does not “level up” next sprint.
What we pay for Senior calendar at the forks Staff token rates on grep and “got it” Staff token rates on a short review

Two places the analogy is honest:

The junior has to be good enough to drive. I would not pair someone who can’t read a stack trace with a distinguished engineer and call it a team. Mentoring is not a promotion. If the work is a novel distributed-systems design, I still want the staff engineer on the ticket. We do that with humans too. We just don’t pretend the intern is almost staff because they had a 1:1.

The senior should not take the keyboard. On human teams, that’s how you get a hero culture and a junior who never ships. I like the same hard constraint on models: the advisor does not call apply_patch and does not open the PR. Two authors means two sources of side effects. We don’t let two people share a deploy key without a reason. CODEOWNERS is the human version of that. The advisor is a reviewer, not a CODEOWNER with push.

And three places it breaks, which I almost papered over because it sounds nice:

The senior can see more than a Slack ping. A human junior summarizes — badly, usually. “It’s a timeout thing.” The useful version of this pattern does not take my summary. It takes the full working tree of the session: every grep, every test failure, every dead end. That’s better than most PR descriptions I’ve reviewed. It’s also why a DIY second call with a 2k-token “brief” is a worse copy of review than sharing the real thread — like reviewing a slide instead of the diff.

The junior does not learn for next sprint. Mentoring compounds in people. It does not compound in a model. Each session starts over. If I want the executor to internalize “we don’t dual-write here anymore,” that’s a prompt, a lint rule, an eval — not “the reviewer told it once.” I kept wanting this to be a training story. It isn’t. It’s staffing this ticket.

Senior time is not a hallway chat, it’s a pause. A human senior can talk while the junior keeps typing. A second model inference usually does not stream into the same turn. The junior stops. On a coding agent that’s a spinner — same as waiting on CI. On a phone call that’s dead air. You already don’t pull a staff engineer onto a live customer call to debate whether to extract a class. Same instinct.

So: same thought as the traditional eng team, inverted from the traditional agent. Junior writes, senior reviews, junior lands the PR. We already believed that about people. We just kept buying the senior to type the patch, because “use the best model” was the default.

Three designs I kept mixing up

Before this, I lumped “model mix” into one bucket. I don’t anymore.

One model, always. Frontier-only is honest. Quality ceiling is that model. Cost ceiling is my patience. Fine for a one-off architecture spike. Wrong for a fleet of coding agents grinding through the backlog. Cheap-only is also honest. I live with the failure modes. Rename a variable, generate a test, “where is this configured” — that’s still the right call. It’s Copilot, not a staff engineer.

A router in front. Classify from the ticket title: easy → small model, hard → frontier. Hardness is not a property of the Jira summary. “Fix the timeout” is easy until it isn’t. The router already committed. I also pay a latency tax on turns that never needed a design review — every cat of a file.

Executor plus advisor. The cheaper model starts in the repo. When it decides it’s stuck — or when I’ve prompted it to consult before an irreversible edit — it asks for a review. The expensive model sees the evidence: the files, the test output, the failed approach. Not the ticket title. Escalation after information. That’s the thing I want to remember.

There’s a fourth design I’m keeping, and I needed to separate it so I don’t throw it out: policy in my code. Schema migrations, drop table, pushing to main, production deploys — the cheap model does not get those tools without a gate. That’s not model routing. That’s CODEOWNERS. An advisor saying “just migrate it” is still a review comment, not a merge.


How the loop actually works

Three boxes. I redrew them until I could do it from memory:

                    ┌─────────────────────────────────┐
                    │  Shared context                  │
                    │  conversation · tools · history  │
                    └──────────▲────────────▲──────────┘
                               │ read/write │ read (advice write)
                    ┌──────────┴─────┐   ┌──┴──────────────┐
                    │ Executor       │   │ Advisor         │
                    │ cheaper model  │──►│ frontier,       │
                    │ every turn     │   │ on demand       │
                    │ main loop      │◄──│ plan / correct  │
                    └────────────────┘   │ / stop signal   │
                                         └─────────────────┘
Enter fullscreen mode Exit fullscreen mode

The executor runs the agent. It greps, reads, edits, runs tests, opens the PR.

The advisor reads the full transcript — system prompt, tool defs, files already opened, test output, whatever the executor already said this turn — and returns a short review: a plan, a correction, or a “stop, you’re in the wrong package.” It does not call tools. It does not author the commit.

The transcript is the question. I kept wanting advisor(question="should I dual-write?"). Throw that away. If the senior only sees my summary, I reintroduced the Slack-ping problem. That’s reviewing a standup update instead of the diff.

Shared context is not a vector store. It’s the session the executor has been living in — the checkout, the failures, the dead ends. The advisor is not guessing from a design doc I wrote. That’s the whole point versus a DIY second HTTP call where I stuffed 2k tokens into another model and hoped.

And the advisor still can’t git push. The executor still has to apply the patch. I needed that said out loud. I do not want two models with write access to the branch. One author. One reviewer.

If you build this yourself, the shape is: one agent loop, one transcript, a tool that means “ask for review,” a cap on how often that happens, a cap on how long the comment can be, and a dashboard that splits the two bills. The consult will pause the stream. On a coding agent that’s waiting on CI. On voice that’s a product incident unless you cover it.


What made this click for me

I had the staffing idea. What I didn’t have was a clean picture and numbers that weren’t my own wishful thinking.

Then I sat with this diagram from Anthropic’s April 2026 post, The advisor strategy:

A cheaper executor runs every turn against shared conversation, tools, and history. A frontier advisor is on-demand, invoked as a tool. Anthropic evals: SWE-bench Multilingual +2.7 pts and about 12% lower cost; BrowseComp with a small executor goes from 19.7% to 41.2%.

They named it the way the slide reads: the working model drives, the frontier model advises, you pay for the frontier model only when it matters. In their stack that’s a mid-tier or small model in the seat and their flagship on the consult. The names are their lineup. The shape is a coding team: author plus reviewer, not a staff engineer typing every line.

They also shipped it as a first-class API primitive instead of “please wire two clients together.” That’s what inspired me to stop treating this as a weekend hack. The advisor tool docs are worth reading if you’re on Claude. If you’re not, the post is still the best public write-up of the pattern I’ve seen. You can build the same loop on any provider: cheaper model as executor, frontier model as a no-tools advisor, shared transcript, cap the consults.

Where I now think the money goes

The spread that makes this worth doing lives on output. A 400-line patch at frontier rates is the expensive line. A 500-token review comment is cents if I cap it. Uncapped, the “cheap consult” becomes a second staff engineer writing the whole PR in comments. Anthropic’s own testing is useful here as a warning, not as my bill: uncapped hard-reasoning advice ran thousands of tokens; a cap around 2k cut that sharply with almost no truncation. Same as “review comments should not be a rewrite of the file.”

cost/task ≈
    executor_input  × $exec_in
  + executor_output × $exec_out
  + Σ advisor_input  × $adv_in     # full transcript each consult
  + Σ advisor_output × $adv_out    # aim for a short plan
Enter fullscreen mode Exit fullscreen mode

Then I’d bucket tasks: never consulted, once, three or more. If 40% of “easy” tasks consult, my prompt is too twitchy. If 0% of failing tasks consulted, my prompt is too shy. Both are prompt bugs. I kept wanting them to be model bugs.

A few things I would get wrong in week one on any stack:

The executor bill and the advisor bill have to show up as two line items. If I only export “the model,” I will under-report frontier spend and then I’m confused.

A token cap on the executor does not automatically cap the advisor. Set a cap on the advice itself.

A per-request consult limit is not a conversation limit. Long sessions need a counter in my code.

Priority, rate limits, and overload on the advisor are a degraded dependency. The junior should keep going without advice. That’s a quality incident, not always an HTTP 500. I want an alert on it.

Cost can go down when a better plan reduces executor tokens. If I only add consults and behavior doesn’t change, cost goes up. That’s not a bug in the pattern. That’s me.

Where I’d use it, and where I wouldn’t

I would not put an advisor on single-turn Q&A. Nothing to review. I’m buying a second model to restate the question. I would not hide it behind a UI where the user already picked a model. I would not use it where every turn is the hard turn — just let the frontier model be the author. This pattern needs a mechanical majority, the way a junior needs a ticket that’s mostly execution.

I’m keeping application gates either way. git push to main, schema migrate, drop table, production deploy — the cheap model never gets those without a gate. Advice is not a merge. CODEOWNERS still owns writes.

What I’d get right in production

The one-liner is adding a consult tool. The actual work is teaching the junior when to ask for review.

Call after orientation — ls, grep, read — and before you write or commit to an interpretation. Call again when you think you’re done, but persist the artifact first (write the file, keep the test output), because the consult takes time and the session can die. That’s “commit locally before you start a long CI job.” Call when you’re stuck or about to change approach. Don’t silently ignore the review. If your evidence contradicts it, call again with the conflict. A passing unit test is not proof the reviewer was wrong — it’s evidence your test doesn’t check what the review is checking.

Coding and research want different timing. A hard rule like “first apply_patch must follow a consult” can lift coding and hurt browse. Measure. Don’t one-prompt every executor. You wouldn’t use the same PR template for a hotfix and a design spike.

Nudging “ask the senior at turn 2” is sharp. Anthropic measured that a turn-2 nudge made most executors call immediately — and if the first useful consult is usually turn 7, that early call hurt the task. A design review before you’ve opened the repo. Measure first-call turn before copying that trick. I would have copied it.

Cap consults per conversation in your code. Cap advice length so the senior doesn’t rewrite the PR in comments. Round-trip whatever the API gives you on the next turn, including the review block. Pin executor and advisor as a pair when you bump models — same as pinning compiler and linter together.

When the advisor errors, the request may still succeed. That’s polite and dangerous. If consults are exhausted, the junior keeps going — log it, and escalate if the task is still failing. That’s a junior merging without review because the reviewer was out. If the frontier model is overloaded, same story: proceed, alert, don’t retry-storm. If the transcript is bigger than the advisor’s window, I failed at the moment I most needed help. Compact before that — same as “this PR is too big to review.”

If easy tasks always consult, the prompt is too aggressive — review on every typo fix. If hard tasks never consult, the junior is being shy. If the executor thanks the advisor and does the opposite, that’s a prompt and eval problem, not a reason to raise the cap. Raising the cap makes a model that isn’t listening more expensive. I would have raised the cap first. That’s the wrong reflex. That’s adding more reviewers to a PR the author isn’t reading.

If the executor migrates prod because the advisor said so, I shipped a confused deputy. Policy still owns writes. Review comments are not terraform apply.

If I were rolling this out

Not a framework. The sequence I’d actually run, so I have something to disagree with later.

First I’d freeze the unit of value. Merged ticket that actually fixes the issue. Contained support session. Completed browse. Successful voice containment. Cost is dollars per successful unit, not dollars per thousand tokens.

Then a three-way eval on the same harness: executor solo, executor plus advisor, frontier solo. Pin prompts. Pin consult caps. Record score, dollars per task, turns, tool calls, advisor call rate, advisor error rate, wall time. If I can’t run that, I’m not ready for the pattern. I’m ready for a blog post. This is the blog post. The eval is the work — same as I wouldn’t roll a new CI check without a canary.

Prompt by workload. Histogram of first-consult turn. Too early, delay it. Never, add a hard rule, then measure again.

Shadow maybe 10% of eligible coding-agent sessions with the same policy engine. Don’t execute the advisor’s plan until the eval bar holds. Export the two bills. Teach whoever watches spend that there are now two line items, while the number is still small. That’s a feature flag, not a rewrite of main.

Kill criteria: if dollars per success don’t improve and quality is flat, turn it off. A pattern that doesn’t move either curve is decoration. I needed to write that so I don’t keep it out of stubbornness.

I still want workers for parallel work — independent spikes, separate checkouts. This does not retire sub-agents. It retires “the frontier model types the whole ticket.” Staff still doesn’t have to be the author.

What I learned

I had the routing story backwards. Don’t classify the first sentence. Let the model that’s already in the loop escalate after it has evidence.

The traditional human model was right. Junior owns the PR, senior reviews, junior lands it. The traditional agent model was the inversion of that: senior is the author, junior fetches. One author. The senior never takes the keyboard, never apply_patch, never opens the PR.

Mentoring is not a promotion. A small model plus an advisor is not a mid-tier model. And unlike a junior engineer, the model does not get better next sprint because someone reviewed it this week. Per-ticket staffing, not a growth plan.

Quality and cost can move together when a short review prevents a long stupid trajectory. Anthropic’s SWE-bench number is that story: fewer wrong files, not a smarter typist. It is not guaranteed on an agent that’s already tight.

The browsing jump is strategy, not style. Doubling a small model’s BrowseComp score told me the advisor is selling search and repair plans — the same thing a senior does when the junior is grepping in the wrong package. New operating point. Still not the mid-tier model running alone.

Prompts are the product. Coding versus browse want different instructions. A nudge at turn 2 can hurt — design review before you’ve cloned the repo. The transcript is the question. A cap on the executor does not cap the reviewer.

Voice is a different clock. The consult pauses the stream. Coding agents can wait on CI. I use this on the text brain or after the call, not as a silent pause on a phone line.

Advice is not a merge. CODEOWNERS stays in my code.

Dashboards will lie if they only show one model. Split the bills. Chart advisor failures, because the request may still look fine — green CI, no review.

Anthropic’s post gave the pattern a name and a public eval. That’s the inspiration. The work is still ours: one author on the diff, a reviewer at the forks, cap the consults, measure dollars per merged issue. The work gets better, and the bill finally looks like the job.

Top comments (0)