How to write a plan detailed enough that an AI agent builds the whole thing first try, without you sitting there correcting it.
Everyone tuning their prompts is working on the wrong thing. You can write the most beautiful prompt in the world and still get back something almost right, because the model isn't short of instruction. It's short of information.
Every gap you leave, it fills with a decision you never made. Then the next step gets built on that decision, and the one after that inherits it. By the time you notice, you're ten steps into somebody else's idea of your project, and the only way back is to start again.
Before a single task, write the block of things that are true for every task. The stack. What isn't installed. The conventions. The things that have already gone wrong before. Every task inherits it, so no task has to work it out again and no task gets to guess.
This one section is the difference between a plan and a to-do list.
Here are real ones, from the plan behind a live feature:
Why it can't live inside the tasks. The tempting version is to repeat the important bits in each task where they matter. Don't. Repeated constraints drift, the copies start disagreeing with each other, and you find out at task fourteen when two finished pieces won't connect.
A phase is a group of work that makes sense to finish together. A task is one unit inside it, and a task is only a task if it has all five of these:
| Every task carries | Because without it |
|---|---|
| Files | It invents a file layout, and the next task can't find anything |
| Interfaces | It guesses what to call things, and two tasks build two halves that don't meet |
| A failing test | You have no way to tell "built" from "built correctly" |
| The implementation | — |
| A verification command | It reports done and is sincerely wrong |
Example — Task 1 of 19, Phase 1: Engine Skeleton
Files:
Create: tools/guest-scout/config.py
Create: tools/guest-scout/run_tests.py
Create: tools/guest-scout/tests/test_config.py
Interfaces:
Consumes: nothing
Produces: config.REPO_ROOT, config.DB_PATH, config.env_value(name)
Step 1: write the failing test (the whole test file, in full)
Step 2: implement until it passes
Nineteen tasks sounds like a lot to write. It's less work than it looks, because once the constraints block exists each task is mostly naming files and interfaces. And it's dramatically less work than debugging a build that went sideways at step four.
This is the one that makes the whole method work, and it's the one almost everybody skips.
A task that ends in "make sure it works" is not a task. It's a wish. The agent has no way to check it, so it will tell you it's finished and it will be sincerely, confidently wrong. It isn't lying. You just never gave it a way to find out.
A task that ends in a command either passes or it doesn't:
$ python3 tools/guest-scout/tests/test_config.py
5 passed ✓ phase 1 clear
That's the done metric. It's a gate, not a note. And it's what turns a plan from a description of the work into something the agent can actually run itself against.
What counts as a done metric:
What doesn't count: "check the page loads", "confirm the output looks right", "verify it works end to end". Every one of those needs a human — and the whole point is that you're not there.
Now the plan can run itself. The loop is simple, and it only works because step 03 gave it something to check against:
task 06 the web source ✓ pass
task 07 the Instagram source ✗ fail → retry
task 07 the Instagram source ✓ pass
task 08 enrichment fan-out ✓ pass
That failure in the middle is the point. Without a done metric, task 07 would have been reported as finished and tasks 08 through 19 would have been built on top of something broken. With one, it just goes round again.
This is what people mean by multi-agent work that actually holds up. Not more agents. Agents that can tell whether they succeeded.
In order. The order matters: you can't write a good plan from a vague idea, and you can't loop a plan that has no way to tell whether it worked.
I want to build [describe it in one sentence].
Before you write anything, interview me. Ask one question at a
time and wait for my answer before you ask the next one. Ask
about the things you would otherwise have to guess: who it is
for, what it does when everything goes right, what it must
never do, and what already exists that this has to fit into.
When you have enough, write a design doc in four sections. Get
my approval on each section before you move to the next one.
Do not write the whole thing and then ask me what I think.
The doc says what we are building and why. It never says how
to code it.
One question at a time, because ten questions in one message gets you three real answers and seven you skimmed. Approval section by section, because if section one is wrong then sections two through four are wrong too.
Turn that design doc into an implementation plan.
Start with a Global Constraints section. Everything that is
true for every task goes there, once: the stack, what is not
allowed, the conventions, the things that have already gone
wrong before. Every task inherits it, so no task has to work
it out again and no task gets to guess.
Then break the work into phases, and phases into numbered
tasks.
Every single task has:
- the exact files it creates or changes
- what it consumes and what it produces, named
- a failing test, written first
- the implementation
- a verification command I can run that either passes or fails
No task should be big enough that you would have to make a
judgement call halfway through it. If you would, split it.
Implement this plan task by task.
After each task, run its verification command and show me the
output. If it fails, fix it and run it again. Do not move on
until it passes.
Do not skip ahead, do not batch tasks together, and never tell
me something works without running the command that proves it.
None of these throw an error. That's what makes them expensive.