You went into plan mode, Claude proposed a clean 5-step plan, you approved it. Execution starts. By the end, files D and E are edited (not in the plan), step 3 was skipped because “the existing code already does that” (it didn’t), and a “minor refactor for clarity” got smuggled into step 4. The PR is bigger than the plan and you can’t tell from the diff which changes were authorized.
Plan mode is a planning aid, not a contract. Approval gives you alignment at the planning step but doesn’t bind execution to the plan unless the prompt makes that binding explicit. The fix: treat the plan as a numbered checklist, require post-step confirmations, and reject any change outside the approved list.
Common causes
Ordered by hit rate, highest first.
1. Plan was loose — Claude inferred extra work
Plan said “update billing flow.” Doesn’t say which files. Claude updated 5 files including 2 you didn’t expect. The plan didn’t pin paths so any reasonable interpretation was authorized.
How to spot it: Re-read the approved plan. If steps reference concepts (“the billing flow”) not file paths, Claude had latitude to expand.
2. Original prompt had implicit “improve while you’re there”
You said “fix the bug AND clean up if you see issues.” The “AND clean up” is a license for scope creep. Claude planned the bug fix, then expanded execution to include cleanup it didn’t surface in the plan.
How to spot it: Search your prompt for “while you’re there,” “also fix,” “and improve,” “clean up.” Any of these authorize plan-overshooting.
3. Claude updated the plan silently mid-execution
The plan said 5 steps. Mid-execution Claude decided step 3 was unnecessary and skipped it without surfacing the change. Or it added a new step 6 because something looked broken along the way.
How to spot it: Compare actual diff to approved plan step-by-step. Discrepancies = silent plan updates.
4. Plan steps were too coarse
“Step 4: refactor billing.ts to use the new pattern” — what does that mean concretely? Claude can interpret broadly because the step didn’t specify.
How to spot it: Plan steps are 1-line abstractions (“refactor X for clarity”) rather than concrete operations (“rename processPayment to processCharge in billing.ts only”).
5. Edge-case discovered during execution
Claude found a real edge case while executing step 2. Instead of stopping and asking, it incorporated a fix as part of the step. Now the diff is bigger than the plan.
How to spot it: Diff for one step touches files / concerns the step didn’t mention. Edge-case sweep.
6. CLAUDE.md authorized opportunistic improvements
Some CLAUDE.md files say “improve code quality where you see issues” — that’s a standing authorization that overrides plan boundaries.
How to spot it: grep -i "improve\|clean up\|opportun" CLAUDE.md returns rules that let Claude expand scope.
Shortest path to fix
Ordered by ROI. Step 1 + 2 turn the plan into an enforceable contract.
Step 1: Make plan steps concrete + file-anchored
A useful plan step names files, symbols, and the exact change. Not abstractions:
Bad: "Step 3: Refactor billing logic for clarity."
Good: "Step 3: Rename `processPayment` to `processCharge` in src/billing.ts:42 and update 3 call sites (src/api/checkout.ts:87, src/jobs/billing-sweep.ts:23, src/services/refund.ts:55). No other changes."
A concrete step has a verifiable result. Abstract steps cannot diverge because they’re already too loose to diverge from.
Step 2: Bind execution with explicit “do not exceed” rule
After approving the plan, prepend execution with:
Execute ONLY the approved plan above.
- Do NOT add steps.
- Do NOT skip steps; if a step seems unnecessary, STOP and ask.
- Do NOT touch files outside the explicit paths in the plan.
- If you find issues outside the plan, list them at the end as TODOs — do NOT fix them.
After each step:
1. Paste a one-line summary of what changed.
2. Stop and wait for "proceed."
The “stop and wait” line per step is the contract enforcement.
Step 3: Diff actual changes vs planned scope mid-execution
After Claude finishes a step, before approving the next:
git diff --stat HEAD
Compare to the step’s explicit file list. Any extra file = scope creep. Revert and re-prompt:
Your step 3 touched files D and E, which weren't in the plan.
Revert those changes. Step 3 only touches src/billing.ts.
Step 4: Reject silent plan updates
If Claude announces “I’m going to skip step 3 because…” or “I’m adding step 6 to handle…”:
Plan changes require my approval. Stop.
Tell me what you propose to change and why.
I'll either update the plan or you keep going as planned.
This catches drift at the announcement, not after the code lands.
Step 5: Audit your prompt + CLAUDE.md for scope-creep authorizations
Search for and remove standing authorizations that override plans:
# In your prompts / CLAUDE.md, find:
grep -in "while you're there\|also fix\|opportunistically\|improve where you see" \
CLAUDE.md src/**/CLAUDE.md
Replace each with a tighter rule: “fix only what’s specified; flag other issues as TODOs.”
Step 6: For repeat divergence, use commit-per-step
Force Claude to commit after each plan step. Each commit’s diff is the auditable unit:
After each step:
1. git add <only-the-step's-files>
2. git commit -m "step N: <one-line summary>"
3. STOP
If `git status` shows unstaged changes after the commit, you exceeded the step.
A clean commit log per step makes “did you stick to the plan?” verifiable.
Prevention
- Plan steps name files + symbols + concrete operations; never “refactor for clarity”
- After approval, bind execution with “do not exceed this plan” + post-step status updates
- Audit CLAUDE.md and prompt templates for standing scope-creep authorizations; remove them
- Diff actual vs planned scope after each step, not at the end
- Reject silent plan updates — Claude must announce + get re-approval
- Commit per step so the audit trail is git-native