Plan Mode Is a Cheap Veto, Not a Design Document
Rejecting a direction after an hour costs the hour. Rejecting a plan costs one exchange. Everything else follows from that ratio.
The point of the plan is that rejecting it is cheap
A planning step before implementation gets described as producing a shared understanding, or a design artefact, or a chance to align. Those are pleasant side effects. The mechanical value is narrower and larger: it moves the moment you can say no from the end of the work to the beginning.
Rejecting a direction after an hour of implementation costs the hour, plus the awkwardness of discarding something that exists, plus the pull toward salvaging parts of it that should not be salvaged. Rejecting a plan costs one exchange. Everything else about the practice follows from that ratio.
Which also means a plan you approve without reading has negative value. It consumed a turn, and it produced a feeling of having decided that will make you less likely to question the direction later. An unread plan is worse than no plan.
A plan is not a design document
The most common way this goes wrong is scope inflation. Asked to plan, an agent will produce something that reads like a design document: background, goals, considered alternatives, a phased rollout, risks and mitigations. It is well-written and it is the wrong artefact.
What you need is short and specific: which files will change, in what order, what is being assumed, and what is explicitly not being done. Four things, most of them lists. If the plan is longer than the diff it describes, the planning step has become the work.
What a good plan actually contains
APPROACH
Replace the polling loop in sync/worker.ts with the existing
event subscription used by sync/inventory.ts.
FILES
sync/worker.ts rewrite the run loop (~80 lines)
sync/types.ts add SyncEvent union (~10 lines)
sync/worker.test.ts new; mirrors inventory tests
config/defaults.json remove pollIntervalMs
ORDER
1. types 2. tests (failing) 3. worker 4. delete config key
ASSUMING
- the event bus delivers at-least-once, so handlers stay idempotent
- pollIntervalMs is not read anywhere outside sync/
- dropping the poll is safe for consumers with no backlog handling
NOT DOING
- touching sync/inventory.ts
- the retry semantics discussed in #4412
Thirty seconds to read. Every section is checkable. And the file list with rough sizes tells you immediately whether the agent understood the task — a plan that proposes to touch nine files for what you thought was a two-file change is either a misunderstanding or something you did not know, and both are worth a sentence before the work starts.
The assumptions section is where the value concentrates
If you read one part, read that one. It is the list of things the agent could not determine from the code and resolved by guessing, and a wrong guess there propagates through every subsequent decision.
In the example above, the second assumption is the dangerous one:
pollIntervalMs being read somewhere else is exactly the kind of
fact that lives in a deployment configuration the agent never saw. Checking it
takes one search. Discovering it after the change is a production
incident.
Agents do not volunteer this section reliably. Ask for it by name, every time.
Reading a plan properly takes ninety seconds
Three questions, in order.
Is the premise right? Not the steps — the sentence the steps are built on. A plan can be internally flawless and rest on a misunderstanding of what you asked for, and the steps will look reasonable the whole way down.
Is the file list the right shape? Too few files usually means something was missed. Too many means the scope grew or the approach is more invasive than you expected.
Is anything in the assumptions surprising? One search resolves most of them.
The plan that is wrong in a way that looks right
Worth naming as a category because it is the hardest to catch. Every individual step is sensible, the ordering is correct, the file list is plausible, and the whole thing solves a slightly different problem from the one you have.
This happens when your request was ambiguous and the agent resolved it silently. It is not detectable by scrutinising the steps, only by re-reading the premise against what you actually wanted. Which is why the first question is about the premise and not about the plan.
"No, use the event bus" produces a corrected plan. "No" produces a different plan that may be wrong in a new way. The correction is cheap and it also becomes context for the rest of the session, which is worth more than the one exchange.
Plans drift during execution
The plan is approved and then the code turns out to be different from what the plan assumed. A file has a dependency nobody expected, a test fails for an unrelated reason, the interface has two implementations rather than one.
At that point the agent is choosing between following a plan that no longer fits and departing from an approved artefact. Both are bad by default, and the resolution is to say in advance which you want: "if the plan turns out to be wrong, stop and tell me rather than adapting". That converts a silent divergence into a cheap second conversation.
What plan mode does not do
It does not make the implementation correct. An approved plan and a working implementation are independent, and approving a plan can make you less likely to review the code carefully, because the direction feels settled.
Watch for that specifically. The plan review and the code review are different activities looking for different failures, and the first one going well is not evidence about the second. If anything, a plan you were pleased with is a mild reason to read the diff more carefully rather than less.
When to skip it
Small, well-understood changes where the plan and the diff would be the same length. Exploratory work where the approach is genuinely unknown and the first attempt is how you learn. Anything with an unambiguous done condition and a low cost to discard — if the check is definitive and the work is ten minutes, planning is overhead.
The heuristic: plan when the cost of a wrong direction exceeds the cost of the planning exchange. For a two-file change with tests, it does not. For a change that will touch a shared interface, it does by a wide margin.
Plans are the best artefact for review by someone else
An underused property. A plan is short, legible to someone who has not been in the session, and it describes intent rather than mechanism — which makes it a far better thing to show a colleague than a diff.
For anything touching an area someone else owns, pasting the plan into a channel and getting a reaction costs them ninety seconds and catches the class of problem no local review will: the thing that is fine in this repository and breaks an assumption held somewhere else.
The anti-pattern is approving to get on with it
The failure this practice actually suffers from is not bad plans. It is that reading one is friction between you and the work, and after a few dozen good plans the reading stops.
Same mechanism as any other approval that becomes routine, and the same mitigation: keep the plans short enough that reading is trivial, and treat a long plan as a signal that the task should be split rather than as a document to skim. A plan you can read in thirty seconds gets read. One that fills the screen does not, and the one that fills the screen is usually the one that needed reading.
Where it fits with everything else
Plan mode is one of several places to catch a wrong direction, and it is the cheapest. Before it: a clear request, and an explicit statement of what you want to be consulted about, as in pairing with an agent. After it: the done conditions from asynchronous task handoff, then code review, then CI.
Each catches failures the others miss. The plan catches the wrong approach. The done condition catches incomplete work. Review catches incorrect work. CI catches the regressions nobody thought about. Skipping the first is the most tempting because it is the only one that costs your attention before anything exists, and it is the one whose absence is most expensive.
Plans are cheap to keep, and worth keeping
A plan costs nothing to paste into the pull request description, and it does something a diff cannot: it states what was deliberately not done. Reviewers routinely raise things that were considered and excluded, and the plan answers those before they are asked.
It also survives the session, which the reasoning otherwise does not. Six months later, the question "why does this module do it this way" has an answer in the pull request rather than in someone's memory of an afternoon.
Watch what the plan reveals about the request
The most useful thing a plan tells you is often about your own prompt. A plan that goes somewhere strange is usually a faithful reading of an ambiguous instruction, and the ambiguity is visible in the plan in a way it was not visible in the sentence you wrote.
Treating a bad plan as a prompting signal rather than a model failure is the more productive reading, and it improves the next request. Over a few weeks it changes how you write tasks generally, which is worth more than any individual plan.
Two plans are sometimes better than one
For a genuinely open question, asking for two viable approaches with the trade-off stated costs one extra exchange and produces a much better conversation. You get a comparison rather than a proposal, and comparisons are easier to judge than single options.
It also surfaces the case where the agent has no strong reason for its choice: if the second plan is obviously a strawman, the first one was arrived at by default rather than by reasoning, which is useful to know before approving it.
The planning step is also where scope gets negotiated
A plan makes size visible before it is spent, which is the only moment at which scope can be reduced cheaply. Seeing "eleven files, two of them shared" in a list is a prompt to ask whether all eleven are necessary for the thing you actually need this week.
Frequently they are not. The agent planned the complete version because you described the complete version, and the version you need is the first two files plus a follow-up ticket. That conversation is trivial at plan time and awkward at review time, when the work exists and discarding it feels wasteful.
This is the same reason estimates are useful even when inaccurate: the number is less important than the fact that seeing it prompts a conversation about whether the thing is worth its size.
A plan is a commitment device for the agent too
Worth noticing: an approved plan constrains the work in a useful direction. An agent working from an explicit file list and an explicit not-doing list stays closer to scope than one working from a sentence, because the boundary was stated rather than inferred.
That is a real effect and it argues for keeping the not-doing section even when it feels obvious. "Not touching sync/inventory.ts" reads as unnecessary until the moment the implementation hits something in that file that looks worth fixing, at which point the line is what stops a two-file change becoming a five-file one.
The value of a planning step is that saying no costs one exchange instead of an hour — so an unread plan is worse than none, since it manufactures the feeling of having decided. Ask for four things only: files with rough sizes, order, assumptions, and what is explicitly out of scope. Read the premise before the steps, treat the assumptions list as the highest-value section, and say in advance that a plan found to be wrong during execution should stop rather than adapt.