AI agents in real projects
What works, what fails, and where a human stays essential. From a platform we are building with agents right now.
We are currently building a cloud platform where most of the code is written by AI agents. Not as an experiment and not as a demo: it is a system that will run other people’s applications, which means the bar does not drop because there is an agent at the keyboard.
This article is about what we put in place and why. The project is not finished, so this is not a retrospective. It is a progress report from someone still in it.
The problem is not the code
Agents write perfectly good code. Give one a failing test and it will make it pass. Give it a well-bounded task and something that works comes out. That is not where it goes wrong.
Where it goes wrong is everything around the code. An agent starts every session with no memory. It does not know which trade-off you made last week, why one library is in the project and another is not, or that a decision three months ago shaped half of your architecture. It knows what is in the files, and what you tell it in this conversation.
That changes what documentation is. On a team of people, documentation is a service to the next colleague. With agents it is the input. What is not written down does not exist, and the agent will fill the gap with whatever seems plausible.
What you fix up front decides what comes out
The first decision on this project was not technical. It was that nothing gets built without an approved specification and an approved plan.
The cycle is:
Idea → spec → approval → plan → approval → implementation (TDD) → review → done
Two approval gates, and they are never merged into one. The spec captures what and why; the plan captures how, including the test plan and the breakdown into tasks. Only then does production code get written.
That sounds heavy for a project where speed is supposed to be the point. In practice it is the reverse. An agent executing an approved plan gets it right first time, because the hard questions are already answered. An agent starting without one produces something that looks right, which you then spend an hour reviewing to discover it made an assumption you do not share.
The exception is written down too: a change may skip spec and plan when no externally visible behaviour changes, it stays around twenty lines, and no dependency, public API or schema is involved. When in doubt, it is not a small change. Without that exception you will quietly stretch the rule yourself, and then the rule is gone.
One place per fact
The second rule is stricter than it sounds: every fact lives in exactly one file. Everywhere else that needs it links to it by path.
The test we use: “if this changed tomorrow, how many files would I have to edit?” The only acceptable answer is one.
With people, a little duplication is harmless. Someone reads two versions of the same rule, notices one is older, and acts on the newer one. An agent does not. It finds both, picks one (often whichever sits closest to its context) and builds on the wrong one. And because the answer is plausible, you find out when it is already somewhere in production.
The project’s routing file therefore opens by saying that it contains no rules itself. It only says where each rule lives: a table of who owns what. Workflow here, testing standards there, architectural decisions somewhere else again. An agent looking for a rule arrives at exactly one place.
Deciding and recording are two different things
This is the rule we added after it went wrong.
A choice was made on this project about the container orchestrator. It was discussed, it was acted on immediately, and it was recorded nowhere. The result: the entire body of documents went on describing the old choice while the code followed the new one. Every agent that read a spec afterwards got a picture that was no longer true.
On a human team that would have been an annoying half hour. Someone says “we changed that”, and it is over. With agents as the readers, nobody has that memory. “Decided” and “recorded” drift apart quietly and fast.
The rule now is absolute: a choice made in conversation and not written down does not exist. Not a chat, not a spec preamble, not a commit message. Only a line in the decision register or, when it carries enough weight, a decision record of its own.
And that produced a second thing which in hindsight matters most: every spec declares what it rests on. Which decisions sit underneath it. When one of those is later superseded, a list falls out of every spec that needs re-examining, instead of it depending on whether somebody remembers.
That is not an agent problem we solved. It is a problem every long-running project has, and agents only make it visible faster.
Rules that live only in prose get broken
A standard written in a document is a request. Agents follow it most of the time, until under pressure they do not. Exactly like people.
So the things that must not happen are not in prose but in code. Two examples from this project.
There is a hook that refuses git commit --no-verify. That command skips the
quality gates named in the definition of done. Ask an agent whether it wants to
use it and it says no. But when the tests are red and the instruction is “get
this committed”, it is an obvious way out. Now it is not available at all, and
the only way forward is to fix the test.
A second hook fires whenever a file containing rules or agreements is changed. It does not judge the content; it reminds you of the one-place check: grep the key phrases of what you just changed across the whole project, and confirm the fact still exists in one file and the links still resolve. A deterministic trigger at precisely the moment drift is created.
The distinction matters. The hook assesses nothing. It makes the check
impossible to forget. Anything resting on judgement can have a bad day; an exit 2 cannot.
The review does not know the rules by heart
The last step of every change is a review that checks the work against the standards. How it is built is worth noting: the review reads the standards directory at the time it runs.
That means editing a rule automatically changes what is enforced. There is no second list to update, no checklist trailing behind the standards. The rules live in one place and enforcement fetches them from there.
The alternative, putting the rules into the review procedure, looks faster and is exactly the problem the one-place rule exists to prevent.
Where a human stays essential
After a few months of working this way, this is the honest division.
Agents are good at executing. Turning an approved plan into code, test first, task by task. Mechanical work across many files. Reading unfamiliar code and explaining it. The first version of almost anything.
The human decides what gets built, and what does not. That is not caution. An agent can lay out a technical trade-off very well, but it does not have the commercial context: what a client will need next year, which dependency you do not want because you want to be able to leave that supplier, which feature is better left unbuilt. The two approval gates are not there as ceremony. They are there because those are the two points where a wrong assumption is most expensive.
The human sees what is missing. This project keeps a separate register of things the design does not yet answer. Not a to-do list for code, but a list of places where we would be guessing if we started now. Each line names what is missing, what it blocks, and what would close it. That is work an agent does not do unprompted: it would rather fill a gap plausibly than report it.
The human decides when a gap is a gamble. In that same register is a note that characterises the whole project: several open questions cannot be answered until there is a development environment to test against. That makes one particular spec the critical path rather than a side quest. Reordering work like that is a judgement about where the uncertainty sits, not about how code should look.
What it costs, and what it returns
Be honest about the price: this is more process than a project of this size normally carries. Specs, plans, decision records, a decision register, a gap register, four fixed procedures and three hooks. For a two-week job it would be nonsense.
What it returns is that the context does not live in one person’s head. Every agent, every session, every new colleague starts from the same bounded truth. And the side effect is the real win: this is also the documentation you want when somebody else picks the project up in two years. We wrote it because agents cannot work without it. It turns out to be exactly what keeps a project standing beyond its first year.
Most of what makes agents productive is what good projects were supposed to have all along. The difference is that you can no longer skip it.
Hexxore builds software with AI agents and advises on how to set that up responsibly. What makes an agentic workflow production-grade is on our agentic workflows page. Working on a project where this question is live? Tell us about it.