Seeing the diff before the diff with plan mode

Day 1: From chat to spec · Lesson 3 of 6 · 11 min

Changing your mind in an agent run is cheap in exactly one place: before the first edit lands. In plan mode that place stays open — the agent reads your code, works out what it would do, and writes a proposal instead of a diff. Nothing in your working tree moves until you answer the prompt it puts on screen — with one exception, below.

Watch first · 3 min

The Explore → Plan → Code → Commit workflow in Claude Code

Claude, 2026-05-17, 3 min 11 s. Watch the seam between the second step and the third: that seam is what this lesson is about. The plan is expected to carry success criteria before any code is written, so ask what you would have checked before letting it run.

What it is, and how you get in

Claude Code runs every turn under a permission mode, and the mode decides what the agent may do without asking you first. Three modes are always in the Shift+Tab cycle: default reads and asks first, acceptEdits also applies file edits and common filesystem commands, and plan reads and proposes. The other three — auto, dontAsk and bypassPermissions — are set deliberately, and this lesson does not use them. The terminal shows you the label, not the config value: default reads Manual, and plan reads plan mode on.

In plan mode the agent is told to research and propose changes without making them: it reads files, runs shell commands to explore, and writes a plan, but does not edit your source. Edits stay blocked until you approve the plan, with the one exception in the note below.

The bypass-permissions exception

In an interactive terminal session with bypass permissions available, an edit the agent attempts while planning runs unprompted. Bypass permissions are meant for isolated containers and virtual machines only; if a file changes while a proposal is on screen, check for this first.

Three ways in. Shift+Tab cycles the modes. /plan in front of a prompt enters plan mode for that prompt alone. A whole session starts there with a flag:

claude --permission-mode plan

For a repository where you always want to look first, set the default in the file your team commits, .claude/settings.json, not the personal .claude/settings.local.json beside it:

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

Leaving is the keystroke you came in with: Shift+Tab exits without approving anything, and approving a plan exits into whichever mode your answer names.

The approval gate in plan mode Time runs left to right. On the left, before the gate, the agent reads files, asks questions and edits nothing, except in a session with bypass permissions available. A plan travels to a vertical barrier labelled the approval gate, where one plan waits. Three exits lead out of the gate: approve, in which edits apply; manual, in which each edit asks; and keep planning, which returns to the left side along a path below the gate, with no file changed yet. approval gate: one plan waits here before the gate reads files asks questions edits nothing plan approve edits apply manual each edit asks keep planning no edit yet no file has changed yet, unless bypass permissions are on
Reads and questions cross freely; a change to a file waits for your answer.

Editing the plan before you approve it

A proposal that is ninety percent right does not have to be thrown away. Ctrl+G opens the proposed plan in your default text editor: strike the step that is wrong, add the verification command it left out, save and close, and approve the version you edited.

The three answers

When the proposal is ready, the approval prompt offers three answers. The first approves and lets edits apply: Yes, and use auto mode, or Yes, auto-accept edits when auto mode is not available, or a bypass-permissions variant in a session that started with those enabled. The other two are Yes, manually approve edits and No, keep planning. The wording varies; what the answers mean does not.

Manual approval is the right default while you are learning what this agent reaches for in this repository. The third answer is an ordinary outcome, not a failure: one turn, no diff, the cheapest correction in the loop. Nobody rejects enough plans in their first week.

What to look for in a plan

Read a proposal for four things. The files it names: one you did not expect means it is solving a bigger problem than the ticket asked for. The verification command, and what it expects that command to print. The order of operations, because a plan that edits before it reads is guessing. And the omission: what you expected and did not see, usually the test.

A proposal with no command that could fail is an intention, not a plan. When you run these commands in Exercise 2, run them from inside day1-work, the copy of your lane that Exercise 1 makes at the course root; the shipped sandbox/ is never edited. The plan's verification command is the one you check hardest; your lane's plain test command guards the rest of the module:

Swift lane
swift test
Kotlin lane
./gradlew test

It is not always the command that can fail. LEDGER-7's test is held back behind a gate, so the plain command stays green with the bug in place; a plan that offers it as proof has named a command that cannot fail. The gated form sets one variable in front of your lane's command, and it is the one a LEDGER-7 plan must name:

Swift lane
LEDGER_RUN_KNOWN_ISSUES=1 swift test
Kotlin lane
LEDGER_RUN_KNOWN_ISSUES=1 ./gradlew test

Exercise 2 applies these four things to a real proposal on LEDGER-7.

Rejecting on evidence

A rejection is worth one sentence, and the sentence names the defect. Vague dissatisfaction produces a second plan with the same problem. Say what is wrong and what would make it right:

No. The ticket is about how amounts are rendered, and your plan edits
LedgerSummary and the fixtures file. Keep the change in the money
formatting path, and name the test command you will run to prove the
JPY case is fixed.

That answer restates the bounds and asks for the falsifiable part back. A useful team norm: paste the approved plan into the pull request description, so your reviewer reads the diff against the intent you approved.

When to skip it

For a two-line change in a file you know well, the round trip costs more than reading the diff would. Renaming a property, bumping a Gradle dependency, fixing an assertion you wrote yesterday: make the edit, read the diff, run the tests. Planning that work is ceremony, and ceremony is how a good practice gets abandoned in week three.

Skip it too when you want a conversation: while you are still deciding whether the change belongs in the model or the view, a proposal pushes you to commit early. The mode earns its turn when the change spans files, when the code is unfamiliar, or when a wrong edit costs more than a reset.

Quick check

The plan reads well but names no command that could fail. What is the right answer at the approval prompt?

No, keep planning, with one sentence asking for the verification command (for LEDGER-7, the gated form) and the output that would count as success. A plan with nothing falsifiable in it hands the finish line back to the agent.

One sentence of an otherwise good plan is wrong. What is faster than rejecting it?

Ctrl+G. Edit the plan yourself, then approve the version you edited. Rejection restarts the proposal; editing keeps the ninety percent that was already right.

Sources

Claude Code documentation, all accessed 2026-09-22 against version 2.1.280.