name: uplan
description: Use after design to turn a validated spec into a lean implementation plan. Outputs the ## Plan section of the task file — files, line numbers, class/method names, invariants, test strategy, order. Ends with a scope-creep / simpler-way check.
Plan
Convert the approved Design into a lean, concrete implementation plan. Output fills the ## Plan section of docs/tasks/<slug>.md. The plan is the contract that up:uexecute will follow.
What a plan is
Plan answers: how do we get from where we are now to the Design's vision? It's the delta — the concrete path from current code to the approved spec. Design owns what it should be; Plan owns how we get there from here.
A plan is the minimum information an engineer needs to implement the Design without re-doing the thinking. That means:
- Concrete locations: exact file paths, line number ranges, class/method/interface names. "Modify
parser.py" is not enough —parser.py:120-160, Parser.tokenize()is. - Per-file change bullets: what changes in each file, by name. Not prose.
- Interface signatures: new or changed function/method signatures. No bodies.
- Phases with commits: ordered phases, one commit per phase minimum.
- Test strategy: the behaviors to cover, not test code.
- Snippets only where words fail: one regex, one tricky algorithm, one non-obvious API call. Never full implementations.
If an engineer could read your plan and implement the wrong thing, the plan is incomplete. If they need to re-derive the Design to understand the plan, the plan is bloated.
Scope is decided in design, not here
By the time you plan, the task's scope is fixed. If you discover a subsystem-split issue now, it means design missed it — stop planning, go back to the user, and decide whether to re-open design or keep the current scope.
Do not silently split the task here. Do not silently expand it either.
Output
Fill ## Plan in docs/tasks/<slug>.md. Do not create a separate plan file.
Brevity
Process
Required contents
Required always:
- Approach: 1-2 sentences on the strategy and why it fits the Design
- File structure: for each file,
path/to/file.ext:lineA-lineB(create|modify) + affected class/method names - Per-file bullets: what changes, by name
- New/changed interfaces: signatures only
- IV/PC/AS referenced by ID: which Design entities each phase preserves or relies on
ID conventions in Plan
Plan introduces two entity types, numbered within the task file:
- PH1, PH2, … — Phases. Each phase heading is
### PH<N> — <name>. - RK1, RK2, … — Risks. Each is one sentence.
References to Design entities use IDs (IV3, AS1, UK2) — never re-quote the full sentence.
Required when relevant (omit the subsection when it would say "single phase, no deps", "none", or similar):
- Test strategy: behaviors to cover. If
TDD: yes, list the failing tests to write first. - Order + dependencies: phases, what blocks what
- Open questions / risks / rollback: what could go wrong, how to back out
- Interfaces: declare cross-phase contracts when ≥2 phases share a signature / anchor / API shape. Omit for single-phase plans.
- Interface graph: declare phase shape when ≥2 phases exist. Omit for single-phase plans.
Optional:
- Code snippets: only for the most critical component per phase. If tempted to include full code, you're over-planning.
Format
## Plan
Approach: <1-2 sentences>
### PH1 — <name>
- **1.1** `path/to/file.ext:lineA-lineB` (create|modify)
- `ClassName.method_name(arg: Type) -> Ret` — <what changes, by name>
- Respects: IV2, AS1
- **1.2** ...
- Commit: `<message>`
### PH2 — <name>
...
### Test strategy (optional — omit if no tests / doc-only)
<behavior list, per file or per phase>
### Order & dependencies (optional — omit for single-phase or obviously-sequential plans)
<what blocks what, parallelizable phases>
### Risks / rollback (optional — omit if none non-trivial)
- RK1 — <one-sentence risk and mitigation>
- RK2 — <...>
### Interfaces (optional — omit for single-phase plans)
- IF1 — `<signature>` — <contract sentence>
- IF2 [blocks] — `<signature>` — <contract sentence> (consumer must wait for producer; see "Blocking interfaces" below)
### Interface graph (optional — omit for single-phase plans)
- PH1 -> IF1, IF2 @ plugins/up/skills/foo/SKILL.md
- PH2 IF1 -> IF3 @ plugins/up/skills/bar/SKILL.md
- PH3 IF2, IF3 -> @ plugins/up/agents/baz/AGENT.md
When to declare interfaces
- An interface is a cross-phase contract: a function/method signature, a shared SKILL.md section anchor, or any API shape that one phase produces and another phase consumes.
- The consume arrow (
IF<N> ->) means runtime coupling — one phase's output is the other phase's input. Doc-only phases that merely reference a prior phase's plan text are sources, not consumers; leave the consume side empty (the line starts withPH<N> -> <produces>). @ <paths>marks the filesystem boundary for each phase. Paths declared by phases in the same wave must be disjoint;up:uexecuteuses this to detect boundary violations after each commit.- Waves are derived from the graph by topo-sort over
[blocks]edges only — non-blocking IF edges (the default) do not create wave boundaries, since the IF declaration is sufficient context for the consumer. Phases linked only by non-blocking IFs land in the same wave and run in parallel. Do not hand-declare waves; declare the graph and the blocking flags, and let the executor derive them. - Omit both
### Interfacesand### Interface graphfor single-phase plans.
Blocking interfaces
By default, an IF is non-blocking: its declared signature is the contract, and a consumer can be implemented in parallel with the producer (the wiring check reconciles any drift after the wave). Mark an IF [blocks] when:
- The consumer needs the producer's actual output, not just the signature — e.g. a generated config file, an applied DB migration, a fixture that must exist on disk, a doc anchor that must resolve at lint time.
- The producer is large, risky, or critical enough that the planner does not want dependent work running concurrently — better to land it, verify it, then build on top. Planner/dispatcher discretion.
Use [blocks] sparingly — every block reduces parallelism. The default of non-blocking is correct for ordinary code interfaces (function signatures, class shapes, SKILL.md anchors) where the IF declaration carries the contract.
Self-review (inline, no subagent)
Fix issues inline. No re-review loop.
Backwards-compat check — restate the design's risks in plan terms
If the task is greenfield, skip this check explicitly in one line.
Default principles
Final check — scope creep, elegance, simpler way
- Scope creep: is every phase directly serving the Design, or have I snuck in "while I'm here" refactors, extra validation layers, speculative generality?
- Elegance: can any pair of phases merge? Are there accidental duplicate data paths? Does the plan introduce abstractions that aren't pulling their weight?
- Simpler way: is there a one-paragraph alternative plan that gets 90% of the value with 30% of the work? If yes, propose it to the user as an option.
If this check surfaces real simplifications, rewrite the plan. Don't stack warnings on top of a bloated plan.
Hands-off mode
See up:handsoff for the full contract. Stage-specific delta: skip the approval wait — present the plan highlights, log - uplan: plan auto-approved to ### Hands-off decisions, invoke up:uexecute directly. Self-review, scope-creep check, and backwards-compat restatement are unchanged. Ambiguities that would require a user call go to ### Deferred (needs user input) and the plan stops — do not guess around them.
Terminal state
Plan written, self-reviewed, scope-checked. Interactive: present highlights, wait for approval, invoke up:uexecute. Hands-off: present highlights, log auto-approval, invoke up:uexecute.