Plan Mode

Read-only research mode for designing changes before touching the codebase. When to enter, how to write a good plan, when to exit.

Feature Foundational
9 min read
plan-mode planning permissions workflow

What it is#

Plan mode is a permission mode that disables all side-effecting tools — Edit, Write, Bash, and any MCP tool that mutates state. The model can still Read, Grep, Glob, WebFetch, and delegate to sub-agents. The result is a Claude that can research and reason as deeply as it wants but cannot touch your filesystem until you explicitly leave the mode.

Entering plan mode usually ends with the model producing a structured plan document — a numbered list of steps, each describing a specific change, with files and rough line counts. You review the plan, push back where it’s wrong, accept where it’s right, then exit plan mode and let the model execute. The output of a good plan-mode session is not changed code; it is a plan you trust.

This is the most important workflow feature for non-trivial changes. Skipping it on a 12-file refactor is how you end up with a half-done branch and a confused session.

When to use it#

Use plan mode whenever the cost of “Claude got it wrong” is higher than the cost of an extra fifteen minutes of planning. That includes:

  • Changes spanning more than ~3 files. The probability that the model’s first instinct is exactly right drops fast with scope.
  • Anything touching schemas, migrations, or auth. These have load-bearing semantics that are hard to fix after the fact.
  • Refactors where the destination is the question. “Split this module into two” is fine as intent; the model needs to plan which two before it starts moving code.
  • Unfamiliar codebases. Use plan mode for the first hour of any new repo — the reads it does are useful in their own right, even if you discard the plan.
  • Production bug investigations. Read everything, theorise, produce a fix plan, then exit. Don’t let the model patch live until you’ve seen its theory.

Skip plan mode for:

  • Trivial single-file edits.
  • Lint fixes, type fixes, mechanical sweeps where the change is obvious.
  • Exploratory questions that don’t need a plan (“what does this function do?”).
  • Continuation turns inside a session that’s already mid-execution.

The instinct most engineers develop after a month: plan mode for the first turn of any session that smells like a real piece of work; skip it on follow-ups.

How it works#

Entering and exiting#

There are three ways to enter plan mode:

  1. Shift-Tab — toggle the permission mode chooser in the TUI; pick “plan.” This is the keyboard path.
  2. --permission-mode plan — start the session in plan mode from the command line. Useful for scripted entry points.
  3. /mode plan — slash command from inside a running session.

The session header changes to indicate plan mode (often a distinct colour and a banner). Any attempt by the model to call Edit, Write, or Bash returns a structured rejection (“blocked by plan mode”) that the model handles by adapting its plan instead of trying again.

To exit, switch to a different mode the same three ways (Shift-Tab, --permission-mode default, or /mode default). The conversation continues with the same context — every file you read in plan stays in context for the executing turns. That continuity is the whole point: research done in plan mode is not wasted when you switch.

What a good plan looks like#

A useful plan-mode output is not prose; it is a structured document the model writes to the conversation (and optionally to a real file). The shape that consistently produces good downstream execution:

## Plan: rename `Foo` to `Bar` across the backend
### Files to change (5)
1. `src/foo.ts` — rename file to `src/bar.ts`, update exports
2. `src/foo.test.ts` — rename to `src/bar.test.ts`, update imports
3. `src/index.ts` — update barrel export
4. `src/api/routes.ts` — update one import + one route handler name
5. `docs/architecture.md` — replace `Foo` references with `Bar`
### Risks
- The string `foo` appears in three log lines that aren't load-bearing —
rename for consistency but no functional risk.
- One CSS class is `foo-button`; out of scope for this change.
### Verification
- `pnpm test` — all suites should pass
- `pnpm lint` — zero new violations
- Grep for `Foo` post-change: should return zero hits in `src/`

The shape matters: file-level granularity, an explicit risks section, an explicit verification section. If the plan is “I will rename Foo to Bar across the codebase,” that’s not a plan, it’s an intent. Push back until the file list and verification steps appear.

Reading-heavy planning#

In plan mode, the model is encouraged to read more aggressively than it would otherwise. It’s free of the cost of confirming each read (in default mode, reads auto-approve anyway, but the model can be conservative). A good plan-mode session might read 15-30 files, which sounds like a lot but is exactly what produces a plan that holds up.

If the repo is large enough that 30 reads would burn the context window, delegate to an Explore sub-agent — it does the broad read in its own context and returns a summary. The parent session stays clean for the plan itself.

Configuration#

Plan mode has very few knobs because most of its behaviour is structural — it’s a permission mode, not a tunable feature.

SettingWhereDefaultPurpose
permissions.defaultModesettings.jsondefaultSet to plan to start every session in plan mode. Rare; most users prefer to opt in.
permissions.planMode.allowBashsettings.jsonfalseAllows specific read-only Bash patterns (e.g. git status, ls) inside plan mode. Useful but easy to misuse — only allow truly read-only commands.
permissions.planMode.outputFilesettings.jsonnullIf set, the plan is also written to this file when the model produces one. Useful for plans you want to keep alongside the code.

The planMode.allowBash field deserves a comment: by default plan mode blocks all Bash because Bash can do anything. But git status, ls, and cat -n are pure-read operations. Allowing them makes plan mode much richer (the model can check git state, list directories) without giving up the safety. Add only commands you can prove are side-effect-free.

Examples#

A plan-mode session for a real refactor#

$ claude --permission-mode plan
> We want to split src/auth.ts into src/auth/session.ts and
src/auth/tokens.ts. Read it, the tests, and any callers, and
produce a plan.
[Claude reads auth.ts, auth.test.ts, and 7 caller files. Greps for "auth/".]
I've read the module. Here is the proposed split:
## Plan: split src/auth.ts into session + tokens
### Files to change (4)
1. Create src/auth/session.ts (~110 lines moved from auth.ts)
2. Create src/auth/tokens.ts (~80 lines moved from auth.ts)
3. Delete src/auth.ts, replace with src/auth/index.ts re-exporting both
4. Update 7 importers from "../auth" → no change needed; barrel preserved
### Risks
- The function `refreshToken` calls into `validateSession` — they end up
in different files. New cross-file import.
- Tests use `import { validateSession } from "../auth"` — barrel re-export
keeps this working without test changes.
### Verification
- pnpm test
- pnpm lint
- diff between old auth.ts and new files should net-zero meaningful code
> Looks good. Exit plan mode and execute.
[Claude switches mode and runs the plan.]

The conversation flow above is the standard one. Notice the plan is concrete (file names, line counts, identified risks) and the verification is explicit. Both reduce the surface for surprises during execution.

Plan mode as a code-review tool#

A second pattern: use plan mode to review a colleague’s PR.

$ git checkout their-branch
$ claude --permission-mode plan
> Read the diff vs main on this branch. Produce a review:
what's good, what's risky, what's missing.

The model reads the diff, the changed files, and any callers. It can’t run tests (plan mode blocks Bash unless allowlisted), but it can read the test files and reason about coverage. The output is a structured review you can paste into the PR.

Gotchas#

  • Plan mode is not “read-only mode for everything.” Sub-agents you delegate to inherit the parent’s mode by default but can be configured to escape it. Check your sub-agent definitions if you want airtight plan-only behaviour.
  • The plan is in conversation context. Exiting plan mode does not “save the plan” anywhere unless you configured outputFile. If you want a durable plan, ask Claude to write it to a file inside the project before you exit — that one Write is the only one allowed (it’ll need to be the first action post-exit), or use outputFile.
  • /clear after planning wipes the plan. The plan lives in conversation context. If you clear and start over, the plan is gone. Save it to a file first if it took real work to produce.
  • Plan mode disables the auto-test loop that some workflows rely on. If your CLAUDE.md says “always run tests after edits,” that’s a no-op in plan mode (no edits happen, no tests run). Don’t read the silence as a success signal.
  • Hooks still fire. A PreToolUse hook that logs every tool call will log all the Reads, Greps, and Globs from plan mode. Fine for audit purposes; surprising the first time you see a 200-line hook log from “just a planning session.”
  • A great plan can still be wrong. The model is reasoning from what’s in context. If it didn’t read the key file, the plan misses the constraint that file would have surfaced. Push back: “did you check how X uses this?” is the most useful follow-up.
The one-line habit that doubles plan-mode value

When the model produces a plan, before you say “go,” ask: “what’s the riskiest step, and what could go wrong with it?” The model will reread the plan with that lens and frequently catch something it would have walked into mid-execution. The whole follow-up costs one turn and one small read; it routinely saves a half-hour of rollback.

Search ESC

Keyboard shortcuts

Shortcuts are disabled while typing in inputs.