Decomposes an existing epic into milestones. The skill drives the conversation about what to ship in what order; aiwf owns id allocation and per-milestone commits.
An epic spec exists. The user says: "break E-NNNN into milestones", "plan the work for the auth epic", "sequence the milestones for X".
-
Read the epic spec. Open work/epics/E-NNNN-<slug>/epic.md. Understand:
- The goal โ what the epic is delivering.
- The scope (in / out).
- The constraints โ what each milestone must respect.
- The success criteria โ what "done" looks like at epic close.
-
Decompose into milestones. Each milestone:
- Is independently shippable. After M-0001 lands, the system is in a coherent state even if M-0002 never runs.
- Has clear, testable acceptance criteria.
- Targets 1โ3 days of focused work. If a candidate is bigger, split it. If smaller, fold it into a sibling.
- Has explicit dependencies (or none). Forward-flowing โ M-0002 may depend on M-0001; never the reverse.
-
Sequence them. Foundational first. Group related work; don't scatter concerns. Identify any milestones that can be parallelized (no dependency between them).
-
Allocate each milestone via aiwf. For each one in sequence:
aiwf add milestone --epic E-NNNN --title "<imperative title>"
aiwf allocates the next free M-NNNN (global, not epic-scoped), creates work/epics/E-NNNN-<slug>/M-NNNN-<slug>.md with the minimal body skeleton, sets parent: E-NNNN in frontmatter, and produces one commit per milestone with aiwf-verb: add trailers.
-
Replace each milestone's body with the rich template at this plugin's templates/milestone-spec.md. Fill in:
- Goal โ 1โ2 sentences.
- Context โ what exists before; what must be in place; why now.
- Acceptance criteria โ testable, numbered (AC1, AC2, โฆ).
- Constraints โ non-negotiable invariants for this milestone.
- Design notes โ locked decisions; reference ADRs by id.
- Out of scope โ what this milestone explicitly does NOT do.
- Dependencies โ prior milestones, external deps, decision records.
Frontmatter (id, parent, status: draft) was set by aiwf add โ don't touch.
-
Declare milestone dependencies via verb, not by hand-editing frontmatter. Two writer surfaces, both producing one atomic commit with aiwf-verb trailers (M-0076):
aiwf add milestone --epic E-NNNN --tdd <policy> \
--title "..." --depends-on M-PPPP[,M-QQQQ]
aiwf milestone depends-on M-NNNN --on M-PPPP[,M-QQQQ]
aiwf milestone depends-on M-NNNN --clear
Replace-not-append semantics: a second --on invocation replaces the list, it does not extend. To add a single dependency to an existing list, pass the full updated list. --on and --clear are mutually exclusive. Each id passed to --depends-on or --on must already resolve to an existing milestone โ typos and forward-references are refused with an error naming the unresolvable id. Cycle detection happens at the next aiwf check (and pre-push hook); the writers don't pre-check global DAG validity.
Do not hand-edit depends_on: in frontmatter. aiwf edit-body refuses frontmatter changes, and a plain git commit against the milestone file trips the kernel's provenance-untrailered-entity-commit warning. Both writer verbs above leave a trailered commit that aiwf history M-NNNN can render.
-
Update the epic's Milestones list. Edit the epic spec to list all milestones in execution order. Use the format from the epic template โ link, one-line description, dependencies.
-
Update ROADMAP.md by running:
aiwf render roadmap --write
-
Confirm the sequence with the user. Walk through the milestone list together. Identify any scope adjustments before drafting begins.
-
Merge planning to main. Planning is closed; the entity tree on this ritual branch now diverges from main. Default behavior is to merge to main now so the freshly-allocated M-NNNN ids, the epic's updated Milestones list, and any depends_on edges are visible to other worktrees, machines, or operators. Held on a long-lived branch, planning data is hostage: other Claude Code sessions see only main's view, parallel epics walk separate filesystem-only next-free-id views (id collisions surface only at eventual merge), and milestone branches stack on a long-lived parent โ making the epic-wrap diff balloon.
Prompt the user as a strong recommendation with explicit decline:
Planning is closed. Default behavior is to merge to main now. Decline only with a specific reason โ entity shape uncertain, near-term re-planning expected, team convention overrides. Merge now? (Y/n)
When the operator confirms, drive the in-place merge:
git checkout main
git merge --ff-only <ritual-branch>
When the operator declines, capture the one-line reason in the conversation transcript so future readers know.
Workflow assumption โ single checkout, not a worktree. The skill assumes the operator runs planning in a single checkout (the same one calling the skill). Planning is sequential conversation; it doesn't benefit from worktree-level parallelism, and the cwd-and-session switching that worktrees impose adds friction without payoff. Worktrees are an implementation-phase tool, not a planning-phase tool.