AI-friendly architecture — Purple Hammer
Engineering·6 July 2026
AI-friendly architecture: write better software, not just more of it
Ari Isaacs·9 min read
The story everyone tells about AI engineering is volume: more code, faster — until it collapses into unmaintainable slop. The real story is the opposite. AI enables building much better software.
AI made one thing radically cheap: deep, local, isolated implementation. A heavily optimised, frontier-grade subsystem — the kind that used to take the best teams months — is now plausibly a couple of days' work when the boundary around it is clean. Meanwhile the best models can barely move a button inside a large, stateful, interconnected app. If your AI is writing slop, the problem is probably your architecture.
The claim of this essay is that AI-led development has elevated isolation to the single most important concern in software architecture: the models make isolated, deterministic, low-state code nearly free to write and maintain — and make everything coupled brutally expensive to touch.
The cost inversion
Eighteen months ago, implementation depth was the dominant cost in software. A 5,000-line numerical optimisation took months to write and was heavy to review and maintain. A shared mutable field felt free — one line. A pub/sub event felt efficient — one emitter instead of a thousand lines of plumbing.
AI inverted that. An isolated subsystem is basically free to build and maintain. The critical cost became the burden the code puts on the next entity that touches it. A human carries an implicit map of the codebase and can filter out the ambient state that doesn't bear on the change at hand. An agent can't. Every time it moves a button it reconstructs the local constraints from scratch — the norms, the invariants, what this call means at this lifecycle edge. Review stops being a gate cleared once at merge and becomes a cost paid on every touch. And coupling sets the size of that cost: in a coupled system, touching a button loads the whole web the button is snarled into.
This follows from how the models reason. LLM reasoning is intensely linear. "Big context" duped us — context was never bound attention. A model can follow one isolated path almost forever: a linear A → B → C → D signal is strong and cheap, and every step focuses the model's attention squarely on the next. But it struggles with a stateful, temporal web: which subscriber saw this flag? which lifecycle edge changed what a call means? which state combination triggers the reported bug? The answer is somewhere, but nothing local says where to look — "many things may affect this, trace them all one by one" is a weak signal to land on and an expensive path to walk once landed.
The obvious reply is that the next model dissolves this. The labs have thrown everything at it — extended thinking, prompt caching, million-token windows, repo-wide retrieval — and the brute force kind of works, until it doesn't. Spending tokens following the slow paths buys headroom, not immunity. Past a certain density, you pay the tokens and the model still drops a constraint.
The other standard answer is tests and harnesses. Necessary, not sufficient. On a coupled, stateful codebase the harness doesn't dissolve the global problem — the agent still has to work through it, and if everything is connected, every change breaks tests. Triaging real reds from wanted changes is more work and more error-prone than coding without tests. In other words: sufficiently bad architecture makes tests stop being regression guards and become progression guards.
Architecture for AIs: narrow entrances, long tunnels
For a system coded mostly by LLMs, good architecture is whatever makes problems local. This one concern overwhelms everything else. The shape I keep returning to: narrow entrances, long tunnels.
A narrow entrance is a small, explicit contract — ideally a pure, stateless function: visible inputs, visible outputs, as few options as possible, ideally none. A long tunnel is everything behind it. The system only ever sees the entrance. And that's what unlocks complexity: the innards can be as gnarly as the domain forces, so long as they're isolated. The poison spreads only when state leaks outward.
The thing we underprice most is the pure function. You can pack an absurd amount of sophistication inside one with almost no error space, because the errors are bounded to the inputs and outputs. Lock the entrance with a correctness test and a performance benchmark, and an agent can work the tunnel overnight — refactor, optimise, try alternative implementations, hunt numerical edge cases — against a sandbox that proves every change. This is where a linear reasoner comes alive: a bounded error space, a deep isolated path, and a number that says better or worse. The optimisation becomes nearly free.
Take a spreadsheet solver running cold — the example, like everything here, comes from building Purple Hammer1. It's a long...