Plan mode
Plan mode is the one where Claude can read your files and run commands to explore, but cannot change anything. It researches, then writes you a plan, and edits stay blocked until you approve it.
That is a small mechanical difference and a large practical one. In the normal loop you review a change. In plan mode you review an intention, before any code exists to be attached to it. Intentions are much cheaper to argue with.
You get in three ways: Shift+Tab until the indicator says plan, /plan in front of a
single prompt, or from the start:
claude --permission-mode plan
Shift+Tab again leaves without approving anything.
One test, done twice
Stockroom has one failing test left:
FAIL test/util.test.ts > dates > gives the day a local timestamp falls on
AssertionError: expected '2026-03-03' to be '2026-03-04'
dayKey("2026-03-04T09:12:00+13:00") returns 2026-03-03. Nine in the morning in Auckland
is the previous evening in UTC, dayKey formats in UTC, and the day comes out wrong. The
tests pin TZ to Pacific/Auckland in vitest.config.ts, so this fails the same way on
everyone’s machine.
First, without a plan. In a normal session, ask for the fix. You will probably get a
change to dayKey, and there is a good chance you also get changes to startOfDay and
endOfDay, because they sit directly underneath it in the same file and they use local
time while dayKey uses UTC. That inconsistency is right there on the screen and it looks
exactly like part of the bug.
Now the same thing in plan mode. Reset first:
git checkout -- src/util/dates.ts
Then, in plan mode:
The test "gives the day a local timestamp falls on" in test/util.test.ts fails.
Work out what to change in src/util/dates.ts. Check who calls each function in that
file before you decide.
The plan should tell you something the other run did not: startOfDay and endOfDay are
exported and called by nothing. Not by src, not by test.
grep -rn "startOfDay\|endOfDay" src/ test/
src/util/dates.ts:15:export function startOfDay(iso: string): Date {
src/util/dates.ts:22:export function endOfDay(iso: string): Date {
Two definitions and no callers. So the fix is one function, not three, and the inconsistency that made the bug look bigger is between the live code and two pieces of dead code.
That is what the plan bought you: the same fix, two functions’ worth of change you now know not to make, and the discovery that there is dead code in that file.
Reading a plan
When the plan is ready you get three choices:
- Yes, and use auto mode - approve, and let the classifier take over the prompts. If auto mode is not available to your account this reads Yes, auto-accept edits instead.
- Yes, manually approve edits - approve, and go back to seeing each change. This is the one to use while you are learning.
- No, keep planning - stay in plan mode and say what is wrong.
Approving exits plan mode, so the session starts editing straight away in whichever mode
you picked. To plan again, cycle back with Shift+Tab.
Ctrl+G opens the plan in your editor. Use it when the plan is nearly right: deleting the
step you do not want is faster and more precise than three rounds of explaining which step
you meant.
What to look for in a plan, in order:
- The file list. This is the highest-value line in the whole thing. If it names a file you did not expect, find out why now. If it is missing a file you know is involved, the research did not go deep enough and the plan is guessing.
- The order. A plan that changes the callers before the thing they call is a plan that cannot be stopped half way.
- What it says it will not do. A plan with no boundaries usually acquires some while it runs.
- The size. Fourteen steps for a two-file change means it has planned the work of understanding the code as well as the work of changing it, and you are about to approve both.
When is planning ceremony?
Not often enough is a real failure mode, and too often is a real failure mode, and the second one is the one nobody warns you about.
Plan first when the change touches more than about three files, when you cannot yet name every file it should touch, when the naive fix is probably wrong, or when you are working in code you do not know. Those are the cases where a wrong direction costs a review instead of a sentence.
Skip it for a one-line fix, for anything you would happily revert with
git checkout --, for exploratory changes you are going to throw away anyway, and for
anything where you already know the exact diff you want. Planning a one-line change costs
you a round trip and gives you a paragraph describing a line.
The tell that you are over-planning: you are approving plans without reading them. A plan you skim is worse than no plan, because it feels like review.
If you want it always on for a project, put it in .claude/settings.json:
{
"permissions": {
"defaultMode": "plan"
}
}
Lesson 18 is about that file properly.
One thing worth knowing before it surprises you: plan mode does not mean nothing runs. Claude runs commands to explore, and if auto mode is available to your account the classifier approves those commands rather than prompting you. Reads and greps, mostly. But “cannot edit my files” and “will not execute anything” are different promises, and plan mode only makes the first one.
Your turn
src/reports/index.ts is 335 lines and seven reports. Split it, in plan mode.
The rule that makes this checkable: nothing outside src/reports/ may change. The CLI, the
server and the tests all import from src/reports/index.ts, and they should carry on
importing from there afterwards.
Split src/reports/index.ts into one file per report, in src/reports/. Keep index.ts as
a barrel that re-exports everything, so src/cli/main.ts, src/server/main.ts and
test/reports.test.ts do not have to change. Find every importer before you plan.
Read the plan before approving it. Specifically: does it list all three importers? Does it say index.ts stays? If either is missing, choose No, keep planning and say so.
Check:
npm testreportsTests 86 passed (86),npx tsc --noEmitprints nothing,wc -l src/reports/index.tsis under 40, andgit status --shortshows changes only undersrc/reports/. Ifsrc/cli/main.tsis in that list, the barrel is not doing its job.
This is the exercise in this course most likely to leave you somewhere confusing, because
it moves code between eight files. If the tests will not go green and you have lost the
thread, git reset --hard after-lesson-12 puts you back at the start of it. Compare with
git diff after-lesson-12 after-lesson-14 once you have finished, and see how somebody
else split the same file.
Then commit it, the way lesson 12 asked:
git add -A && git commit -m "Split the reports module behind a barrel"
Recap
Plan mode reads and explores but cannot edit until you approve a plan. Shift+Tab or
/plan gets you in, Shift+Tab gets you out, Ctrl+G edits the plan directly.
The value is finding out what a change touches before anything is touched, which is why the file list is the part of a plan worth reading closely.
Plan for multi-file work and unfamiliar code. Do not plan a one-line fix. And if you are approving plans without reading them, you have stopped planning and started performing it.
Next: the file that tells Claude what it needs to know about your project before you have to say it again.