Between "understand" and "change" stands a separate phase, and mixing them is a costly mistake. Plan mode exists precisely to separate exploration from implementation: in it Claude reads files and runs recognized read-only shell commands but does not change sources. It is enabled by switching Shift+Tab to Plan mode or with the /plan command and a task statement. The result is a plan you approve before a single file is touched.
It is important to understand that plan mode is a mode of analysis, not hidden implementation. If auto mode is available and useAutoModeDuringPlan is enabled, the classifier may allow additional commands, but the essence of the mode does not change: it serves understanding, not change. This is a technical guarantee that the exploration phase will not quietly turn into edits - but the guarantee does not remove the need for a clear task, which the mode itself does not replace.
A good plan is recognizable by its specifics. It has an observable cause with evidence, a list of files and symbols to be changed, the sequence of changes, the question of migration and backward compatibility, a test that first fails or explicitly fixes a regression, verification commands, rollback conditions and, separately, the unknowns requiring your decision. A three-line plan of "update the service, add a test, check" gives no point of control: it cannot be judged by what exactly will happen.
If the plan came out general, the specifics are worth requesting explicitly. Below is a wording that forces each step to be spelled out: the exact file, symbol, expected contract change and verification, and separately the assumptions not yet confirmed by the code. It is the externalized assumptions that matter most: they show where the plan stands on a guess rather than on read code, and where you may need to intervene before, not after, implementation.
Accepting a plan is a point of directional control, and it is passed consciously. Before moving to writing you check git status; if another agent works in parallel, you take a separate worktree. Then you leave plan mode, approve the plan and explicitly restate the boundaries - which steps to implement, what not to do (migration, changing the public schema) and where to stop to show the diff. Restating boundaries at approval is cheaper than rolling back extra changes already made.
It helps to see once what approving a plan with explicit boundaries looks like. Below is a short wording: implement specific steps, do not touch migration and the public schema, stop after the focused tests and show the diff. You return to this form at every transition from plan to code: it turns approval from a vague "go ahead" into a precise command with set limits.
# Approving a plan with explicit boundaries
Plan accepted. Implement steps 1-3. Do not run migration and do not change
the public schema. After the focused tests, stop and show the diff.Exploring large codebases obeys the same narrow-context principle. You do not ask to read the whole monorepo - you give an entry point and ask to expand the scope only along dependency edges: start with a specific file, trace the direct calls, types and related tests and do not index the other packages until a concrete dependency leads there. So the context stays cheap and relevant rather than bloated with everything at once.
Structural means help with this too: code intelligence or an LSP for navigation, nested CLAUDE.md at the package level, path-scoped rules and per-package skills. They reduce grep errors and the cost of context, directing the agent's attention pointwise. The typical failure of this phase is letting the agent immediately edit poorly understood code or approving a plan of general phrases with no files and checks; the right move is a map and a concrete plan first, then approval with boundaries.
# Force the plan to be concrete
For each plan step name the exact file, symbol, expected contract change
and verification. Separately list the assumptions not yet confirmed by
the code.