The plan, subagent and review loop
I built this site’s landing page, and later its bilingual blog, with Claude Code. Both times I used the same process: a written spec first, then a step-by-step plan, then a separate subagent for each task, with an independent review after every one.
This post describes the process, what it actually caught and what it missed.
The process
- Spec. A few questions and answers turn into a written description of what to build: scope, decisions, what is out of scope. No code.
- Plan. The spec is split into ordered tasks. Each task lists the files, the test to write, the code itself and the commit message. The plan is concrete enough that implementing it is close to transcription.
- Implementation. Each task goes to a fresh subagent that has never seen the conversation. It writes the failing test first, then the code, commits, and leaves a report file.
- Review. Another subagent compares the task’s diff with the plan and gives two verdicts: does it meet the spec, and is the quality good enough.
- Fix. Findings go back to the same implementer. After the fix, a short review covers only the changed part.
- Final review. When all tasks are done, the whole branch is reviewed once more with the strongest model.
The coordinating session writes no code. It hands out tasks, reads review results and records what happened and which decision it made in a ledger file. Even after context compaction, it knows where it stands from that file.
Why fresh context
In a long session a model eventually stops questioning its own earlier decisions. Starting every task with a clean context prevents that. The subagent sees only its task, the interfaces it touches and the global rules. Less context means less drift.
Because the plan is concrete, cheap models are enough for the implementation tasks. Reviews use a mid-tier model, the final review the strongest one.
What the reviews caught
All real, all found in code that passed its tests:
- A list that should have been hidden was visible. The landing page’s “Latest writing” section renders two lists, one per language, and hides one with
hidden. The list’sdisplay: gridrule overrodehidden, so both lists showed. The test that should have caught it tested nothing: its regex stopped at the first nested</ul>, so the card count was always one. - The implementer changed an interface to pass a test. A link-checking test mistook the
href=inside thedata-lang-hrefattribute for a link. The implementer renamed the attribute and the test passed. But that name was the interface the next task’s JavaScript would read. Ruling: the interface was restored and the broken regex fixed. - A deploy that would have failed silently. The documented FTP setup would have sent the deploy to the wrong folder. The pipeline would go green and the site would not change.
- Links to pages that do not exist. Tag pages emitted an
hreflanglink to the other language even when that page did not exist. - A code path that had never run. There was an “only available in English” note for single-language posts, but none of the sample posts were single-language. The code would have run for the first time in production. A single-language sample post was added.
- Small but real. Curly apostrophes replaced with straight ones, bio paragraphs left empty when JavaScript is off, a one-day cache that also applied to HTML.
What they missed
- Environment differences. Node 20 locally, Node 22 in CI.
node --test tests/does not work on Node 22. No review saw it and the first deploy failed. Lesson: run locally what CI runs. - Visual checks. Subagents without a browser skipped the “look at the page” step. The coordinating session did it in the browser itself.
When it is worth it
The ceremony is not cheap. Each task means an implementer, a reviewer, often a fix round and another short review. It pays off for tasks that touch several files and whose interfaces depend on each other. In the blog work, the hidden bug caught by the final review justified the whole process on its own.
It is not worth it for a one-line fix, a copy change or a setting. Doing those directly is faster and cheaper.
Lessons
- A written spec first. The plan derives from it and the reviews judge against it.
- The more concrete the plan, the cheaper the implementation.
- Keep the author and the reviewer separate. The author’s tests test the author’s assumptions.
- Never change an interface to pass a test. Question the test first.
- Give the final review to the strongest model. Cross-task bugs only show up in the whole diff.
- Reviews do not test the environment. Keep CI and local the same.
- Record the decisions. The list of every ruling the coordinator made is the only trace you have at the end.