I plan agents in two models before I write any code
A method for building AI agents that starts with architecture and adversarial review instead of a system prompt, and why it costs less than rearchitecting later.
Most published advice on building agents opens with a system prompt. Someone shares the block of text that made their agent work, and the implication is that the prompt is the artefact.
The prompt is the last thing I write.
The loop
I open plan mode and describe the problem. Not the solution, not the tooling, the problem. What breaks today, who it breaks for, what the system needs to be true about the world. The model asks clarifying questions here, and answering them properly is the step most builders skip. No code in this phase.
From that I draft an architecture. Component boundaries, what each part owns, where state lives, which failures are recoverable.
Then I hand the architecture to a different model and ask it to attack the design. A second model critiques differently from the model that wrote it, because it is not defending choices it made. The critique it produces is more useful than a self-review, which tends toward polish.
I feed that critique back to the first model and we revise. Once, sometimes twice. Only then does anything get written to disk.
This sounds slow. Measured against the whole project it is not. It trades a delay measured in hours against rearchitecting after you have shipped, which is measured in weeks and comes with a migration.
Structure before code
Once the architecture holds, I get a day-by-day plan and start with the folder layout:
/agent-project
├── agents/ orchestrator + subagents
│ ├── orchestrator.py
│ └── subagents/
├── skills/ one skill, one file, <200 lines
├── config/
├── tests/
├── docs/
│ └── decision-log.md updated daily
├── .env.example no real secrets, ever
├── .gitignore
└── README.md
The structure encodes the constraints. A skills/ directory with a line limit in its own name is harder to violate than a rule in a document nobody rereads.
Building file by file
I build in small increments. One file at a time, day by day.
After every file, I make the model explain what it just wrote before it touches the next one. Not a summary of the intent, an explanation of the actual mechanics: what this function does when the input is empty, why this retry has that backoff, what happens if this call succeeds and the next one fails.
Skipping that step leaves you with cognitive debt. You end up owning a system you cannot explain because you never had to understand it. That debt comes due at the worst moment, when something breaks in production and you are reading your own codebase as a stranger.
I would rather move slower and be able to answer questions about my own system.
Documenting as you go
Two habits, both cheap, both things I skipped once and regretted:
A decision log, updated at the end of every day. Every decision made and everything implemented. Tomorrow's session starts from that file rather than from re-reading code and guessing at intent. It is also the reference when a test fails three weeks later and you need to know what the behaviour was supposed to be.
A real README, not a placeholder. The version you write on day one is wrong by day ten, which is fine. The version that says TODO is still wrong on day ninety.
And one absolute: real credentials never go in a .env file that git can see. Ship .env.example with the shape and none of the values.
Constraints I hold
Three rules survived contact with several projects:
Skill files stay under 200 lines. Past that, models start missing their own instructions and I start losing the ability to review a change without reading the whole file. The limit forces decomposition I would otherwise defer.
One orchestrator, subagents reporting to it, dispatchers managing the handoffs. A flat set of agents calling each other produces failure modes nobody can trace. A single coordinator that owns sequencing gives you one place to look when the behaviour is wrong, and giving the handoffs their own owner keeps that coordinator from turning into a second implementation. Divide the work as granularly as the problem allows.
Cost lands in the design, not the retrofit. Which model handles which step, where results get cached, what runs on every request against what runs nightly. Bolting cost control onto a working system means rewriting the parts that work.
What this buys
At the end I know what got built. That sounds like a low bar. Set against the alternative, where you discover your own architecture by reading production logs, it is the whole thing.
A prompt gets you a demo. An architecture that survived a hostile review gets you a system that holds when real users arrive with inputs you did not imagine.
Related reading
- AI engineeringNot every agent in your pipeline should be an LLM callMost agent pipelines route validation, formatting, retries and the final write through the model. Those are the steps that should never vary, and handing them to a model is what makes an agent flaky and expensive.
- AI engineeringAI made execution cheap. Judgement did not get cheaper.Building an autonomous agent took days instead of months. Deciding which tasks deserved automation took far longer, and that gap is not closing.
- GovernanceYour staging environment is isolated on a diagramAnthropic found three real breaches across 141,006 evaluation runs. The model behaved as trained. The test environment kept live network access, and the same gap runs through data pipelines.