Intermediate · 18 min read · updated 2026-07-14

Claude Code Plan Mode: A Spec-First Workflow

How to use Claude Code plan mode to review a full plan before any file changes, so big refactors don't turn into cleanup jobs.

Claude CodePlan ModeVibe CodingDeveloper WorkflowAI Engineering
Who this is for: developers and technical founders who already run Claude Code day to day, have been burned at least once by an agent that rewrote half a codebase before they noticed, and want a repeatable way to review intent before execution instead of reviewing damage after it.

Claude Code plan mode exists because "just let the agent go" and "review every single edit" are both bad defaults for anything nontrivial. One is reckless, the other is slower than writing the code yourself. Plan mode is the middle setting: the model reads your codebase, drafts a concrete plan, and stops — no files touched — until you approve it. This guide covers when to actually use it, how to write prompts that produce plans worth reading, and how to iterate on a plan without restarting the whole conversation.

What plan mode actually does

Toggle plan mode (Shift+Tab in the CLI, or --permission-mode plan on the command line) and Claude Code switches into a read-only investigation state. It can use Read, Grep, Glob, run read-only bash commands, and browse your repo freely, but every tool that would mutate state — Write, Edit, Bash commands with side effects — is blocked. Instead of doing the work, the model produces a structured plan: what it found, what it intends to change, in what order, and what could go wrong.

You then get three options: approve and let it execute exactly that plan, reject and give feedback (the model revises and re-presents), or exit plan mode entirely and go back to normal execution.

The important detail people miss: plan mode is not "ask before every edit." It's "ask before any edit, but ask once, comprehensively." That distinction is what makes it useful for large changes instead of annoying for small ones.

Plan mode vs normal mode vs auto-accept

ModeFiles touched before you see anythingBest forFailure mode
Auto-accept everythingAll of them, immediatelyTrivial fixes, throwaway scriptsSilent scope creep, unreviewed architecture decisions
Normal (per-edit approval)One at a time, you approve eachSmall, well-understood changesApproval fatigue — you start clicking "yes" without reading
Plan modeZero — plan is presented firstRefactors, migrations, new features touching 3+ filesNone, if you actually read the plan (see below)

When to reach for plan mode

Not every task deserves a plan. Asking Claude Code to plan a one-line CSS fix wastes a turn and your patience. The signal to switch is scope, not difficulty.

Use plan mode when:

  • The change touches more than 2-3 files you didn't already have open in your head.
  • You're not 100% sure which files are even involved (plan mode's exploration phase does that discovery for you, for free).
  • The task is a migration or rename that could plausibly break something outside the obvious blast radius — env vars, build config, a CI step.
  • You're delegating to a model you haven't calibrated yet on this specific codebase (new project, or you just wrote a big CLAUDE.md and want to sanity-check it actually took).
  • The cost of a wrong first attempt is high — production data models, billing logic, auth.

Skip plan mode when:

  • It's a single-file, single-concept fix ("rename this prop", "fix this off-by-one").
  • You're in a tight edit-run-edit loop and already watching the diff every time.
  • The task is exploratory and you want the model to just try something and show you, because a plan for "see what happens" is a contradiction.
Rule of thumb: if you'd want to sketch the approach on a whiteboard before touching code yourself, use plan mode. If you'd just start typing, skip it.

Writing prompts that produce a plan worth reading

A bad plan-mode prompt produces a generic plan. "Add authentication" gets you five bullet points that could apply to any app on earth. The fix is the same discipline as writing a good spec for a junior engineer: constraints, not vibes.

The three things every plan-mode prompt needs

  1. The concrete outcome, stated as a testable fact, not a feeling. Not "make the checkout faster" — "reduce checkout page LCP under 2.5s on 4G, measured via the existing Lighthouse CI job."
  2. The boundaries. What files/modules are in scope, and — often more useful — what is explicitly out of scope. "Do not touch the payment webhook handler, only the client-side form" saves you from a plan that quietly reaches into places you didn't want touched.
  3. The existing pattern to follow, if one exists. Point at a file: "match the validation approach in src/lib/validators/signup.ts." Models default to whatever's statistically common in training data unless you anchor them to your actual codebase conventions.
Plan a migration of our REST client-fetching in src/features/orders
from raw fetch() calls to the useQuery pattern already used in
src/features/inventory/hooks.ts. Scope: orders feature only, do not
touch inventory or shipping. Preserve existing error-shape contracts
consumed by OrderErrorBoundary. Flag any endpoint that doesn't have
a matching TypeScript response type yet — don't invent one, just
flag it.

That prompt gives Claude Code enough to produce a plan with actual file-level specificity, not a rehash of "identify affected files, write tests, deploy."

Reading a plan like a reviewer, not a rubber stamp

The entire value of plan mode collapses if you skim the plan and hit approve. Read it the way you'd read a PR description from a contractor you've worked with twice — trust the mechanics, verify the judgment calls.

Specifically check:

  • The file list. Does it match your mental model of the blast radius? If the model lists fewer files than you expected, it may have missed a caller. If it lists more, ask why before approving — sometimes it's right and you're the one who forgot a dependency.
  • The order of operations. For anything involving a schema or API contract change, the plan should change the schema, add backward-compatible reads, migrate writers, then remove the old path — not do it in one shot. If the plan is "change everything simultaneously," push back.
  • Anything marked as an assumption. Good plans from Claude Code will flag assumptions explicitly ("assuming the /api/v2 endpoint is unused elsewhere — confirm?"). Don't approve past an unresolved assumption; answer it first.
  • Tests. Does the plan mention how it will verify the change, or does it just say "update the code"? A plan with no verification step is a plan to find out in production.
Warning: a plan that reads as extremely confident and extremely short is a red flag, not a good sign. Real refactors have edge cases. If the plan doesn't mention any, either the task was smaller than you thought or the model didn't look hard enough — ask it to re-explore with ultrathink or a more targeted Grep before approving.

Iterating on a plan without starting over

Rejecting a plan doesn't reset the conversation — that's the whole point of doing this inside one thread instead of firing off a fresh prompt each time. When you reject, give a specific correction, not a vague "no, try again."

Good rejection feedback:

  • "Don't touch LeadModal.jsx — that's shared with the guides page, split it into a separate follow-up plan."
  • "You're proposing a new dependency (zod) for validation — we already use manual validation in src/lib, follow that instead, no new deps."
  • "The order is backward — migrate the read path before the write path, not after."

Each of these gives the model a constraint it can act on immediately, and the revised plan usually arrives in one more turn. Vague feedback ("make it better," "I don't like this") burns a turn without narrowing anything — the model has nothing concrete to change.

If a plan needs more than two rounds of rejection, that's usually a sign the underlying task description was underspecified, not that the model is failing. Go back and tighten the original prompt.

Executing the approved plan

Once you approve, Claude Code executes autonomously against the agreed plan — this is where you get the speed benefit back. You've front-loaded the judgment calls, so execution doesn't need per-file check-ins.

Still worth doing:

  • Watch the first two or three file edits land. If the first edit already diverges from the plan's stated approach, stop and ask why — better to catch drift at file one than file twenty.
  • Let it run to a natural checkpoint (a passing test suite, a completed migration step) rather than interrupting mid-file.
  • After execution, review the diff as a whole, not edit-by-edit — you already reviewed the intent, now you're checking that intent was executed faithfully.

A realistic before/after on a mid-size refactor

For a recent client project moving five components off inline styles onto CSS variables (see our styling rules for the pattern we standardized on), skipping plan mode meant three separate correction rounds after the fact — a shared variable got renamed inconsistently across two files, and one component's RTL logical-property conversion was silently skipped. Running the same task through plan mode surfaced the naming inconsistency risk and the RTL gap in the plan itself, before a single file changed. Net time was roughly the same; the difference was zero post-hoc cleanup commits.

Plan mode and your CLAUDE.md

Plan mode reads project rules the same way normal execution does, but it's a better place to catch when your CLAUDE.md or .claude/rules/*.md files are stale. If a plan proposes something that contradicts a rule file, that's either a bug in the plan or a rule that's out of date — plan mode surfaces the conflict before code exists, which is much cheaper to fix than after. If you're not sure your rule files are even being picked up, that's worth auditing separately — see writing effective CLAUDE.md memory.

Combining plan mode with subagents

For genuinely large changes — a full-page redesign, a hosting migration — a single plan can get unwieldy. One pattern that works well: use plan mode to produce the top-level plan, then have that plan explicitly delegate investigation-only sub-tasks to subagents ("agent A investigates current test coverage, agent B investigates the current deploy pipeline"), and only bring the findings back into a second, refined plan before any execution begins. This keeps the context window of the main thread from bloating with exploration noise while still getting you one clean go/no-go decision point.

FAQ

Does Claude Code plan mode work with headless/non-interactive runs?

Not the same way — headless runs (via -p flag or SDK) don't have an interactive approval step, so "plan mode" there means asking the model to output a plan as text and stopping, then a separate script or human reviews it before triggering execution. If you're building this into CI or a scheduled job, see headless Claude Code automation for how approval gates are typically implemented there.

How is plan mode different from just asking Claude Code to "explain your approach first"?

Functionally similar in spirit, but plan mode enforces the read-only constraint at the tool level — the model literally cannot call Write or Edit while in plan mode, so there's no chance of it "explaining" while quietly already having made a change. Asking nicely relies on the model choosing not to act; plan mode removes the option entirely.

Does using plan mode cost more tokens or money?

Slightly more, because the exploration phase (reading files, grepping) happens whether or not you end up approving the plan, and a rejected plan means a second exploration-plus-plan round. In practice this is a rounding error next to the cost of a bad autonomous edit that has to be manually reverted. If token spend is a real concern on your account, pair plan mode with the practices in Claude Code token cost control.

Can I make plan mode the default instead of toggling it every session?

Yes — set the default permission mode in your settings rather than toggling per session; see Claude Code permissions and safety for how permission modes are configured project-wide versus per-invocation.

Is plan mode useful for non-developers doing vibe coding?

Yes, arguably more so — someone without the instinct to eyeball a diff and spot a problem benefits even more from a plain-English plan they can read before anything executes. If that's your situation, pair this with when to use vibe coding to calibrate which tasks are safe to run fully autonomously versus which deserve the plan-review step.

What happens if I approve a plan and then find a problem mid-execution?

You can interrupt at any point — the same as interrupting any Claude Code run — and either correct course with new instructions or roll back via version control. This is also why running plan-mode-approved changes on a clean git branch (or a git worktree if you're running multiple plans in parallel) matters: a mid-execution stop is trivial to recover from when everything is a git diff away from clean.

Getting this right on a real project

If you're rolling Claude Code out across a team or a codebase bigger than a side project, the plan-mode habit is one of maybe five workflow decisions that determine whether it saves time or creates cleanup work. We help teams set up that workflow — CLAUDE.md, permissions, plan-mode conventions — as part of broader AI-engineering advisory work. Book a free 30-minute call through the contact form or message us directly on WhatsApp.

Sources