Plan-Driven Development
Use PLAN.md, task decomposition, and checkpoint commits to keep AI agents on track for large features
title: "Plan-Driven Development" description: "Use PLAN.md, task decomposition, and checkpoint commits to keep AI agents on track for large features" section: "Workflows" readTime: "13 min"
Plan-Driven Development
Large features fail when you hand an AI agent a vague goal and walk away. Plan-driven development solves this: you create a structured plan file first, the agent uses it as a grounding document, and every checkpoint is a commit that can be rolled back.
Why Plans Matter for AI Agents
AI agents are excellent at executing well-defined steps but poor at decomposing ambiguous requirements autonomously. A plan file:
- Forces you to think through the design before any code is written
- Gives the agent clear acceptance criteria for each step
- Creates natural review points so you don't end up reviewing 2,000 lines of unreviewed AI code
- Serves as a shared artifact that any agent (Claude, Copilot, Cursor) can pick up
The PLAN.md Pattern
Create a PLAN.md in your repo root or feature branch:
# Feature: User Authentication
## Goal
Add email/password auth with JWT tokens and refresh rotation.
## Constraints
- Use existing Prisma schema — do not modify users table
- All endpoints must be protected by the existing rate limiter
- No new dependencies without approval
## Steps
### Step 1: Password hashing utilities [ ]
- Create `src/lib/auth/password.ts`
- Export: `hashPassword(plain: string): Promise<string>`
- Export: `verifyPassword(plain: string, hash: string): Promise<boolean>`
- Tests: `__tests__/auth/password.test.ts`
### Step 2: JWT utilities [ ]
- Create `src/lib/auth/jwt.ts`
- Export: `signToken(payload: JWTPayload): string`
- Export: `verifyToken(token: string): JWTPayload | null`
- 15min access token, 7-day refresh token
### Step 3: Auth endpoints [ ]
- POST /api/auth/register
- POST /api/auth/login → returns { accessToken, refreshToken }
- POST /api/auth/refresh → rotates refresh token
- POST /api/auth/logout → invalidates refresh token
### Step 4: Middleware [ ]
- `src/middleware/auth.ts` — validates JWT, attaches user to request
- Apply to all /api/protected/* routes
## Acceptance Criteria
- [ ] All tests pass
- [ ] No secrets logged
- [ ] Rate limiting applies to /register and /loginRunning a Plan with Claude Code
Option 1: Step-by-step with checkpoints
claude "Read PLAN.md. Execute Step 1 only.
After completing it, run the tests, then stop and wait for my approval
before moving to Step 2. Mark the step [x] in PLAN.md when done."After review:
claude "Step 1 looks good. Proceed to Step 2."Option 2: Autonomous execution with commits
claude "Read PLAN.md. Execute each step in order.
After each step: run tests, commit with message 'feat: PLAN step N — <description>',
then continue. If any step fails tests after 2 attempts, stop and report."Option 3: Plan mode first
Use Claude Code's built-in plan mode. In plan mode Claude reads files and runs exploratory commands but does not edit your source until you approve a plan. Enter it any of these ways:
# Start a session in plan mode
claude --permission-mode plan
# Or, inside a session: press Shift+Tab until the status bar shows "⏸ plan mode on"
# Or prefix a single prompt with /plan
/plan Add authentication as described in the requirements below: [paste requirements]When Claude presents the plan, you choose how to proceed:
| Option | Effect |
|---|---|
| Yes, and use auto mode | Approve and execute with auto mode's classifier reviewing actions (reads Yes, auto-accept edits if auto mode isn't available) |
| Yes, manually approve edits | Approve and review each edit individually |
| No, keep planning | Stay in plan mode and tell Claude what to change |
Press Ctrl+G to open the proposed plan in your text editor and edit it directly before approving. Approving exits plan mode and Claude starts implementing; press Shift+Tab (or use /plan again) to plan the next phase.
To make plan mode the default for a project, set "defaultMode": "plan" under permissions in .claude/settings.json. The opusplan model alias uses Opus while planning and Sonnet for execution.
Planning adds overhead. Skip it when the change is small and clear — if you could describe the diff in one sentence, ask Claude to do it directly. Plan when you're unsure of the approach, the change touches multiple files, or you're unfamiliar with the code.
Option 4: Let Claude interview you into a spec
For larger features, have Claude draft the plan document with you:
I want to build [brief description]. Interview me in detail using the AskUserQuestion tool.
Ask about technical implementation, UI/UX, edge cases, concerns, and tradeoffs.
Keep interviewing until we've covered everything, then write a complete spec to SPEC.md.
Then start a fresh session (/clear or a new claude) to implement from SPEC.md with clean context.
GitHub Copilot Plan-Driven Flow
VS Code's Copilot Chat has a built-in Plan agent: pick Plan from the agents dropdown, or type /plan followed by your task, to get an implementation plan before any code is written. A committed plan file still works with any agent:
-
Create PLAN.md manually or ask Copilot to generate it first:
Before writing any code, create a PLAN.md for adding authentication. Break it into atomic steps, each with files to create/modify and test requirements. Wait for my approval before implementing. -
Execute step by step with the Agent:
Implement only Step 1 from #PLAN.md. Run the tests when done. Don't touch Step 2 yet.
Cursor Plan-Driven Flow
Cursor has a built-in Plan Mode (press Shift+Tab in the chat input or use the mode picker): the agent asks clarifying questions, researches the codebase, and produces a plan you can edit before building. Plans are saved in your home directory by default; click Save to workspace to keep one in the repo.
To run an existing plan in Agent mode:
Read @PLAN.md. Implement Step 1 only.
After each file change, run npm test.
When Step 1 is complete and tests pass, update the checkbox in PLAN.md and stop.
@-mentioning a file attaches it to the chat as context.
Checkpoint Commits
Commit after every completed step — not at the end of the feature:
# Good: atomic, reviewable commits
git commit -m "feat: auth — password hashing utils (PLAN step 1/4)"
git commit -m "feat: auth — JWT sign/verify (PLAN step 2/4)"
git commit -m "feat: auth — register+login endpoints (PLAN step 3/4)"
git commit -m "feat: auth — middleware + route protection (PLAN step 4/4)"
# Bad: one 800-line commit
git commit -m "add authentication"Benefits: if Step 3 goes wrong, git reset --hard HEAD~1 gets you back to a working Step 2 state.
Checkpoints vs Commits
Claude Code also checkpoints automatically: every prompt you send creates a checkpoint, and pressing Esc twice or running /rewind lets you restore the conversation, the code, or both to an earlier point (or summarize from a selected message). This is handy for trying a risky step and backing out.
Checkpoints only track changes made through Claude's file-editing tools — not changes from Bash commands or external processes. They complement git commits; they don't replace them.
Verify Against the Plan
Before marking the feature done, have a fresh-context reviewer check the work against the plan:
Use a subagent to review the diff against PLAN.md. Check that every requirement
is implemented, the listed edge cases have tests, and nothing outside the task's
scope changed. Report gaps, not style preferences.
For a pure correctness pass, run /code-review.
Plan Quality Checklist
When Plans Break Down
| Symptom | Fix |
|---|---|
| Agent skips to Step 4 without finishing Step 2 | Add explicit "stop and wait" instructions between steps |
| Plan becomes stale mid-implementation | Ask agent to update PLAN.md with what actually changed |
| Agent rewrites the plan to make it easier | Version-control the plan; tell agent it's read-only |
| Feature scope creeps | Add a "Non-goals" section to PLAN.md |