Plan mode in Claude Code: the conversation step that prevents thrash
Published 2026-05-11 by Owner
The pattern plays out the same way every time: you ask an agent to add a feature, it goes quiet for thirty seconds, and then you see a wall of diffs touching files you didn’t expect. Some edits are right. Some are confident and wrong. You accept the good ones and spend the next ten minutes undoing the rest.
That’s not a model quality problem. It’s a sequencing problem. The agent executed before you agreed on a plan.
Claude Code’s plan mode is the conversation step that sits between “here’s the task” and “start editing files.” When you invoke plan mode, the model produces a written plan in chat — what it intends to touch, why, in what order — without making any changes to your codebase. No file writes. No shell commands. A proposal on paper.
To enter plan mode, tell Claude Code explicitly: “Think through this and give me a plan before making any changes.” Or use the built-in /plan prefix if your configuration supports it. The key behavior is that the model reads files to understand the codebase — it can still use read-only tools to gather context — but it stops short of any writes or command runs. It produces prose and a step list. You review. You push back or approve. Then you explicitly ask it to start executing.
This is distinct from just asking “how would you do this?” which invites a theoretical answer the model may not follow when it actually executes. Plan mode in the context of Claude Code specifically constrains the execution layer: the model isn’t theorizing, it’s proposing the actual sequence of moves it intends to make.
The analogy to Cline’s Plan/Act split is accurate but inexact. Both insert a thinking step before execution. Claude Code’s version is lighter on ceremony: there’s no mode toggle in a UI, you just ask for a plan explicitly, review it in the conversation, and then signal when you’re ready for execution. The cost of getting this wrong is lower when the agent hasn’t touched anything yet.
The rough shape of a plan-mode session: ask for the plan, read it, push back once or twice until it covers the cases you care about, then explicitly transition to execution. That’s the whole loop. The rest of this guide is about the parts that matter inside that loop.
Why plan mode matters most on unfamiliar codebases
On a codebase you’ve worked in for months, you have a mental map. You know that “add a new route” means touching three files in a specific order, that there’s a shared validator you should reuse, that changing the auth middleware will break three tests. When an agent proposes something, you can spot the gap immediately because you already know where the bodies are buried.
On an unfamiliar codebase — day two on a new project, an OSS repo you’re contributing to for the first time, a colleague’s service you’re debugging — you don’t have that map. The agent might have a better structural read than you do at that moment, or it might be confidently wrong about something load-bearing. Without a plan on paper, you have no way to tell which before the diffs land.
The stakes are asymmetric. Getting a plan wrong costs nothing: you read it, say “that’s not right, here’s the constraint you missed,” and get a corrected proposal. Getting an execution wrong costs real time: you revert the edits, re-read the files the agent touched, figure out what assumption it made, and try again. On a codebase you understand well, you can speed through that cycle. On an unfamiliar one, each revert is expensive because you have to reconstruct context.
Plan mode changes the cost structure before it matters. A bad plan is a paragraph you reject. A bad execution is an edit session you unwind.
The rough rule: the less familiar you are with the code being touched, the more you benefit from a written plan first. This also applies when the task is familiar but the scope is larger than usual — any time you catch yourself thinking “I’m not sure what else this might affect,” that’s plan mode territory.
How a plan-mode session runs
When the plan looks right, you need to signal a clean transition from proposal to execution. “Ok do it” works, but it creates ambiguity — the model might continue discussing, refine the plan further, or misread your intent.
The conventional signal is more explicit: confirm the plan is approved, then ask the model to exit plan mode and begin. Something like:
“That looks right. Exit plan mode and implement this.”
Or, if you’ve made changes to the proposal during dialogue:
“Use the revised plan from your last message. Exit plan mode and start.”
The word “exit” is the handshake. It tells the model to stop proposing and start executing. Without it, you can end up in a loop where the model keeps elaborating the plan instead of acting on it, which wastes turns and tokens.
One thing worth noting: the plan lives in the conversation context when execution starts. If the plan was three messages back, the model has it. You don’t need to paste it again — but if the session is long and context is compressed, a brief confirmation of the key points doesn’t hurt.
A bad handoff looks like this: “Ok that sounds good, go ahead.” The model interprets this as approval and starts executing, but sometimes it also continues generating the next paragraph of the plan instead of switching gears. You then have to interrupt and re-anchor. The explicit “exit plan mode” phrasing short-circuits this. It’s a mode-change signal, not just a permission signal.
If you find the model continuing to propose after you’ve approved, that’s a sign the handoff was soft. Repeat it more directly: “Stop planning. Start implementing the plan from your previous message now.”
A plan that needed three rounds
Plan mode’s value is easiest to see in retrospect. Here’s how a real plan-mode session plays out when the task has hidden complexity — and why the first plan being wrong is not a failure, it’s the feature.
The task: add a per-user rate limiter to an existing API. The API is new to me; I’ve read the routing layer but not the middleware chain.
First plan (wrong):
I’ll add a Redis-backed rate limiter at the route level. For each route that needs limiting, I’ll wrap the handler with a
rateLimit()call that reads from Redis using the user ID as key. I’ll createsrc/middleware/rate-limit.tswith the core logic.
The problem I spotted: “at the route level” means touching every route handler individually, maybe fifteen files. The better approach is a single middleware that applies globally with per-route configuration — something a router middleware pattern would handle. The plan also assumes Redis is already configured; I know it isn’t.
I pushed back:
“The Redis instance isn’t set up yet. And adding this per-route seems like a lot of touch points — can you use the global middleware chain instead? What does the middleware setup look like?”
Second plan (better but incomplete):
I’ll first provision a Redis connection in
src/lib/redis.ts, added to the app init insrc/app.ts. Then I’ll add a singlerateLimitMiddlewareinsrc/middleware/rate-limit.ts, applied globally in the router setup. Per-route configuration will come through route metadata.
Better. But I noticed it didn’t mention anything about what happens when rate limit state needs to be reset — for test runs, and for admin override. Those are edge cases I’d discover in code review if not caught here.
I added them:
“Good. Two additions: the middleware should skip when
NODE_ENV === 'test'to avoid flaky tests. And we’ll need an admin endpoint to reset a user’s limit manually. Can you add those to the plan?”
Third plan (solid):
src/lib/redis.ts— Redis client singleton, skipped in test envsrc/middleware/rate-limit.ts— middleware that reads user ID from request context, skips when NODE_ENV is testsrc/app.ts— wire the middleware into the global chain after auth middleware (so user ID is available)src/routes/admin.ts— newDELETE /admin/rate-limit/:userIdendpoint, requires admin rolesrc/middleware/rate-limit.test.ts— unit tests for the skip-in-test path and the limit logic with a mock Redis client
That’s the plan I approved. Total cost of the plan-mode dialogue: maybe eight hundred tokens across three turns, no file edits. The execution was clean because the plan was specific about order and dependencies — I knew exactly what files to look at in the diff.
The value was the second round of pushback. The first plan wasn’t catastrophically wrong, but it would have generated a messy implementation that I’d have needed to refactor before merging. The third plan produced code I could review once and merge.
Notice what the three-round dialogue didn’t cost: time spent reverting bad edits, reading unexpected diffs, or re-running tests after an implementation that broke something. All of that pressure came before any file changed. That’s the trade plan mode is offering.
When to skip plan mode
Plan mode has overhead. For trivial changes, it’s pure friction.
Skip it for one-line changes. “Fix this typo in the error message” has no ambiguity. The plan would be “fix the typo” and you’d still be reading it when you could have just approved the fix.
Skip it when you have a clear spec. If you wrote the implementation notes yourself and you’re just handing them to Claude Code for execution, you are the plan. There’s nothing to propose. The model should be translating your spec into code, not reasoning about what to build.
Skip it for well-understood library boilerplate. “Add a Zod schema for this type and wire it into the existing validation middleware” has a well-trodden path in the model’s training. The plan would be obvious, and obvious plans aren’t worth a round-trip.
Skip it the second time you do a similar task in the same session. If you added a new API route earlier in the session and the approach was right, adding a second route doesn’t need a plan. The model already has the pattern from what it just did, and the conversation context carries the decisions you made. Ask it to follow the same approach and execute directly.
Skip it when the scope is constrained to one file. Single-file, single-purpose changes are easy to review in diff form. If the diff is wrong you’ll see it immediately. The cost of a bad edit is low.
The threshold from the Cline world translates here: multi-file changes on unfamiliar code almost always benefit from a plan first. Single-file changes on familiar code usually don’t.
A corollary worth stating: if you feel impatient skipping plan mode, that impatience is a good signal you probably should have used it. The times it feels most unnecessary are often the times a silent assumption would have led the execution somewhere unexpected.
Plan mode as a scope probe
There’s a use for plan mode that isn’t about execution at all.
On a large codebase, sometimes the question isn’t “how do I implement this” but “what does implementing this actually involve.” Asking Claude Code for a plan on a non-trivial task surfaces the scope — which files, what dependencies, what test surface area. You might read the plan and decide the task is bigger than you thought, or smaller, or in the wrong place in the stack.
This works even when you’d ultimately write the code yourself. The plan is a structural read of the task from an agent that has already indexed your codebase. It’s often faster than spending twenty minutes tracing call graphs manually.
The plan also reveals assumptions. If the model’s plan starts with “assuming the user table already has a preferences column,” that assumption is now visible. You can confirm or correct it before it becomes a buried ALTER TABLE in an Act session you weren’t expecting.
The plan doesn’t commit you to anything. You can read it, use it to orient, and then put it down and do the work your own way. That’s a valid use of the conversation step — not every plan needs to become an execution. Sometimes reading “here are the seven places this change touches” is itself the deliverable.
What you’re buying with plan mode is the ability to catch the wrong approach before it’s woven into your files. The plan turns a potential revert into a conversation. Most tasks that touch more than one file are worth that trade.
The workflow for most non-trivial Claude Code sessions looks like this: plan mode until the approach is solid, then a clean exit into execution, then review. That sequence consistently produces less cleanup than jumping straight to execution — even when it feels slower in the moment.