AI Systems
Engineer the boundary, generate the implementation
The useful split is not humans versus agents. It is that the decisions live upstream and the code lives downstream, and only one of those can be handed over.
Most arguments about AI and software are stuck on the wrong axis. One side says an agent can build the application. The other says it produces code nobody should trust. Both are arguing about volume, and volume was never the interesting variable.
The useful split is not humans versus agents. It is that the decisions live upstream and the code lives downstream, and only one of those can be handed over.
What has to be decided before anything is written
Ask an agent to build a service and it will produce one. What it cannot do is tell you whether it should have been one service or three, because that question is not answerable from the prompt — it depends on what else exists, what changes together, and who is going to operate it at two in the morning.
The decisions that have to be made by someone holding the whole system in their head:
- Where the boundary sits. What this component owns, and what it must never reach into.
- The contract. What goes in, what comes back, and what happens on every failure.
- The shape of the data. Not the table — the invariants. What must always be true, and what the system does when it is not.
- The failure modes. What is retried, what is idempotent, what is allowed to be lost.
None of these are typing problems. They are the parts that are expensive to change later, because everything downstream is built assuming the answer.
The brief that makes generation work
Once those exist, generation is genuinely good, and the difference between a useful result and a plausible one is almost entirely in the brief.
A weak brief describes an outcome: build the part that syncs calendars.
A strong brief describes a boundary:
This component owns exactly one thing: reconciling our appointment records with an external calendar. It receives an account identifier and a time window. It returns a list of differences, and it never writes. It cannot read appointment data for any other account. The external provider fails by timing out rather than erroring, so treat no response inside four seconds as a failure and return a partial result flagged as stale.
The second brief produces code you can review in minutes, because you already know what it is supposed to do and what it is forbidden from doing. The first produces something that works on the happy path and has to be read line by line to find out what else it decided.
This is why the bottom-up direction works and the top-down one does not. Not because agents are weak, but because a boundary is the thing that makes generated code reviewable at all.
An example of the division
Building a launcher for AI coding agents meant supporting several providers that authenticate in entirely different ways — API keys, browser-based flows, local models needing no credentials at all.
The engineering decision was the interface: one menu, one credential store, provider differences never leaking into what the user sees. That decision took the longest and is the reason the tool is usable.
The adapters behind it — one per provider, each conforming to an interface that already existed — were exactly the kind of work an agent does well. Bounded, contracted, and verifiable against a definition somebody had already committed to.
The same pattern held for workspace connectors on a support platform: the connector interface was designed once, deliberately, and then each concrete connector was mostly generated against it. The generated part was never the risky part, because the risky decisions had been made.
The second half: review
Generated code needs review, and agents are unexpectedly good reviewers. They catch the things attention slips on — an unhandled branch, an inconsistent null check, a loop that will be slow at scale, an edge case in date handling. It is a reviewer that never gets tired, and on those categories it is better than a person on a Friday afternoon.
Then it flags something that is not a bug.
A discount that looks wrong is a contractual rate for one customer. A validation that seems too permissive exists because the upstream system sends malformed identifiers and the business decided to accept them. A retry that appears missing is absent deliberately, because the operation is not safe to repeat.
The pattern is consistent: an agent recognises patterns, not product context. It knows what code of this shape usually does. It does not know what your business agreed to, which exceptions were negotiated, or which apparent inconsistency is load-bearing.
Which makes it an excellent reviewer and a poor decision-maker. Every flag is worth reading. Not every flag is worth acting on, and telling those apart requires exactly the context that was never in the prompt.
What this changes about who you need
It does not reduce the need for engineering judgment. It concentrates it.
Fewer people are needed to produce the code. The same people — arguably more senior ones — are needed to decide what the code should be, and to tell a real finding from a confident one. Teams that go fastest with these tools are not the ones that delegate the most. They are the ones with someone who can write the brief that makes delegation safe.
If a system was built the other way round, and the boundaries were inferred rather than decided, our production readiness review is fixed in scope and says which of those inferences held.
More
Related reading.
AI Systems
Nobody has read your AI-generated codebase
It runs, it demos, and no human has traced a request through it end to end. Here is what that costs, and the four things worth checking first.
AI Systems
Someone still has to answer for it
Generation gets cheaper every year. Being the party who answers when a regulator asks who approved the data model does not, and that gap is widening.
Recognise the problem?
If this describes where you are, the first conversation is usually short and tells you whether we are useful.