Implementation Plan Creation
Create an implementation plan in docs/plans/yyyy-mm-dd-<task-name>.md. Write as if the engineer implementing it has zero context about the codebase — document everything they need: which files to touch, actual code to write, exact commands to run, how to test it. Assume they are skilled but know nothing about this toolset or problem domain.
Step 0: Parse intent and gather context
Before asking questions, understand what the user is working on:
Parse user's arguments to identify intent:
- "add feature Z" / "implement W" → feature development
- "fix bug" / "debug issue" → bug fix plan
- "refactor X" / "improve Y" → refactoring plan
- "migrate to Z" / "upgrade W" → migration plan
- generic request → explore current work
Gather relevant context quickly — use direct tool calls (Read, Glob, Grep), NOT an Agent. Keep discovery under 30 seconds in the default mode; deep-discovery mode below lifts both this budget and the file cap.
for feature development:
- glob for files matching the feature area
- read 1-3 most relevant files to understand existing patterns
- check project structure with a quick
lsof key directories
for bug fixing:
- grep for error messages or function names mentioned in the request
- read the specific file(s) involved
- check
git log --oneline -5for recent changes
for refactoring/migration:
- glob for files matching the area being refactored
- read 2-3 key files to understand current structure
- grep for imports/references to identify dependencies
for generic/unclear requests:
- check
git statusandgit log --oneline -5 - read README.md or CLAUDE.md for project overview
lsthe top-level directory structure
CRITICAL: do NOT launch an Agent or read more than 5 files in this step. This cap is on discovery only — Step 2's "Read what you will modify" pass is separate and uncapped.
Deep-discovery mode — the 5-file cap and 30-second budget above are the default, not a hard ceiling. Switch to deep mode when any of these become true:
docs/plans/(includingcompleted/) already contains a sibling plan for the same feature (checkable right here at Step 0)- the user states, at any point, that this plan is part of a larger, multi-plan effort (a feature broken into slices, a WBS/parent doc)
- Step 1's scope/constraints answers reveal multi-plan or large-feature scope that wasn't apparent yet at Step 0
The first condition can be checked now. The other two usually can't be known until after Step 1 — when either fires there, go back and run the deep pass below before Step 2, rather than proceeding with shallow discovery just because the trigger came late.
In deep mode: read as many files as it takes to understand the actual call chains the plan's tasks depend on — no fixed file count, no 30-second budget. This is still a discovery pass, not a full audit, so keep it targeted to what the plan's tasks will actually call or touch.
for Go repos — resolve the real test command, don't assume
go test ./...:- check
Makefilefor atesttarget → usemake test - else check
.github/workflows/*.yml/.gitlab-ci.ymlfor the test step → mirror that exact invocation - else fall back to
go test ./...
Use whichever command this resolves to everywhere the plan references "run full test suite."
Synthesize findings into a brief context summary (3-5 bullet points)
Step 1: Present context and ask focused questions
Show the discovered context, then ask questions one at a time — a separate AskUserQuestion tool call per question, never multiple questions batched into one call's questions array:
- Plan purpose: "what is the main goal?" — multiple choice with suggested answer based on discovered intent
- Testing approach: "TDD or regular?" — options: "TDD (tests first)" / "Regular (code first, then tests)". Ask this early because it shapes the task structure throughout the plan.
- Scope: "which components/files are involved?" — multiple choice with discovered files. The tool requires ≥2 options per question — if discovery turned up only one file/component, do not force a second fabricated option; ask this one as free text instead.
- Constraints: "any specific requirements or limitations?"
- Plan title: "short descriptive title?" — suggest based on intent
Step 1.5: Explore approaches
Once the problem is understood, propose implementation approaches:
- Propose 2-3 different approaches with trade-offs
- Lead with recommended option and explain reasoning
- Present conversationally — not a formal document yet
Example format:
I see three approaches:
**Option A: [name]** (recommended)
- how it works: ...
- pros: ...
- cons: ...
**Option B: [name]**
- how it works: ...
- pros: ...
- cons: ...
Which direction appeals to you?
Use AskUserQuestion to select the preferred approach before creating the plan.
Skip this step if the approach is obvious, user specified it, or it's a clear bug fix.
Step 2: Create plan file
Check docs/plans/ for existing files, then create docs/plans/yyyy-mm-dd-<task-name>.md (use current date).
File structure first
Before defining tasks, map out which files will be created or modified and what each one is responsible for. This is where decomposition decisions get locked in.
- Design units with clear boundaries and well-defined interfaces — each file should have one clear responsibility
- Prefer smaller, focused files; you reason best about code you can hold in context at once
- Files that change together should live together; split by responsibility, not by technical layer
- In existing codebases, follow established patterns; if a file is unwieldy, a split in the plan is reasonable
This structure informs task decomposition — each task should produce self-contained changes that make sense independently.
Read what you will modify
Before writing a task, read in full every file that task lists under Modify, and every file it lists under Create that already exists. Not a grep for the symbol, not the first 50 lines — the whole file. This is not part of Step 0's discovery budget and is not capped by it: discovery decides what the plan touches, this pass establishes what is actually there in the files it has already decided to touch.
Two things go wrong when this is skipped, and both produce a plan that cannot compile:
- Helpers and fixtures. A task writes
newFakeClientBuilder()when the real signature isnewFakeClientBuilder(t, scheme), or declares a helper that already exists in the same package. Before writing any test code, read the existing test files in that same package — the ones the new tests will sit beside — and reuse their real fixture and helper names, with their real parameter lists. - Existing assertions. A task changes behavior that an existing test already pins (a returned
Result{}, a status reason, an error string) and never lists the assertion as needing an update. Any test currently asserting on behavior a task changes is itself aModifytarget — find those assertions while reading, and give each one an explicit checklist item.
If a file is genuinely too large to hold, that is a signal to narrow the task's scope, not to skim the file.
Dependency contract check
Skip this step if the plan introduces net-new code with no existing dependencies to verify.
Otherwise, before writing tasks: identify every external function, method, or API the plan's correctness depends on — things the plan will CALL, not things it will CREATE. For each one:
- Read its body (not just its name or signature)
- Record what it actually guarantees: privileges granted, errors returned and how they're wrapped, side effects, state left behind after it runs
- Flag any gap between the name's implied behavior and the body's actual behavior — these are the places plans silently go wrong
This is a focused pass — typically 3–6 functions, not broad exploration. Record findings in the "Verified Dependency Behaviors" section of the plan.
In deep-discovery mode (Step 0), widen this to every dependency any task actually calls — not a fixed 3–6 count. A function reused across several tasks needs verifying once; a wrong assumption about it otherwise silently reproduces itself into every task that calls it.
Test-only helpers count as dependencies. A fixture, builder, or assertion helper the plan's test code calls is a function the plan's correctness depends on, even though it never ships — and it is the single most common place plans go wrong. It does not need a "Verified Dependency Behaviors" entry (that section is for shipped behavior), but its real signature does need to be right in every task that calls it.
Plan structure
# [Plan Title]
**Goal:** [one sentence describing what this builds]
**Architecture:** [2-3 sentences about the approach]
**Tech Stack:** [key technologies/libraries involved]
---
## Context (from discovery)
- files/components involved: [list from step 0]
- related patterns found: [patterns discovered]
- dependencies identified: [dependencies]
## Verified Dependency Behaviors
*External functions/APIs this plan calls — verified by reading their bodies, not inferred from names. Omit if plan is net-new with no existing dependencies.*
- `FunctionName` (`path/to/file.go:NN`): [what it actually does — privileges granted, errors returned/wrapped, side effects, state left behind]
- ...
## Development Approach
- **testing approach**: [TDD / Regular - from user preference]
- complete each task fully before moving to the next
- make small, focused changes
- **CRITICAL: every task MUST include new/updated tests** for code changes
- **CRITICAL: all tests must pass before starting next task**
- **CRITICAL: update this plan file when scope changes during implementation**
- **CRITICAL: single summary commit at the end** — no per-task commits; one commit covers all implementation + plan move when complete
- **CRITICAL: run `golangci-lint run ./...` before committing** — fix all linter issues first
- run tests after each change
- maintain backward compatibility
## Technical Details
- key design decisions and rationale
- data structures and changes
- parameters and formats
- processing flow
## Progress Tracking
- mark completed items with `[x]` immediately when done
- add newly discovered tasks with ➕ prefix
- document issues/blockers with ⚠️ prefix
## Implementation Steps
### Task 1: [specific name]
**Files:**
- Create: `exact/path/to/new_file`
- Modify: `exact/path/to/existing`
**If TDD:**
- [ ] **Write failing tests** — happy path + error cases + edge cases
```go
func TestFunctionName_HappyPath(t *testing.T) { ... }
func TestFunctionName_InvalidInput(t *testing.T) { ... }
func TestFunctionName_EmptyResult(t *testing.T) { ... }
Run tests to verify they fail
Run:
go test ./path/... -run TestFunctionName -vExpected: FAILWrite minimal implementation
func FunctionName(input Type) ReturnType {
// implementation
}
Run tests to verify all pass
Run:
go test ./path/... -run TestFunctionName -vExpected: PASS
If Regular:
- Write implementation
func FunctionName(input Type) ReturnType {
// implementation
}
- Write tests — happy path + error cases + edge cases
func TestFunctionName_HappyPath(t *testing.T) { ... }
func TestFunctionName_InvalidInput(t *testing.T) { ... }
func TestFunctionName_EmptyResult(t *testing.T) { ... }
Run tests to verify all pass
Run:
go test ./path/... -run TestFunctionName -vExpected: PASS
Task N-1: Verify acceptance criteria
- verify all requirements from Goal are implemented
- run full test suite:
<command resolved in Step 0, e.g.make testorgo test ./...>- if failures look like shared-state flakiness — an assertion fails against a resource another test seems to have touched, failures aren't reproducible when the same test is run alone (
-run), or which tests fail changes between runs — retry once with-p=1before treating it as a regression
- if failures look like shared-state flakiness — an assertion fails against a resource another test seems to have touched, failures aren't reproducible when the same test is run alone (
- run
golangci-lint run ./...— fix all issues before proceeding - verify test coverage meets project standard
Task N: [Final] Wrap up and commit
- update README.md if needed
- update CLAUDE.md if new patterns discovered
- move this plan to
docs/plans/completed/— usemkdir -p docs/plans/completed && mv <plan> docs/plans/completed/(plainmv, notgit mv: the plan is usually untracked, and the finalgit add -Astages the move either way) - single summary commit: all implementation changes + plan move in one commit
- open draft PR — invoke
planning:pr
Post-Completion
Items requiring manual intervention or external systems
### No placeholders
Every step must contain the actual content an engineer needs. These are plan failures — never write them:
- "TBD", "TODO", "implement later", "fill in details"
- "Add appropriate error handling" / "add validation" / "handle edge cases" (without showing the code)
- "Write tests for the above" (without actual test code)
- A single happy-path test when error cases or edge cases clearly exist — always enumerate: what inputs cause errors? what are the boundary values? what does the function return when there's nothing to return? Each scenario that can fail Sonar coverage gets its own named test function.
- "Similar to Task N" (repeat the code — the engineer may read tasks out of order)
- Steps that describe what to do without showing how — if a step changes code, show the code
- References to types, functions, or methods not defined in any task
### Code comment rules
Comments inside example code shown in tasks must be self-contained — never a pointer to something else:
- No ticket IDs, no links to Confluence/Jira/PRs, no commit SHAs
- No `(Slice N)` markers or "see ... in Technical Details" pointers back into this plan
- No `docs/specs/...` references — inline the one clause of context a reader needs, don't point at the spec
- At most 1-2 lines; if it needs more than that to justify itself, the content belongs in this plan's prose, not in a code comment
- State only the "why" a future reader needs at the call site to not re-break the thing — never restate what the code obviously does
This applies to comments in the code itself. Plan-level cross-references (a WBS/slice note, "this plan supersedes the approach in `<prior-plan>`") stay in the plan's own prose sections — this rule doesn't touch those.
## Step 2.5: Self-review
After writing the complete plan, check it yourself before offering next steps. All 8 checks below are internal reasoning, not an announced procedure — where a check is faster with a tool call (a grep, a read) than by eyeballing, make the call and act on the result, but don't narrate it as its own step or report a "clean" pass; only surface something if you actually find and fix an issue.
1. **Spec coverage** — skim each requirement. Can you point to a task that implements it? Add tasks for any gaps.
2. **Placeholder scan** — search for any patterns from the "No placeholders" section above. Fix them.
3. **Type consistency** — do method signatures and names used in later tasks match what's defined in earlier tasks? A function called `ParseConfig()` in Task 3 but `LoadConfig()` in Task 7 is a bug. Then check the same names against the real files: every helper, fixture, and function a task *calls* rather than creates must match the signature in the file you read, and no task may declare something that already exists in that package.
4. **Dependency behavior check** — for each entry in "Verified Dependency Behaviors": does the plan's logic actually hold given what that function does? A function that grants USAGE+DML but not CREATE is not "full access" even if named that way.
5. **Error/status tracing** — skip if the plan asserts no error outcomes or status codes. Otherwise, for every one asserted, trace it end-to-end: where the sentinel/error originates, every `%w` re-wrap on the way, and what the handler that receives it actually returns. Fix any task whose expected outcome doesn't match what the trace shows.
6. **Test setup preconditions** — skip if the plan has no test setup steps. Otherwise walk each task's test setup in execution order against the API's actual state-transition/creation-order rules. Fix any step that would be rejected because it violates an ordering requirement.
7. **Multi-phase state** — skip if the plan touches no migration, workflow, or staged operation. Otherwise check what earlier phases actually leave in place before a later task asserts on that state. Fix any assumption of absent state that an earlier phase already establishes.
8. **Comment hygiene** — same as the other seven: check the plan's code blocks for ticket IDs (`[A-Z]{2,}-[0-9]+`), links (`https?://`), commit SHAs (`\b[0-9a-f]{7,40}\b`), `Slice [0-9A-Z]`, `see .* Technical Details`, and `docs/specs`. Skip a match that's actually a standard name, not a reference — `UTF-8`, `SHA-256`, `RFC-7231`, `AES-256`, `ISO-8601` and the like aren't ticket IDs. Rewrite any real hit per "Code comment rules" above.
Fix issues inline. No need to re-review after fixing.
These checks mirror what the separate `plan-review` agent verifies. Catching them here means fewer review rounds, not weaker review — the reviewer still runs the same checklist independently.
## Step 3: Next steps
After self-review, tell the user: "created plan: `docs/plans/yyyymmdd-<task-name>.md`"
Before building this menu, check availability: `[ "$AGTERM_ENABLED" = "1" ] && command -v agtermctl >/dev/null 2>&1`. Only include the "Implement in a Separate Session" option below when that check succeeds; omit it otherwise (the other four options are always shown).
Then use AskUserQuestion:
```json
{
"questions": [{
"question": "Plan created. What's next?",
"header": "Next step",
"options": [
{"label": "Auto-review", "description": "Run structured agent review — checks correctness, over-engineering, test coverage"},
{"label": "Review with revdiff", "description": "Open plan in revdiff for inline annotations"},
{"label": "Implement in a Subagent", "description": "Hand off implementation to a background subagent — reports back when done, keeps this session clean"},
{"label": "Implement in a Separate Session", "description": "Hand off implementation to a fresh agterm session, in the same workspace as this one — runs interactively, you can watch and drive it directly"},
{"label": "Done", "description": "Stop here"}
],
"multiSelect": false
}]
}
Auto-review: invoke the
planning:review-planskill on the plan file — it handles the review/fix loop internally. When it returns, stop completely. Do NOT proceed to implementation.Review with revdiff: invoke the
revdiff:revdiffskill on the plan file — it handles the full annotation and revision loop internally. When it returns, stop completely. Do NOT proceed to implementation.Implement in a Subagent: first ask which model the implementer should run on, using AskUserQuestion:
{ "questions": [{ "question": "Which model should the implementer subagent use?", "header": "Model", "options": [ {"label": "Inherit", "description": "Use the same model as this session (default)"}, {"label": "Opus", "description": "Most capable — best for complex or subtle implementations"}, {"label": "Sonnet", "description": "Faster and cheaper — good for straightforward plans"}, {"label": "Haiku", "description": "Fastest and cheapest — for simple mechanical changes"} ], "multiSelect": false }] }Then use the Agent tool with
subagent_type: general-purposeandrun_in_background: trueto dispatch the plan below. Passmodelset to the chosen tier (opus,sonnet, orhaiku); for Inherit, omit themodelparameter entirely. Do NOT add task-by-task review scaffolding or extra process — this is a plain hand-off, matching what a fresh session would get:You have a new implementation plan to execute: PLAN_FILE Read it fully, then implement every task in order, following its stated testing approach. Run the project's tests and linter before treating any task as done. When the whole plan is implemented, report a concise summary of what changed, and flag any deviations from the plan or open concerns.Tell the user implementation has been handed off to a background subagent (noting the chosen model) and they'll be notified when it completes. Stop completely — do NOT continue.
Implement in a Separate Session: hand off to a fresh agterm session in this same workspace. First ask which model it should run on, using the same AskUserQuestion as the Subagent option above (
Inherit/Opus/Sonnet/Haiku); lower-case the chosen label forMODEL(empty string for Inherit).Run:
bash "${CLAUDE_PLUGIN_ROOT}/scripts/agterm-handoff.sh" "PLAN_FILE" "" "MODEL"(substitute the real plan path forPLAN_FILEand the chosen model forMODEL).On success (exit 0), the script's last stdout line is the new session's display name (e.g.
Implement: foo) — tell the user implementation has been handed off to a new agterm session with that name, in this same workspace (noting the chosen model, unless Inherit), and they can switch to it to watch or drive it directly. On failure (non-zero exit), tell the user the handoff failed, quoting the script's stderr output. Do not fall back to a subagent silently. Either way, stop completely.Done: stop.
Key principles
- Zero context — write as if the implementer knows nothing about this codebase; show the code, show the commands, show expected output
- One question at a time — do not overwhelm with multiple questions
- Multiple choice preferred — easier than open-ended when possible
- YAGNI ruthlessly — minimal scope, no unnecessary features
- Lead with recommendation — have an opinion, explain why, but let user decide
- Explore alternatives — always propose 2-3 approaches before settling
- Single summary commit — never commit per task; one commit at the end covers everything
- Complete code in every step — if a step changes code, include the actual code block