Your Smartest AI Is a Lousy Junior Engineer
I used to treat model choice like a volume knob. Turn it all the way up. Use the smartest thing available. If the work matters, why would I ever ask a weaker model to do it?
That instinct held right up until I’d spent enough hours with coding agents to notice an uncomfortable pattern: the strongest model is often the one that makes the most exhausting junior engineer.
Not because it can’t code. It can code. It reasons across a whole repo, infers your conventions from scattered examples, spots the constraint buried in the ticket, and hands you a patch that looks annoyingly plausible before you’ve finished describing the problem. The problem is stranger than incompetence: it has judgment — and it can’t tell when you want it.
Judgment is great, until you’ve already decided
Judgment is wonderful when I need judgment. It is much less wonderful when I’ve already made the decision and now just need someone to follow the line I drew.
There’s a conflict hiding inside the phrase “follow the instructions.” When I hand a model a task, there are really two tasks:
- The task I literally wrote down.
- The task the model infers I must have meant.
Stronger models are better at the second one. That’s a gift when my request is half-formed and I need the model to reason its way toward the real problem. It’s a liability when my request is deliberately narrow.
If I say “use the existing pattern in the neighboring file,” I might mean exactly that. Maybe I already know the pattern isn’t ideal and I’m preserving consistency because the broader refactor belongs in its own review. Maybe the release branch is warm and I’m minimizing risk. The model doesn’t have any of that context. What it has is a local objective and a lot of horsepower — so it optimizes.
It sees the duplication. It sees the awkward abstraction, the helper that could be generalized, the function boundary it would have drawn somewhere else. And then it does the very human senior-engineer thing: it improves the assignment while completing it.
Sometimes the improvement is genuinely good. That’s exactly what makes it dangerous. A bad detour is easy to reject. A tasteful detour costs attention.
The bill comes due at review
Here’s where it actually hurts. I asked to thread one new field through three existing layers — read it, pass it down, match the error handling next door. What came back was the field, plus a small generic config mapper the model invented, plus a renamed variable, plus a “while I was here” tweak to the tests. None of those decisions is obviously wrong in isolation. Together, they changed the job from “verify this implementation” into “reopen the design conversation.”
That’s not junior execution. That’s an uninvited architecture review with a patch attached.
And the cost isn’t just annoyance. I can’t approve the change I asked for without also vetting three I didn’t. The diff no longer traces cleanly back to a requirement, and the quiet behavioral change is the one I’m most likely to miss — because the suite still passes. I asked for a screwdriver and got a multitool, and now I have to inspect every blade before I trust the one I needed.
A smaller, narrower model does less of this. Not because it’s magically reliable — it can still misread a spec or fumble the mechanics — but because, given a narrow task and an explicit prompt, it’s far less tempted to reopen the problem. It takes the spec seriously because the spec is most of what it has. That makes it a weaker collaborator during discovery and a better worker during execution.
To be clear, this isn’t a knock on junior engineers, human or otherwise. Good junior execution is a real skill: read the local pattern, make the smallest correct change, ask when the plan contradicts the code, and finish without turning the assignment into an architecture referendum. The point isn’t “dumber is better.” It’s that restraint is the job — and restraint is exactly what raw capability fights against.
The senior model belongs at the edges, not the middle
So I’ve stopped putting the strongest model in the middle of the work. I put it at the edges.
At the beginning, it’s exactly what I want. It’s good at ambiguity. It can hold three approaches in tension and tell me where each one gets ugly. It says, “this looks like a two-line fix, but the real risk is the cache-invalidation path.” That’s senior-engineer work, and more reasoning power is the product — I want it hunting for the clever failure mode, because that’s the one that bites in production. The same instinct makes it the right tool for rubber-ducking a stuck problem or running an audit, where suspicion is the whole point.
At the end, I want it back, with fresh skepticism: review the diff, find the missing migration, catch the accidental behavior change, notice the test that proves the mock instead of the feature.
The middle is a different job. The middle is mostly translation — take the decided plan and turn it into code. There’s still craft in it, but the craft is local: read the nearby files, match the idiom, keep the patch small, don’t create a second problem while solving the first. Put the strongest model there and it treats implementation as one more chance to rediscover the plan.
In practice, my loop is now: think with the strong model, freeze the plan, execute with a narrower model, review with the strong model again. Strong model on the ends, narrow model in the middle.
The hand-off — turning the plan into instructions a junior could follow without re-deriving my reasoning — is where it lives or dies. For execution I don’t write a wish; I write a ticket that includes the decision, not just the desire:
- Touch only these files.
- Preserve the surrounding pattern, even if you see a cleaner abstraction.
- Don’t rename or refactor unrelated code.
- Run these tests. Stop when the checklist is done.
That’s less glamorous, on purpose. A boring patch isn’t a disappointing patch — when the job is execution, the boring patch is the product. I want the diff to look inevitable, every changed line tracing straight back to an instruction.
It was never really about price
It’s tempting to file this under cost optimization — expensive model for hard thought, cheap model for grunt work. True enough, but it misses the actual lesson, which is organizational.
Different phases of the work need different failure modes. In planning, I’d rather a model overthink than underthink. In execution, I’d rather it be a little unimaginative than quietly ambitious. In review, I want the suspicion back. Asking one model to do all three because it’s “the best” is like asking the same person to run the design meeting, implement every ticket, and approve their own pull request. Even if that person is brilliant, the structure is wrong.
For me today that means Opus to think, plan, and review, and Sonnet or Haiku to do the work — but the model names will age out long before the principle does. So I still want the smartest model in the room. I just don’t always want it holding the keyboard. Once I stopped asking it to be both architect and junior, everything got faster.
Which of your tasks actually need judgment — and which have you been handing to an architect when they just needed a careful junior?