Plan mode first, or just start? Both passed; planning cost 73% more
We asked Claude Code to add note archiving to a 24-file API six times. Three runs planned first in plan mode, three just started. All six passed our hidden tests. Planning first cost about 73% more per run, $0.28 against $0.16.
“Start in plan mode” is common advice for changes that touch more than one file: let Claude read the code and propose a plan, approve it, then let it edit. We wanted to see what that buys on a realistic multi-file change.
The setup
The same notes API as our subagents recipe: about 470 lines across 24 files. The task touches at least four of them, and two traps are only visible if you read the code. Tag counts don’t go through the shared listNotes() helper, they scan the store directly. And they’re cached, so archiving a note has to clear that cache or the counts go stale.
The prompt, the same in every run:
Add note archiving to the notes API. POST /notes/:id/archive and POST /notes/:id/unarchive archive or restore one of the caller’s notes and return the updated note, or 404 if it isn’t theirs. Archived notes must stay out of everything that lists a user’s notes (GET /notes, search and tag counts), except that GET /notes?archived=true lists only their archived notes. GET /notes/:id still returns an archived note. Every note the API returns, in lists or on its own, includes archived: true or false. Add tests.
We ran it 3 times each two ways:
- Just start: the prompt as written, with edits allowed.
- Plan first: the same prompt in plan mode (
--permission-mode plan), where Claude can read but not edit. Then, in the same session with edits allowed, one reply: “Your plan is approved. Go ahead and implement it.”
Afterwards, a hidden test Claude never saw checked every requirement in the prompt, including tag counts read just before and just after archiving. A second hidden test checked something the prompt didn’t ask for: every other write in the notes service records an audit event, so archiving should too.
What happened
| Just start | Plan first | |
|---|---|---|
| Hidden archiving test passed | 3 of 3 | 3 of 3 |
npm test passes |
3 of 3 | 3 of 3 |
| Archive and unarchive audited (not asked) | 3 of 3 | 3 of 3 |
| Added its own tests for archiving | 3 of 3 | 3 of 3 |
| Ran tests after its last edit | 3 of 3 | 3 of 3 |
| Average cost per run | $0.160 | $0.276 |
| Average cost, planning step only | n/a | $0.152 |
| Average turns | 18.7 | 19.7 |
| Average time per run | 55.1s | 60.6s |
| Main conversation at its largest | 33,800 tokens | 40,000 tokens |
Claude Code 2.1.302, Sonnet 5.5, 3 runs per column. Plan-first costs, turns and times cover both steps, including the subagent’s own usage. Every run, check and diff: run data.
What we learned
Every plan found both traps. All three plans said that tag counts read the store directly and need their own filter, and that archiving has to clear the cached counts. That’s exactly what the hidden test probes.
So did every run that just started. Without a plan, Claude still read before it wrote: each plain run read the routes, services and tests with a few shell commands before its first edit. All three got the tag counts and the cache right, and all three added the audit event nobody asked for.
Planning cost about as much as doing. The planning step alone averaged $0.152, nearly the price of a whole plain run ($0.160). In plan mode Claude handed the reading to an Explore subagent in 3 of 3 runs, then wrote up the plan. The implementation step that followed averaged $0.124, a little cheaper than a plain run, but not by enough to make up the difference. In total, planning first cost about 73% more and took about 5.5 seconds longer.
The planned runs tested a bit more. Plan-first runs added 7, 7 and 8 tests; the plain runs added 5 each. Two of the three plain runs also edited the seed data to add archived: false to every note. None of the planned runs touched it; their plans said up front that a missing field counts as not archived.
The plan is where you’d catch a wrong turn. The plans spelled out choices before any code existed: archiving an already-archived note returns 200, and any archived value other than "true" gives the normal list. One flagged an unrelated date bug and said it would leave it alone. Here every plan was fine, so reading them changed nothing. On a change where Claude misreads the task, that’s the moment to say so.
One note on the setup: headless Claude Code can’t show the plan-approval dialog, so Claude presented each plan as a message and we approved it with a reply. Interactively you’d click approve instead.
Three runs per column is a small sample, and this change touched four or five source files in a small codebase. We’d expect plan mode to earn its cost on bigger or vaguer tasks, where there’s more to misread. We haven’t tested that yet.
The recipe
- For a clear, contained change, just start. Claude reads the relevant code before editing either way, and on this task planning added cost, not correctness.
- Use plan mode when you want to review the approach before code exists: a vague request, an unfamiliar codebase, or a change you’d be annoyed to undo.
- Actually read the plan. Its value is the assumptions it lists, such as defaults and edge cases. Approving without reading is the 73% with nothing back.
- If you plan, ask the plan to name its tests. The planned runs wrote more tests because the plan listed them up front.