teachyou.ai academy
← All posts
Claude CodeAI coding assistantdeveloper toolsagentic codingcode review workflow

Claude Code Plan Mode vs Acting Directly

Pramod Dutta · Jul 6, 2026 · 11 min read

Claude Code plan mode is a read-only setting where the agent explores your codebase, writes up a step-by-step plan, and waits for your approval before it edits anything. Acting directly skips that pause: the agent reads a few files, then starts writing code immediately, checking in only when it hits a permission gate. Neither mode is "better" in the abstract. Plan mode buys you a checkpoint before changes land; acting directly buys you speed when the task is small enough that a checkpoint would just be friction. The rest of this article walks through when each one earns its keep, how to switch between them mid-session, and a worked example that shows the difference on a real refactor.

What Plan Mode Actually Does

When you toggle plan mode on (Shift+Tab in the terminal, or --permission-mode plan from the CLI), Claude Code restricts itself to read-only tools. It can still use Read, Grep, Glob, and run non-mutating shell commands, but Edit, Write, and any Bash command that changes state get blocked until you exit the mode. The agent uses that read-only window to build a mental map of the code: which files own the logic in question, what the call sites look like, what tests already cover the area, and what the blast radius of a change would be.

At the end of that exploration, it presents a plan, usually a short list of concrete edits tied to file paths, sometimes with a note about tradeoffs it considered and rejected. You can approve the plan as-is, ask for changes, or reject it outright and redirect. Only after approval does Claude Code drop into normal permission mode and start making the edits it just described.

The value of plan mode is not that the agent becomes smarter while planning. It is that you get a fixed point to review before any file on disk changes. For a one-line typo fix, that checkpoint is overhead. For a change that touches authentication, a shared utility used in twenty places, or a database migration, that checkpoint is the difference between catching a bad assumption in a chat message versus catching it in a diff after the fact.

Two failure modes plan mode does not solve on its own:

  • A plan can still be wrong if the agent misread the codebase. Reading the plan carefully matters as much as reading the diff would.
  • Plan mode does not shrink the actual scope of a task. If you ask for a plan on a genuinely huge refactor, you will get a huge plan, and reviewing a fifteen-step plan is its own kind of tedious.

When to Use Plan Mode

Reach for plan mode when the cost of a wrong first guess is higher than the cost of a short delay. In practice that maps to a handful of recurring situations.

Multi-file changes where you don't already know every file involved. If you know exactly which three files need to change, you can often skip the plan and just say so. Plan mode earns its cost when you are the one asking Claude Code to find the files, because that's exactly the step you want to review before it starts editing.

Anything touching auth, billing, or data migrations. These are the categories where a plausible-looking but wrong assumption (say, treating a soft-deleted row as gone, or missing a second place a JWT gets validated) is expensive to unwind. Reviewing the plan is cheap insurance.

Unfamiliar codebases. If you just cloned a repo and haven't built a mental model of it yet, plan mode doubles as free onboarding. Reading the agent's plan teaches you the shape of the code faster than reading the code cold.

Ambiguous requests. If your own instruction to the agent was underspecified ("clean up the error handling in the API layer"), plan mode forces the ambiguity to surface as a written plan instead of as a set of edits you have to reverse-engineer the intent of afterward.

Here's a prompt pattern that gets good plans out of Claude Code:

Enter plan mode. I want to move rate limiting from per-route
middleware into a single shared middleware keyed by user ID
instead of IP. Look at how rate limiting is currently wired in
src/middleware/ and src/routes/, and propose a plan that keeps
the existing 429 response shape.

Naming the constraint ("keeps the existing 429 response shape") up front means the plan the agent proposes already respects it, instead of you catching the violation during review.

When to Skip Plan Mode and Act Directly

Acting directly is the right default for anything where you already hold the plan in your head, or where the task is small enough that writing the plan out would take longer than just doing it.

Single-file, single-purpose edits. Fixing a bug you've already localized, adding a field to one form, renaming a variable inside one function. Asking for a plan here just adds a round trip.

Tasks with a tight, mechanical scope. "Add a disabled prop to the Button component and thread it through the three places that render it" doesn't need a planning phase; the scope is already the plan.

Iterative, exploratory work where you'll redirect anyway. If you're pairing with the agent in a tight loop, running it, looking at output, adjusting, plan mode's checkpoint doesn't fit that rhythm. You're already reviewing every step by watching the diffs land.

When you trust the blast radius. If the change is inside a module with strong test coverage and the tests will catch a bad edit before it ships, the plan-mode checkpoint is partly redundant with the test run you're going to do anyway.

A direct-action prompt for the same kind of task looks like this:

In src/utils/formatCurrency.ts, add support for a locale
parameter that defaults to "en-US". Update the two call sites
in src/components/PriceTag.tsx and src/components/Invoice.tsx
to pass the user's locale from the existing useLocale() hook.
Run the existing tests in formatCurrency.test.ts after.

Notice this prompt does the work a plan would have done: it names the files, the exact change, and the verification step. When your instruction already contains that much structure, plan mode has nothing left to add.

Switching Between Modes Mid-Task

You don't have to commit to one mode for a whole session. A common pattern is to start in plan mode for the parts of a task that are uncertain, then drop into direct action once the uncertain part is resolved.

Say you're adding a new background job. You're not sure whether the existing job queue supports delayed execution, so you start in plan mode:

Enter plan mode. I need a job that sends a follow-up email
72 hours after signup. Check whether our job queue (looks like
it's in src/jobs/) supports delayed execution, and if not,
propose how we'd add it.

The agent reads src/jobs/, finds that the queue library does support a delay option, and comes back with a three-step plan: add a new job file, register it in the job index, call it from the signup handler with a 72-hour delay. You approve it. Claude Code exits plan mode automatically once you approve and starts implementing.

If halfway through implementation you want to add a fourth piece of work that wasn't in the original plan, and it's small, you can just ask directly without re-entering plan mode: "also add a unit test for the delay calculation." That's a direct-action request layered on top of an approved plan, and it's a normal way to work.

Going the other direction, if you started in direct-action mode and the agent's first edit reveals the task is bigger than you thought, say so and ask it to switch: "hold on, stop editing, switch to plan mode and figure out how many other call sites this affects before you touch anything else." Claude Code will stop mutating files and go back to read-only exploration.

A Worked Example: Refactoring an API Client

Here's a concrete before-and-after that shows why the choice matters, not just in theory.

Task: an Express API client wrapper (src/lib/apiClient.js) currently retries failed requests with a fixed one-second delay. You want exponential backoff instead.

Acting directly, a reasonable first attempt might look like this:

async function requestWithRetry(url, options, retries = 3) {
  let attempt = 0;
  while (attempt < retries) {
    try {
      return await fetch(url, options);
    } catch (err) {
      attempt++;
      if (attempt >= retries) throw err;
      await sleep(1000 * Math.pow(2, attempt));
    }
  }
}

That's a correct implementation of exponential backoff in isolation. But if you skipped exploration, you might miss that sleep isn't imported anywhere in this file, that three other files call requestWithRetry with a fourth timeoutMs argument that this signature just dropped, and that there's already a withBackoff helper in src/lib/backoff.js written for exactly this purpose that the rest of the codebase uses. The edit works in a vacuum and breaks in context.

With plan mode, the same request produces something like:

Plan:
1. src/lib/backoff.js already exports withBackoff(fn, opts) -
   used by src/lib/dbClient.js and src/lib/emailClient.js.
   Reuse it here instead of writing new retry logic.
2. src/lib/apiClient.js: wrap the fetch call in withBackoff,
   passing through the existing timeoutMs option.
3. Three call sites in src/services/*.js call
   requestWithRetry(url, options, retries) - keep that
   signature as a thin wrapper around the new implementation
   so none of them need to change.
4. Add a test in src/lib/apiClient.test.js asserting delay
   grows exponentially, following the pattern in
   backoff.test.js.

The plan surfaces the existing withBackoff helper and the three call sites before a single line changes. Reviewing four bullet points here is faster than reviewing a diff that silently dropped a parameter and duplicated logic that already existed elsewhere.

Plan Mode and Permissions

Plan mode interacts with Claude Code's permission system rather than replacing it. Even after you approve a plan and the agent moves into normal mode, it still respects whatever permission rules are configured in settings.json, project-level allowlists, or --permission-mode flags you've set for the session. Approving a plan is not a blanket grant to do anything; it's approval of the specific steps written in that plan.

If you want plan mode as the default for a project, rather than something you toggle per session, set it in the project's Claude Code settings:

{
  "permissions": {
    "defaultMode": "plan"
  }
}

With that in place, every new session in the project starts read-only until you approve a plan, which is a reasonable default for shared repos where you want every session's first move to be reviewable, even ones kicked off by teammates who haven't built the same intuition yet for when to ask for a plan.

Common Mistakes

Asking for a plan on a task with no real ambiguity. If you already know it's a one-line change, asking for a plan just makes you review your own instruction reflected back at you. Skip it.

Approving a plan without reading it. The entire value of the mode collapses if you rubber-stamp the plan the same way you'd rubber-stamp a diff you didn't read. Read the file list and the stated approach, not just the step count.

Never using plan mode at all, even on risky changes. The opposite failure is treating direct action as the only mode because it feels faster. On anything touching money, auth, or data integrity, the few minutes a plan costs are cheap relative to unwinding a bad migration.

Writing vague plan requests. "Enter plan mode and improve the codebase" produces a plan that's vague because the request was vague. Name the specific area, the specific goal, and any constraints you already know about, the same discipline that makes a direct-action prompt good also makes a plan-mode prompt good.

FAQ

Does plan mode make Claude Code slower overall? It adds one review round trip before edits start, but it often saves time overall by catching wrong assumptions before they turn into a diff you have to unwind. For small tasks the round trip is pure overhead; for larger or riskier tasks it usually nets faster.

Can Claude Code run any commands while in plan mode? Yes, read-only ones. It can run Read, Grep, Glob, and shell commands that don't mutate state, like a linter in check-only mode or git log. Anything that writes to disk or changes state is blocked until you approve the plan and exit plan mode.

How do I toggle plan mode from the terminal? Shift+Tab cycles through permission modes in an interactive session. You can also start a session directly in plan mode with --permission-mode plan on the command line, or set defaultMode: "plan" in settings.json to make it the project default.

What happens if I reject a plan? Claude Code stays in plan mode and waits for new instructions. You can ask for a revised plan, point out what it missed, or narrow the scope, and it will explore again and propose an updated plan without having touched any files.

Is plan mode the same as a dry run? Close, but not identical. A dry run typically simulates the exact operation without changing anything. Plan mode is closer to a design review: the agent explores, reasons about the approach, and writes up what it intends to do, which may differ in detail from the final edits if new information comes up during implementation.

Should I use plan mode for every session by default? Only if most of your sessions involve ambiguity, multi-file scope, or high-risk areas. If your day-to-day work is small, well-scoped edits, defaulting to plan mode adds a review step that rarely changes the outcome. Turning it on situationally, or setting it as default just for sensitive directories, tends to fit better than an all-or-nothing rule.