Intent is the first informal abstraction layer, and that breaks the compiler analogy. Every earlier jump up the stack came with a deterministic translator and a formal language. Agents come with neither, and that matters a lot once you ask whether anyone still needs to understand the code.

Code-Level Understanding Is a Resource You Spend Down

The moment a team goes agent-only, whatever code-level knowledge existed at that point freezes into a snapshot. That snapshot is usually one person: whoever wrote the system by hand before the agents arrived. From there it only decays. The agents change the code past what the snapshot covers, and the other engineers never build a snapshot of their own, because the thing that used to build one, writing code by hand, is gone. So code-level understanding becomes something you spend down.

Do you even need it anymore? I don’t think so, on one condition: you have code-level controls, and you can measure how well the agents implemented the intent from the ticket.

Meeting that condition is hard because of one failure mode. The agent implements feature B, quietly changes feature A, and rewrites feature A’s test to keep CI green. Tests are mutable and the agent will mutate them. So the controls can’t be the tests as written. They have to be intent frozen into something the implementing agent can’t touch: the ticket, locked golden tests, deterministic hooks. Without those, the gap between what you asked for and what shipped is hard to see without going back to the code, and reading the code takes the knowledge you’ve been spending down.

How the Old Jumps Worked

We’ve moved up abstraction levels before. Machine code to assembly, assembly to C, C to JavaScript, JavaScript to frameworks. Each time, we stopped needing to look at the layer below, for two reasons.

The translator that absorbed the lower layer was deterministic. gcc compiles the same way every time, so the high-level language became the source of truth and the assembly became disposable. And the lower-layer knowledge concentrated into a small group, compiler engineers and kernel developers, who maintain the translator and get called when it leaks.

That second reason still holds, and it’s my answer to the question above. Keep one or two code-level humans, point them only at the verification layer, and let code-level knowledge fade everywhere else. Those people shouldn’t be spent shipping features. It’s harder than the old version, though. gcc is shared infrastructure, so one small group of maintainers serves the whole world. Right now every team hand-rolls its own agent controls, so every team needs its own group. There’s no shared agent compiler yet.

Determinism and Formality

The first reason doesn’t hold. Martin Fowler and Birgitta Böckeler point out that with LLMs we’re moving sideways into non-determinism at the same time as we move up. You can’t trust an agent and forget about it the way you do a compiler, because it won’t produce the same output twice.

The source of truth also flips. With a compiler, the high-level code is canonical and the assembly is throwaway. With an agent, the generated code is canonical and you can’t recover the prompt from it. Anyone checking their English ramblings into version control is hand-building version control for the one artifact every earlier layer kept without anyone thinking about it.

Formality is the other break. Assembly, C, and JavaScript are formal languages, and a syntax error won’t compile. Intent written in English has no such property. Dijkstra wrote about this in 1978: the “naturalness” with which we use our native tongues “boils down to the ease with which we can use them for making statements the nonsense of which is not obvious.” You can’t reject a bad intent the way a compiler rejects bad syntax. This is the first jump that’s both non-deterministic and informal, which is why the old intuitions don’t transfer cleanly.

Rebuilding Determinism in Shells

We can’t make the model deterministic, so the move is to rebuild determinism in shells around it: types that make bad states uncompilable, golden tests the agent can’t edit, deterministic hooks instead of in-context instructions. Together that verification layer is a synthetic compiler wrapped around a translator you can’t trust on its own. Every earlier abstraction layer got its compiler for free, and with this one we’re building it by hand.

Even the optimists end up somewhere close. Marc Brooker writes that the future of programming looks like the past: “a natural language conversation, a feedback loop, with the occasional descent into mathematical precision.” That descent into precision is the verification layer, so the real question is how occasional it is and where you put it.

I don’t think that allocation is solved, and I think it gets decided subsystem by subsystem. Spend the precision where product-market fit has been found and correctness has real consequences, billing being the obvious one, and stay disposable everywhere pre-PMF. Post-PMF is where high engineering throughput is clearly good. Pre-PMF the bottleneck is iteration and customer feedback, and more engineering throughput can flood that bottleneck with unvalidated work.