DEV Community

Cover image for Code Preview: Reviewing the Plan Before the AI Writes the Code
Rodrigo Nobrega
Rodrigo Nobrega

Posted on

Code Preview: Reviewing the Plan Before the AI Writes the Code

AI made writing code cheap. It did not make reviewing code cheap. On my team, that gap became the real bottleneck. So I proposed a change to how we work: move the most important review upstream, and review the plan before any code exists. The team adopted it, and it is now part of how we build. We call it the code preview.

There is nothing revolutionary here. Design reviews, RFCs and architecture decision records have existed for decades. What changed is the economics. When a developer and an AI can produce a 1,500-line pull request in an afternoon, the expensive part is no longer typing. It is a reviewer trying to reverse-engineer intent from a wall of generated code, and discovering on line 900 that the whole approach was wrong.

Some teams are already living the worst version of this. A developer who had just joined a big company described it publicly: specs, tickets, code and reports all generated by AI, nobody reading anything, and no time given to understand where things are going.

A post by @v0xium describing a team where everything is generated by AI and nobody reads it

The problem in that post isn't that the team uses AI. It's that nobody is reviewing intent anymore. Output goes out faster than anyone can understand it.

A widely shared response came from Mitchell Hashimoto, who proposed a benchmark he calls the "whiteboard defense":

He doesn't ask engineers to know every line. He asks them to explain how a system works and defend its decisions: why X instead of Y, what happens with a malicious actor, where it fails. And he draws a clear line: prototypes and demos can be fully generated, customer-facing work cannot ship without high-level understanding.

I agree with every word. The code preview is how my team tries to meet that bar in practice. The whiteboard defense is a test you can be given at any moment after shipping. The code preview builds the answers before any code is generated: the "why X instead of Y" lives in the plan's alternatives section, the failure modes in its risks, and the whole team has already challenged them.

Reviewing a plan written in plain language is much cheaper than reviewing the code that comes out of it. That is the whole idea. The rest of this post is about how we run it, what we learned in practice, and where it falls short.

How the code preview works

The plan is a first-class artifact in git, reviewed like code, before code is generated.

  1. A developer picks up a business requirement and investigates it: the codebase, the constraints, the options.
  2. They write a plan.md, usually with AI help, and commit it to a dedicated plan branch.
  3. A short kickoff meeting presents the plan to the team. This is the only synchronous part. Its job is shared context, the why and the big picture, not line-by-line scrutiny.
  4. The team reviews the plan asynchronously. Everyone has access to the plan branch and can point their own AI tools and skills at it: check it against the codebase, hunt for missing edge cases, compare it with existing patterns.
  5. Once the plan is approved, the code is generated on a feature branch that the plan branch merges into.
  6. Code review follows, against a plan the reviewer already understands.

Only the reasoning survives the trip to main; the plan itself is removed before the merge.

We originally called the meeting the "solution defense." I renamed it. "Defense" made it sound like the developer was on trial, and people who feel on trial argue instead of listening. "Preview" describes what it really is: a look at the code before it exists. The defense still happens, as Hashimoto describes it, but as a conversation the team has together before anything is built.

The part I find most interesting is step 4. AI sits on both sides of the plan. One AI helps write it, and several others, configured differently by different people, stress-test it. Reviewers with different setups catch different things.

The best catch wasn't a bug

The most valuable thing a code preview has caught for us wasn't a mistake. It was a missed opportunity.

A colleague presented his plan for a new third-party integration. It used an outbox pattern so the integration could deliver reliably even when the external API misbehaved. It was a solid, well-reasoned plan.

During the discussion, others realized the same problem existed well beyond his integration. Other parts of the system talk to third-party APIs too, and they need the same guarantees. The conversation shifted from "is this the right outbox for this integration?" to "why don't we have one outbox for the whole application?"

We left with a broader scope: a single outbox implementation that every third-party integration uses. Every integration gets the same robust behavior, and nobody has to reinvent it. His work became the foundation for the rest of the system instead of one more local solution.

A shared outbox isn't the right call for every system, and that trade-off was part of the debate. In our case, the integrations' contracts and delivery guarantees were close enough that one general implementation made sense. We agreed to start shared and split it only once a real need proves it.

A code review might have caught this too, but by then we would already have invested in the local solution. Catching it at the planning stage meant we could change direction before any code was written. AI coding agents can scan a codebase for reuse, but they usually lack the organizational context, the knowledge of what others are about to build, and the mandate to question a ticket's scope. That took several people with context on different parts of the system, looking at the plan together while changing course was still cheap.

One question decides everything

Every judgment call in this process comes down to the same question: is this architectural, or will other parts of the system depend on it? We ask it at three moments.

Should this task get a code preview at all? It is up to the developer. A new report can skip it. A different frontend component in an admin panel can skip it. An outbox pattern for a new integration should be presented and defended. A simple rule of thumb: preview anything that is expensive to undo or that other parts of the system will build on. It's the same line Hashimoto draws between a demo and customer-facing work.

Does a mid-course correction need re-approval? Implementation always teaches you something the plan missed. A naming convention change or a small database index doesn't need another round. Changing a deep integration pattern, for example adding a deduplication table where the plan had none, goes back for approval.

What survives into the permanent docs? The reasoning behind architectural decisions does. The step-by-step implementation does not (more on that below).

One principle applied at three moments is what keeps the process from turning into a pile of rules. It also leaves room for developer judgment, which is the point. We are not trying to replace judgment with ceremony.

Plans are transient, docs are permanent

A plan never reaches main. The plan branch merges into the feature branch, and the plan.md must be removed before the feature merges to main.

The reason is a distinction I think many teams blur. A plan describes how to build something. System documentation describes how something works. Once the feature ships, the first kind of document is history, and history that sits next to living docs becomes a liability. Repos fill up with stale, half-true markdown: plans that were changed during implementation, steps that no longer match the code.

This matters more with AI in the loop. Coding assistants read the repo as context, and they can't tell an outdated plan from current documentation. A stale plan.md on main is a prompt that confidently describes a system that doesn't exist.

That doesn't mean the plan's reasoning is thrown away. A good plan explores the alternatives and explains why they were discarded, for example: "we will call the third-party API asynchronously, so a slow or failing provider never blocks a user-facing request." That reasoning belongs in the final docs too, and the docs are part of the deliverable. So when a feature ships, the plan's scaffolding (the steps, the file lists, the task breakdown) is discarded, and its reasoning is promoted into permanent documentation.

Two gates, not a bottleneck

My biggest concern when we started was obvious: we were adding a second approval gate. Plan review, then code review. That sounds like twice the waiting.

In our experience, it worked the other way: reviewing the plan made the code reviews that followed more focused and easier to navigate.

Code review doesn't get lighter. Reviewers still check the code properly. It gets easier because the reviewer no longer has to learn the semantics of the change from the code itself. They already learned them from the plan, written in natural language, days earlier. Code review becomes a comparison: does this code do what we agreed it would do? That is a much easier question than "what is this code trying to do, and is it a good idea?"

The two questions also get answered by the right people at the right time. Whether the approach is right is debated while changing it costs nothing. Whether the implementation is right is checked against a reference everyone shares.

What makes a good plan.md

A good plan is short enough to review in one sitting and specific enough that the AI can generate code from it without guessing. The section that matters most is the one most plans skip: alternatives considered.

A skeleton that works:

# Plan: <feature name>

## Requirement
The business problem, in a few sentences.

## Proposed solution
The approach, the main components, how data flows.

## Alternatives considered
Each option and why it was discarded.

## Impact
What existing parts of the system change or depend on this.

## Risks and open questions
What could go wrong; what the team needs to decide.

## Implementation steps
The ordered steps the code generation will follow.

## Docs to update
Which system docs this feature changes.
Enter fullscreen mode Exit fullscreen mode

The last two sections map directly onto the lifecycle above. Implementation steps are scaffolding and disappear with the plan. Alternatives considered and docs to update are what carry the reasoning into permanent documentation.

A plan written this way doubles as the best prompt you can give a code generator. The team effectively reviews the prompt before it runs.

Pros and cons

The trade is more upfront thinking in exchange for less wasted generation and faster code review. Here is how it has played out.

What works

  • Wrong approaches die early. They are caught in a markdown file, before tokens, review time or rework are spent on them.
  • Code reviews are more focused, because reviewers compare code against a plan they already understand.
  • The plan is the prompt. A plan the team has challenged produces better generated code than one person's first idea.
  • Developers keep thinking. Writing a plan someone will scrutinize forces you to understand the problem instead of delegating the thinking to the AI.
  • Diverse review. Each reviewer brings their own AI tools and skills, so the plan is tested from several angles.
  • Shared context. The kickoff means the whole team knows what is being built and why.
  • Cleaner docs. Transient plans stay off main, and the reasoning that matters is promoted into permanent documentation.

What costs

  • Upfront time. Writing and reviewing a plan takes time before any code exists. For small tasks it is pure overhead, which is why skipping is allowed.
  • It relies on judgment. Whether to preview, and whether a correction needs re-approval, are developer calls. That flexibility is deliberate, but different people will draw the line in different places.
  • Plans can look right and still be wrong. Some problems only appear in code. The process reduces surprises; it doesn't eliminate them.
  • Reviewing a plan is a skill. Reviewers have to engage with prose seriously, not skim it and approve.
  • The "why" depends on discipline. If no one promotes the reasoning into the docs before the plan is removed, it survives only in git history.

Review intent, not just output

AI moved the cost of software from writing code to understanding it. The code preview is our response: put human attention where decisions are made, in a plain-language plan, and let the generated code be checked against it.

If you want to try it, start small. Pick the next architectural change on your board, write the plan, put it on a branch, and ask the team to review it with their own tools before a single line is generated. Then notice how the code review feels.

I'd like to hear how other teams handle this. Do you review plans, prompts, or only the final code?

Top comments (0)