Blog

Claude Code planning mode

I've been building Vistaclair, an inspector that intercepts every API call Claude Code makes to Anthropic's servers. After watching hundreds of sessions, I've accumulated a detailed picture of how Claude Code's planning system actually works under the hood — and it's more layered than the docs suggest.

There are two distinct planning mechanisms in Claude Code: plan mode and the Plan subagent. They look similar from the outside, but they serve different roles and operate at different levels of the architecture. Most people conflate them. This post pulls them apart.

The Two Mechanisms at a Glance

Plan Mode vs Plan Subagent — Two Layers of the Same System PLAN MODE User-facing permission state EnterPlanMode Read-Only Lock Phase 1: Explore Phase 2: Design Phase 3: Review Phase 4: Write Plan 📄 Plan file ~/.claude/plans/*.md ExitPlanMode → user approval PLAN SUBAGENT Internal worker spawned by Agent tool Agent({ subagent_type: "Plan" }) Spawned during Phase 2 Tools: Read, Grep, Glob, Bash (readonly) No: Edit, Write, Agent, ExitPlanMode Returns: detailed implementation plan as tool_result text to parent Transparent to user — no approval gate spawns during Phase 2
Plan mode is the outer permission envelope; the Plan subagent is the internal research worker that runs inside it.

Plan mode is a permission state for the entire conversation. When active, Claude cannot edit your code — it can only read files, run exploratory commands, and write a single plan file. The user must approve the plan before implementation begins.

The Plan subagent is a specialized worker that Claude spawns (via the Agent tool with subagent_type: "Plan") to do architectural design work. It runs inside plan mode during Phase 2, returns a detailed plan as text, and the parent assistant writes it to the plan file.

They're complementary, not competing. Plan mode is the safety container. The Plan subagent is the thinking engine inside it.

How Plan Mode Works Internally

When Claude decides a task needs planning (or you press Shift+Tab to force it), it calls the EnterPlanMode tool. This is a tool call with zero parameters — it just signals intent:

{
  "type": "tool_use",
  "name": "EnterPlanMode",
  "input": {}
}
EnterPlanMode is the simplest tool call in Claude Code — empty input, massive behavioral change.

The harness responds with a tool result that does two things: confirms entry, and injects a massive <system-reminder> that rewrites Claude's behavioral constraints for the rest of the planning phase.

The system-reminder that changes everything

This is the part most people never see. When I intercepted the actual tool result, it contains a detailed workflow specification. Here are the key sections, straight from the wire:

system-reminder (excerpt)
Plan mode is active. The user indicated that they do not want
you to execute yet -- you MUST NOT make any edits (with the
exception of the plan file mentioned below), run any non-readonly
tools (including changing configs or making commits), or otherwise
make any changes to the system. This supercedes any other
instructions you have received.

## Plan File Info:
No plan file exists yet. You should create your plan at
/home/hp/.claude/plans/abstract-puzzling-cook.md using the
Write tool.
The hard constraint: no edits except one file. Note the randomly-generated slug name for the plan file.

That line — "This supercedes any other instructions you have received" — is doing heavy lifting. It's a priority override that prevents any earlier system prompt from convincing Claude to make edits during planning. It's the same pattern used in security-critical prompt engineering: a late-injected instruction that explicitly claims precedence.

Random plan file slugs
Each plan gets a randomly-generated three-word slug like abstract-puzzling-cook.md or elegant-flowing-river.md. These live in ~/.claude/plans/. I've accumulated over 100 of them across sessions. They're never cleaned up automatically, which is actually useful — you can go back and read old plans to understand past decision-making.

The five-phase workflow

The system reminder doesn't just say "plan things." It prescribes a specific five-phase process with explicit rules about which agent types to use in each phase:

Plan Mode: The Five-Phase Workflow Phase 1 Understand Up to 3 Explore agents in parallel Phase 2 Design Up to 3 Plan agents in parallel Phase 3 Review Read critical files Verify alignment Phase 4 Write Plan Write to plan file (only edit allowed) Phase 5 Exit ExitPlanMode → approval Explore Subagent Rules • Max 3 agents in parallel • Use 1 for isolated known files • Use multiple for uncertain scope • "Quality over quantity" • Each gets specific search focus • ONLY Explore type in Phase 1 Plan Subagent Rules • Default: at least 1 for most tasks • Skip only for trivial changes • Up to 3 for complex tasks • Different perspectives per agent: simplicity vs perf vs maintainability root cause vs workaround vs prevention Exit Rules • Turn MUST end with either: AskUserQuestion (clarify) ExitPlanMode (done) • NEVER ask "Is this plan okay?" via text — only ExitPlanMode • Can include allowedPrompts
The five phases with explicit rules about which agent types are permitted in each.

A few things stand out about this design:

  • Phase 1 is locked to Explore agents only. You can't spawn a Plan agent during exploration. This forces a separation between information gathering and design — no premature solutioning.
  • Multiple agents per phase enable parallel perspectives. The system explicitly suggests different viewpoints: "simplicity vs performance vs maintainability" for new features, "root cause vs workaround vs prevention" for bug fixes.
  • The exit constraint is strict. Claude's turn must end with either AskUserQuestion or ExitPlanMode. It's explicitly told never to ask "Is this plan okay?" as a text message — that phrase must go through the tool. This prevents plan mode from degenerating into open-ended conversation.

The Plan Subagent Up Close

When Phase 2 arrives, Claude spawns a Plan subagent. Here's what that actually looks like on the wire:

{
  "name": "Agent",
  "input": {
    "subagent_type": "Plan",
    "description": "Design implementation plan",
    "prompt": "Design an implementation plan for optimizing...
      Here's the full context:\n\n## Problem Statement\n...
      ## Specific Bugs Found\n### Bug 1: ...\n\n
      ## Key Files to Modify\n- db.js\n- routes.js\n...
      Please provide a detailed implementation plan
      with specific code changes needed for each file."
  }
}
A real Plan subagent invocation from my session data — the prompt is extensive, often 3,000+ words.

The Plan subagent has a restricted tool set — it gets Read, Grep, Glob, and read-only Bash, but no Edit, Write, Agent, or ExitPlanMode. It can look at code but can't change it, and it can't spawn its own subagents (preventing infinite nesting).

What comes back is a structured implementation plan, often with specific file paths, line numbers, code snippets, and a phased approach. In the session I inspected, the Plan subagent returned a 5-phase plan covering backend changes, frontend modifications, bug fixes, and a specific implementation sequence — all from a single prompt.

The prompt is the secret weapon
The quality of the Plan subagent's output depends almost entirely on how much context the parent Claude packs into the prompt. In the best sessions I've observed, the Phase 1 Explore agents feed back detailed findings (specific line numbers, function signatures, data flow paths), and the parent distills all of that into the Plan agent's prompt. Garbage in, garbage out — but detailed context in, surgical plan out.

ExitPlanMode: The Approval Gate

Once the plan is written to the plan file, Claude calls ExitPlanMode. Unlike EnterPlanMode (which requires no permission), exiting does require user approval. This is an asymmetric design: easy to enter planning, hard to leave it.

{
  "name": "ExitPlanMode",
  "input": {
    "allowedPrompts": [
      {
        "tool": "Bash",
        "prompt": "run node scripts to measure/test interaction sizes"
      }
    ]
  }
}
ExitPlanMode can pre-authorize specific Bash commands the plan needs, reducing permission prompts during implementation.

The allowedPrompts field is a detail I haven't seen documented anywhere. It lets Claude request pre-authorization for specific types of Bash commands that the plan will need. In this case, the plan involved measuring WebSocket message sizes, so it pre-authorized scripts for that purpose.

When the user approves, they get options:

  1. Approve and start in auto mode — Claude implements autonomously
  2. Approve and accept edits — Claude implements, auto-accepting file edits
  3. Approve and review each edit — Full manual review of every change
  4. Keep planning — Stay in plan mode with feedback
  5. Refine with Ultraplan — Send to a cloud session for browser-based review
ExitPlanMode → User Approval Flow ExitPlanMode() + allowedPrompts[] User decides Auto mode Autonomous implementation Accept edits Auto-accept file changes Review each edit Full manual control Keep planning Iterate with feedback Ctrl+G opens plan in your text editor for direct editing
The approval flow gives you five levels of trust — from full autonomy to continued iteration.

Why the System Instructions Work So Well

After reading through dozens of plan mode transcripts, I've identified several prompt engineering patterns in the system instructions that make plan mode effective. These aren't obvious — they're the kind of thing you only notice when you compare successful planning sessions to ones that went off the rails.

1. The precedence override

you MUST NOT make any edits ... or otherwise make any changes
to the system. This supercedes any other instructions you have
received.
The nuclear option: explicit precedence claim.

This single sentence prevents a whole class of failures. Without it, a CLAUDE.md file could say "always auto-commit after edits" and Claude might honor it even during planning. The precedence override is the difference between a suggestion and a hard constraint.

2. Forced termination conditions

This is critical - your turn should only end with either
using the AskUserQuestion tool OR calling ExitPlanMode.
Do not stop unless it's for these 2 reasons.
No open-ended conversations allowed.

This prevents Claude from writing a plan in text and then just... stopping. By forcing every turn to end with a tool call, the harness can programmatically detect the state transition and show the right UI (approval buttons, plan viewer, etc.).

3. Anti-pattern prohibition

Phrases like "Is this plan okay?", "Should I proceed?",
"How does this plan look?", "Any changes before we start?"
or similar MUST use ExitPlanMode.
An explicit list of natural-language patterns that must be channeled through the tool instead.

This is clever. Claude naturally wants to ask "Does this look good?" as a text message. But that would bypass the structured approval flow. By listing the exact phrases and redirecting them, the instructions channel conversational instincts into the programmatic path.

4. The single-file exception

NOTE that this is the only file you are allowed to edit -
other than this you are only allowed to take READ-ONLY actions.
One exception to the no-edit rule — the plan file itself.

This is a pragmatic compromise. If Claude couldn't write anything, it would have to hold the entire plan in its context window — which burns tokens and risks truncation on long plans. Allowing exactly one file to be written gives Claude persistent storage for the plan without opening the door to code changes.

A Real Plan Mode Session, End to End

Here's what a complete plan mode session looks like in my inspector. This one was about reducing a 75 MB WebSocket initialization message — a real problem I hit in Vistaclair itself:

Real Session Timeline: "Reduce 75 MB WebSocket Init Message" EnterPlanMode() → Harness injects 5-phase workflow + assigns plan file: abstract-puzzling-cook.md Tools locked to read-only Phase 1 → Explore Agent "Explore init message client consumption" Searched inspector.js: renderTimeline(), isNewUserTurn(), extractToolCalls() Returned: field-level analysis of which data each function needs (5 detailed tables) Phase 1 (cont.) → Read extractToolCalls inspector.js lines 455-515 — verify what response.body.content needs Phase 2 → Plan Agent (implicit) Parent synthesizes exploration findings into design decisions Designed: summarizeForInit(), interaction:getDetail lazy-loading, image truncation fix 4 implementation steps, 3 files to modify, expected result: 75 MB → <500 KB Phase 4 → Write Plan File Write ~/.claude/plans/abstract-puzzling-cook.md Context section, 4-step plan, file list, verification checklist Phase 5 → ExitPlanMode({ allowedPrompts }) Pre-authorizes: "run node scripts to measure sizes" User approval required to proceed ✓ User approved plan → System reminder: "Exited Plan Mode. You can now make edits..." Implementation begins Plan file remains at ~/.claude/plans/abstract-puzzling-cook.md for reference t=0 ~30s ~90s ~2min Session: 5f1ba6c8 • Files: 304.json, 554.json • Plan: abstract-puzzling-cook.md
A complete plan mode session as captured by Vistaclair — from EnterPlanMode to approved implementation.

When to Use Each Mechanism

Here's my practical take after watching both mechanisms across hundreds of sessions:

ScenarioUseWhy
Complex multi-file refactorPlan mode (Shift+Tab)You want the full approval workflow, the plan file for reference, and the safety of read-only constraints
Quick architectural decisionPlan subagent directlyYou just need Claude to think through an approach — no approval gate needed
Unfamiliar codebasePlan modeThe 5-phase workflow forces thorough exploration before design
Adding a feature you understand wellNeitherJust build it. Planning adds overhead when you already know the path
Bug with unclear root causePlan modePhase 1 exploration is perfect for investigation before committing to a fix strategy
When to use plan mode vs plan subagent vs neither.
Plan mode has real overhead
Every plan mode session I've observed adds 2-5 minutes of exploration and design before any code is written. The Explore and Plan subagents each make their own API calls. For a task where you already know exactly what to change, that's wasted time and tokens. Save plan mode for genuine uncertainty.

Gotchas and Observations

  • Plan files accumulate forever. There's no garbage collection on ~/.claude/plans/. After a few months of heavy use, I had 100+ plan files. They're small (a few KB each), but it's worth knowing they're there.
  • The Plan subagent can't spawn sub-subagents. This prevents recursive planning spirals but also means a Plan agent can't delegate research to an Explore agent. All exploration must happen in Phase 1.
  • EnterPlanMode requires no permission but ExitPlanMode does. This asymmetry means Claude can decide to plan on its own, but it can never decide to start implementing on its own. That's a deliberate trust model.
  • The tool description lists 7 specific conditions for when to use plan mode. These range from "New Feature Implementation" to "User Preferences Matter." Claude is trained to evaluate these before every non-trivial task.
  • Ultraplan exists for truly large plans that benefit from browser-based review with inline comments. I haven't used it much, but it sends the plan to a cloud session and gives you a collaborative review UI.

The Takeaway

Claude Code's planning system is more structured than it appears. Behind Shift+Tab there's a carefully designed workflow with hard permission boundaries, forced agent types per phase, structured approval gates, and system instructions that explicitly override other prompts.

The separation between plan mode (the permission container) and the Plan subagent (the thinking engine) is the key insight. They're designed to work together — plan mode provides safety, the Plan subagent provides depth. You can use the Plan subagent without plan mode for lighter-weight planning, or you can use the full plan mode workflow when you need the guardrails.

If you're using Claude Code for anything non-trivial, spending 2 minutes in plan mode before a complex task is almost always worth it. The plan file alone — sitting in ~/.claude/plans/ as a record of the thinking process — has saved me from bad implementations more than once.

Comments

No comments yet.

Leave a comment

We use analytics cookies. Privacy