to-roadmap · diff
git:20260923.0a9c513 to git:20260923.42f2923
7 added, 138 removed. Audit A to A.
---
name: to-roadmap
description: 'Capture a multi-task initiative into `.task/roadmap/<slug>.md` — a phase-grouped backlog of ready-to-pick-up items.'
argument-hint: '[initiative]'
disable-model-invocation: true
user-invocable: true
allowed-tools: 'Bash(bash *skills/_lib/preflight.sh* *) Bash(bash *skills/_lib/write-task.sh* *) Bash(bash *skills/_lib/roadmap-items.sh* *) Bash(bash *skills/_lib/detect-project.sh* *) Bash(bash *skills/validate/validate.sh* *)'
---
Fix a **multi-task initiative** (phases, dependencies, or more than a couple of atomic steps) into `.task/roadmap/<slug>.md`. Multi-task counterpart to `/task:to-task` / `/task:to-plan` (which each fix one task). Depth is fixed: one roadmap file, flag-free.
**Input:** `$ARGUMENTS` — a rough description of the initiative, or a reference back to a prior discussion in this conversation ("build a roadmap from what we discussed").
**Format contract:** [docs/contract.md § Roadmap file format](../../docs/contract.md#roadmap-file-format-taskroadmapslugmd) is the single source of truth for the output structure. This file describes the authoring flow that produces it.
## Instructions
### Step 0: Setup gate
The entry state, gathered before this skill reached you — no tool call of your own:
!`bash "${CLAUDE_PLUGIN_ROOT}/skills/_lib/preflight.sh" roadmap`
[docs/contract.md § Helpers](../../docs/contract.md#helpers) owns that block's shape. Read it, then act:
1. `AI_DIR:` is the pipeline root: `.task/roadmap/<slug>.md` below means `$AI_DIR/roadmap/<slug>.md`, **never a cwd-relative path** ([contract § Setup-gate categories](../../docs/contract.md#setup-gate-categories)).
2. **`CONFIG: absent`** → this skill is intake-capable: read `${CLAUDE_PLUGIN_ROOT}/skills/_lib/setup.md` and follow it — it owns the sub-steps and the `.task/CLAUDE.md` template — then continue. No confirmation chip; a wrong detected value is fixed by editing the file.
- 3. **`CONFIG: present`** → leave the file untouched: it is user-owned, and only a missing `.task/.gitignore` is recreated, by the preflight above itself; `task.root` is written by first-run setup and not restored afterwards.
- 4. `ROADMAPS:` lists the roadmaps that already exist, with progress — Step 1 matches structural style against them and Step 4's slug-collision check reads the same list, so neither needs a listing call of its own.
+ 3. **`CONFIG: present`** → leave the file untouched: it is user-owned, and only `task.root` and the `.git/info/exclude` line are restored when missing.
+ 4. `ROADMAPS:` lists the roadmaps that already exist, with progress — the capture flow's context step matches structural style against them and its save step's slug-collision check reads the same list, so neither needs a listing call of its own.
If that block arrived unexpanded — the command line itself rather than its output — the preprocessing did not fire: run that command yourself and continue exactly as above.
- There is no full-scan validate call here: Step 4 validates the one file it writes, and pre-existing artifacts are checked on demand with `validate.sh all`, never as an entry gate.
-
- ### Preconditions
-
- - **Too small for a roadmap** — no obvious phases, no inter-task dependencies, fewer than ~3 atomic steps → **stop and suggest** `/task:to-task` or `/task:to-plan`. Say plainly that nothing was written; after several brainstorm rounds the user cannot otherwise tell whether a half-roadmap now exists. Carry **both** options with the reason: "This is one task, not an initiative — no phases, no cross-item dependencies. Nothing was written. `→ Next: \`/task:to-plan\` to capture it with a plan, or \`/task:to-task\` for the what-and-why only.`"
-
- (The slug-collision check runs at save time, once the slug is derived — see Step 4.)
-
- ### Step 1: Load context
-
- One parallel batch, since none of these depends on another: `.task/CLAUDE.md` (Language, conventions), the project's `CLAUDE.md` if present, and the `docs/` top level. Structural style comes from Step 0's `ROADMAPS:` list — open one only when this initiative may overlap it, and declare that one as a Prerequisite. No source files: this is a shallow scan, not investigation.
-
- ### Step 2: Cold start or harvest
-
- **Branch first** — where the decisions come from matters:
-
- - **Harvest** — this conversation already settled concrete decisions about **this same initiative**, small details included. Tells: "build a roadmap from what we discussed", or `$ARGUMENTS` reading as a handle for prior discussion. → Step 2H.
- - **Cold start** — a rough few-line description, no prior initiative-specific discussion. → Step 2C.
-
- On the fence, prefer harvest: a false positive costs one recap the user skims, a false negative silently drops details.
-
- #### Step 2H: Harvest — Decision Inventory
-
- Comb the prior conversation and print, as message text in your reply (chat-only, never written to a file; heading skeleton English, prose in the language from `.task/CLAUDE.md`):
-
- ```
- ## Roadmap — Decision Inventory
-
- {Building this roadmap from our discussion — here is every decision I
- captured. Say so if a line is wrong.}
-
- ### Decisions locked so far
- 1. {one locked decision at full specificity — small details included
- verbatim, e.g. "the button is first in the panel"}
- 2. {...}
-
- ### Open forks (not yet decided)
- - {unresolved question left by the discussion}
-
- ### Coverage caveat
- {Only if part of the discussion is out of context — a false alarm
- erodes trust. Omit the heading otherwise.}
- ```
-
- It is a **recap** of decisions the user already reached: print it, no confirmation chip. Open forks left → resolve them in one focused round (Step 2C's shape) first, then draft. A misread arrives as chat: correct it and reprint before drafting.
-
- #### Step 2C: Cold start — brainstorm round
-
- ```
- ## Roadmap — Round 1
-
- ### Initiative as I understand it
- {2–4 sentences, including scope ambition.}
-
- ### Decomposition options
- **A) {name}** — {sketch}
- - Phases: {...}
- - Pros / Cons: {...}
- - Fits when: {...}
-
- **B) {alternative}** — {sketch}
- ...
-
- ### My recommendation
- {2–4 sentences, a real opinion, not a hedge.}
-
- ### Risks and forks I want to flag
- - {specific to this initiative — not generic}
-
- ### What I need from you
- {One focused question on the most load-bearing fork.}
- ```
-
- Always **2–3 decomposition options** with different phase boundaries — behavioral milestones, observable state changes, not technical layers like "substrate" vs "UI". Iterate as `Round N`, same structure, narrowed to the fork in focus. A round is **content dialogue, not a path fork**: print it as message text and close on the open question, because convention (c)'s chips would flatten the pros and cons the round exists to show. Typical depth 3–6 rounds; past 6, say the initiative is too big and suggest splitting. Stop when the user says "write it", or when another round would only restate conclusions.
-
- **Track decisions as you go, not in your head.** Two kinds surface: **behavioral** ones, observable properties the user locked in, which land in an item's `### Outcomes` / `### Acceptance criteria`; and **technical anchors** — a protocol, a cross-cutting data shape, a "we picked X over Y because…" whose reasoning would not survive re-derivation — which belong in a standalone spec, never in an item body. Step 3 routes both.
-
- Before drafting, reprint the full list as message text — the cold-start twin of Step 2H's inventory, no confirmation chip. Topics the user said to skip stay skipped.
-
- ### Step 3: Draft the file
-
- Once the Step 2H inventory (or the Step 2C recap) is **printed** — no reply is awaited; a correction arrives as chat, and you reprint before drafting — draft the whole file per [contract § Roadmap file format](../../docs/contract.md#roadmap-file-format-taskroadmapslugmd), which owns the section skeleton, the item grammar and the link rules. Two things it is easy to get wrong:
-
- - `**Dependencies:**` is an em dash `—` for none, otherwise a comma-separated list of item numbers. Any other word reads as a dependency on a missing item and hard-stops the autopilot.
- - A `**Ready description:**` blockquote must stand alone, and its sub-headings are **quoted** (`> ### Context`, …). `validate.sh` treats a bare unquoted one as a hard error, because `to-plan` strips the `> ` prefix to find the body.
-
- **Route every confirmed decision to a home:**
-
- - Observable behavior / user-facing effect → the item's `### Outcomes`, or `### Acceptance criteria` when it's a testable assertion.
- - Cross-item technical decision → a standalone spec. One that already exists gets a `Spec:` header line **directly under `# <Title>`**, above the intro, plus a `### Spec references → [<spec-slug>](../spec/<spec-slug>.md) §N` citation in each steered item. One that does not exist is **not written here**: surface the decision with a one-line recommendation to capture it via `/task:to-spec`, and reference it on a later run.
- - Scope exclusion → `## Out of scope`, with the reason.
- - Anything else → drop it, but say so to the user with a one-line reason — never a silent omission.
-
- Reserve specs for choices that would break cross-item consistency if a later `/task:to-plan` re-derived them differently. A single-item detail is that item's `### Outcomes` / `### Acceptance criteria`, never a spec.
-
- **`**Model:**` is optional** — only with a real basis: pure content editing → `haiku`, a new subsystem or cross-module change → `sonnet`. Leave it off rather than guess.
-
- Behavioral discipline: `### Outcomes` / `### Goal` / `### Invariants` state observable properties only, with no project-specific file or symbol names (normative names from a spec or `CLAUDE.md` are fine). If design work would be free to pick a different symbol, the name is `/task:to-plan`'s call, not this file's.
-
- Before saving, self-check and fix inline (drafting hygiene; Step 5 is the post-save pass):
-
- 1. Every fork raised in the brainstorm has a home in some phase, or an explicit `## Out of scope` mention.
- 2. Each `**Ready description:**` stands alone — a reader who hasn't seen the roadmap could pick it up in `/task:to-plan` from the blockquote alone.
- 3. No placeholders (`TBD`, `TODO`, `???`, `fill in`).
- 4. Every `**Dependencies:**` cites a task number that exists in this file.
- 5. Every item heading produces a unique kebab-case slug.
- 6. Item numbers unique across the whole file — the driver's auto-mark keys on the number, so two items sharing one would be ticked together.
- 7. Every confirmed decision (Step 2) has a concrete home, or was explicitly dropped with a stated reason.
- 8. Every cross-artifact reference is a Markdown link — `Spec:` headers, `### Spec references` citations, `## Prerequisites`, `## Backlinks`.
-
- ### Step 4: Save
-
- Write the file directly — no in-chat preview, no confirmation prompt.
-
- 1. Slug: kebab-case from the initiative title, ≤ 50 chars (`add-auth-flow`, `migrate-to-vite`).
- 2. **Slug collision.** If that slug is already in Step 0's `ROADMAPS:` list → **stop** and pose an `AskUserQuestion` (**Overwrite** / **Pick different slug**). Never silently overwrite. That list is a snapshot taken before the brainstorm rounds, and unlike the task captures there is no writer script to refuse a collision here — so when the slug is *absent* from it, confirm with a file read that nothing is there before writing.
- 3. Write `$AI_DIR/roadmap/<slug>.md` (creating the directory if needed) with the full content, `Spec:` headers included. Nothing else is written — spec authorship is `to-spec`'s.
- 4. Validate it: `bash "${CLAUDE_PLUGIN_ROOT}/skills/validate/validate.sh" roadmap <slug>` — surface any WARN/ERROR in the Step 6 digest; only a setup-precondition failure (exit 2) hard-stops.
-
- ### Step 5: Light self-check (report-only)
-
- Skim the **saved file** (not the in-chat draft) yourself — no subagent fanout, no lens-audit machinery — against three lenses:
+ There is no full-scan validate call here: the save step validates the one file it writes, and pre-existing artifacts are checked on demand with `validate.sh all`, never as an entry gate.
- - **Coverage** — phase and fork coverage, dependency integrity (dangling or cyclic).
- - **Decomposition** — any item reading as compound: two unrelated concerns, or far more outcomes than its neighbours.
- - **Clarity** — behavioral discipline held, descriptions self-contained, and each `### Spec references` citation naming a `Spec:`-referenced `$AI_DIR/spec/<spec-slug>.md` that really has that `§N`, with a target matching its label (a copied citation pointing at the previous spec still resolves for an agent and misleads the human).
+ ### Steps 1–5: Precondition, context, harvest, draft, save, self-check
- Report a count per lens plus the obvious issues, a few lines. **Never rewrite the saved file** — findings are for the user to fix or discuss; there is no auto-apply.
+ Read `${CLAUDE_PLUGIN_ROOT}/skills/_lib/roadmap-capture.md` § **Core** and follow it — its too-small precondition, then steps 1 (context) through 5 (the post-save self-check). It is the single owner of the roadmap capture flow: the harvest-or-brainstorm branch, the decision routing, the drafting self-check, the slug-collision guard, the write and the validate call. Step 0's `AI_DIR:` and `ROADMAPS:` are the inputs it expects from you; the digest below is yours.
### Step 6: Output — digest
Print the structural digest of what was written (convention (b)) as message text — enough for the user to judge at a glance whether to open the file:
```
Wrote `.task/roadmap/<slug>.md`
{Title}
Items: {N} tasks across {M} phases — recommended order: 1 → 2 → 4 → 3 → 5 …
- 1. {item title}
- 2. {…}
Specs referenced: {slug, …} (or "none"; plus any decision flagged for a `/task:to-spec` follow-up)
validate: {OK — 0 errors, N warning(s) | the FAIL lines}
```
- On a result that is **not** clean, append `re-check after editing: bash "${CLAUDE_PLUGIN_ROOT}/skills/validate/validate.sh" roadmap <slug>` — `validate` is not a slash command, so it is worth spelling out. Omit it on a clean result.
- - Print the Step 5 findings summary (or "clean / minor only").
+ - Print the self-check findings summary from Core step 5 (or "clean / minor only").
- The file is already written — to change anything, just say so.
- End with the next-step footer, naming the slug in **both** halves so either is pasteable as-is: `→ Next: \`/task:roadmap-to-workflow <slug>\` (run the whole roadmap) or \`/task:to-task <slug>#1\` (pick up the first item by hand — any item number works).`
## Forbidden
- - Naming project-specific files, modules, functions, types, or constants in `### Outcomes` / `### Goal` / `### Invariants` — normative names from spec/CLAUDE.md are the only exception.
- - Planning implementation details (file lists with line numbers, function signatures, code blocks > 5 lines) — that is `/task:to-plan`'s job when the item is picked up.
- - Modifying any file other than `.task/roadmap/<slug>.md` — specs live at `.task/spec/<slug>.md` and are authored only by `to-spec`, never written or edited here.
- - Auto-checking / auto-unchecking item checkboxes — ticking `- [x]` happens inside the executing session (or, in a roadmap run, the `roadmap-to-workflow` **driver**), never here and never inside a per-item agent.
- - A single-direction monologue in a decomposition round — offer ≥ 2 options or explicitly justify why only one is viable. (The Decision Inventory and the cold-start recap are chat-only recaps, not decomposition rounds — exempt.)
- - Generic risks ("watch out for bugs") — risks must be specific to the initiative and project.
- - More than one initiative per file — split and pick one for this run.
- - Persisting topics the user asked to skip; placeholders anywhere.
- - Writing a `.refine.md` sidecar, a `.spec.md` sidecar, or a `.lock` file — none of those exists in the pipeline.
+ Everything in `roadmap-capture.md` § **Forbidden** — it binds every roadmap the flow writes.