Overview
Cursor's agent mode is fantastic for scoped edits and dangerous for wide refactors — it happily rewrites 40 files when you meant 4. The plan-file pattern gates every change through a versioned markdown plan you review before code moves. It's the difference between a shippable refactor and a 3-hour cleanup PR.
How it works
- You write a one-paragraph description of the refactor and ask Cursor to draft a plan.md, not code.
- The plan lists every file to touch, the intent per file, and the acceptance test.
- You edit the plan aggressively — deleting scope, tightening intent, adding tests.
- Cursor executes one plan section at a time; you approve each diff before moving on.
- The plan file stays in the PR as documentation of intent.
Benefits
- Prevents scope creep — you see the sprawl before Cursor writes it.
- Makes review painless — reviewers read the plan, then verify each section.
- Turns AI edits into auditable history.
Use cases
- Renaming a core abstraction across a codebase.
- Migrating from one library to another (e.g., moment → date-fns).
- Splitting a god-file into focused modules.
Step-by-step guide
Step 1: Write the intent paragraph
One paragraph, in your voice, describing what changes and why. This becomes the top of plan.md and the PR description.
Step 2: Ask for a plan, not code
Prompt: 'Draft a plan.md that lists every file to change and the intent per file. Do not write code yet.' Cursor obeys explicit refusals.
Step 3: Prune ruthlessly
Delete any file where the intent is 'update to match' — that's an implicit dependency you should verify separately, not a real change.
Step 4: Add acceptance criteria per section
Each plan section gets a 'done when' line. Cursor uses these as its stop condition, which prevents over-editing.
Step 5: Execute one section at a time
Prompt: 'Execute Section 2 only.' Review the diff. Only then approve Section 3. Never let Cursor batch-execute the full plan.
Step 6: Commit the plan
Include plan.md in the PR. Future you (and your reviewers) will thank you.
Example
plan.md excerpt: '### 3. src/api/users.ts\nIntent: Replace direct DB calls with the new UserRepo.\nDone when: All three route handlers use userRepo.get/create/update and tests pass unchanged.'