@connorbritain/roadmap 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +495 -0
  2. package/docs/DEPLOYMENT.md +195 -0
  3. package/package.json +46 -0
  4. package/schema/backlog.schema.json +65 -0
  5. package/schema/roadmap.schema.json +273 -0
  6. package/scripts/assistant.mjs +30 -0
  7. package/scripts/backlog.mjs +81 -0
  8. package/scripts/cleanup.mjs +69 -0
  9. package/scripts/cli.mjs +119 -0
  10. package/scripts/cycle.mjs +89 -0
  11. package/scripts/dispatch.mjs +302 -0
  12. package/scripts/estimate.mjs +201 -0
  13. package/scripts/fanout.mjs +355 -0
  14. package/scripts/grab.mjs +119 -0
  15. package/scripts/init.mjs +60 -0
  16. package/scripts/lib/assistant-core.mjs +64 -0
  17. package/scripts/lib/backlog-core.mjs +318 -0
  18. package/scripts/lib/brief.mjs +123 -0
  19. package/scripts/lib/cli-core.mjs +97 -0
  20. package/scripts/lib/cycle-core.mjs +58 -0
  21. package/scripts/lib/estimate-core.mjs +204 -0
  22. package/scripts/lib/execution.mjs +186 -0
  23. package/scripts/lib/fanout-core.mjs +39 -0
  24. package/scripts/lib/graph.mjs +346 -0
  25. package/scripts/lib/journal-core.mjs +48 -0
  26. package/scripts/lib/linear-core.mjs +812 -0
  27. package/scripts/lib/mcp-core.mjs +313 -0
  28. package/scripts/lib/plan.mjs +68 -0
  29. package/scripts/lib/plate-core.mjs +53 -0
  30. package/scripts/lib/pr-watch-core.mjs +72 -0
  31. package/scripts/lib/priority.mjs +43 -0
  32. package/scripts/lib/recommend.mjs +178 -0
  33. package/scripts/lib/render-core.mjs +215 -0
  34. package/scripts/lib/review-core.mjs +104 -0
  35. package/scripts/lib/store.mjs +113 -0
  36. package/scripts/lib/sync-core.mjs +89 -0
  37. package/scripts/lib/validate-core.mjs +130 -0
  38. package/scripts/lib/wizard-core.mjs +50 -0
  39. package/scripts/linear.mjs +780 -0
  40. package/scripts/mcp.mjs +193 -0
  41. package/scripts/next.mjs +43 -0
  42. package/scripts/plate.mjs +77 -0
  43. package/scripts/promote.mjs +27 -0
  44. package/scripts/prompt.mjs +124 -0
  45. package/scripts/render.mjs +39 -0
  46. package/scripts/review.mjs +79 -0
  47. package/scripts/scheduler.mjs +78 -0
  48. package/scripts/set.mjs +31 -0
  49. package/scripts/show.mjs +53 -0
  50. package/scripts/test/run.mjs +3943 -0
  51. package/scripts/validate.mjs +28 -0
  52. package/scripts/watch-prs.mjs +72 -0
  53. package/scripts/wizard.mjs +97 -0
package/README.md ADDED
@@ -0,0 +1,495 @@
1
+ # Roadmap: scope, manage, and orchestrate AI coding sessions in any repo
2
+
3
+ `roadmap` is a CLI, MCP server, and Claude Code plugin. It turns two YAML files into your repo's plan of record — a **hierarchical, dependency-aware roadmap graph** plus a **prioritized backlog** for the work that surfaces erratically — then **fans that plan out into parallel coding sessions**, each scoped to a single unit of work in its own git worktree.
4
+
5
+ In a Codex environment, the primary surfaces are the CLI, the MCP server, and the repo-level [`AGENTS.md`](AGENTS.md). The Claude plugin assets are included for teams using them.
6
+
7
+ - **One source of truth (each).** `docs/roadmap/roadmap.yaml` holds the PIs, sprints, deps, priorities, file-ownership, session estimates, gates, prompts, and kickoff briefs. `docs/roadmap/backlog.yaml` holds the erratic work: follow-ups, bugs, chores, urgent items.
8
+ - **Generated views.** `docs/SLICES.md` and `docs/BACKLOG.md` are *rendered* from the YAML; never hand-edit them.
9
+ - **Derived, never stored.** Per-PI exec-plan lines (`(S0 ∥ S1)→S2→S3`), the cross-PI "ready now" wave map, "sessions remaining" rollups, and priority ordering are all computed from `deps` + `touches` + `status` + `priority`.
10
+ - **Deterministic fanout with feasibility pre-checks.** A scheduler decides which slices can run concurrently under a cap it *recommends* from five real ceilings — CPU, RAM, independent work, human review, and **free disk for the worktrees** — then launches each in its own worktree and Claude Code session. When even one worktree won't fit on disk, launch is refused before anything is created.
11
+ - **Zero-prompt pickup.** Stash the pickup instructions on the slice itself (`prompt:`); `/slice <key>` or `roadmap grab <id>` is then all a session needs.
12
+ - **Repo-agnostic.** The resource classifier reads the build/test runner command in each sprint's gate (not its language) to size the session. It recognizes the common runners across JS/TS, Python, Java/Kotlin, C/C++, Go, Rust, and Ruby, and `meta.weight_patterns` teaches it anything bespoke. Nothing is hardcoded to one stack.
13
+
14
+ ---
15
+
16
+ ## Concepts
17
+
18
+ `roadmap` has a small, deliberate vocabulary:
19
+
20
+ | Term | What it is |
21
+ |---|---|
22
+ | **Roadmap** | The whole graph: every PI and sprint in `roadmap.yaml`. The map of *all* the work. |
23
+ | **PI** *(Program Increment)* | A top-level initiative or epic. Groups related sprints; carries a status, dependencies, and exit criteria. |
24
+ | **Sprint** | A unit of work inside a PI (`s1`, `s2`, ...). Carries its deps, the files it `touches`, a session estimate, a verification `gate`, and a kickoff brief. |
25
+ | **Slice** | A sprint *as the thing you act on*, addressed by its stable `invoke` key (e.g. `auth-sessions`): "show me a slice", "fan out this slice." The slice is the atomic, **launchable** unit. |
26
+ | **Wave** | The set of slices that can run **concurrently right now**: mutually dependency-free, sharing no files, under the cap. Within a wave, declared `priority` decides who gets a scarce cap slot. |
27
+ | **Fanout** | Launching a wave. One git worktree plus Claude Code session per slice, plus an optional **lead** session that reviews and merges the resulting PRs. |
28
+ | **Backlog** | The tracker beside the roadmap for **erratic work** — follow-ups, bugs, chores, urgent items that surface outside the plan. Items are directly launchable (`roadmap grab <id>`) or promotable into roadmap sprints (`roadmap promote <id> --pi <pi>`), cross-linked both ways. |
29
+ | **Priority** | `{ tier: P0–P3, weight: 0–100, reason }` on any sprint or backlog item. Sort order is derived (tier, then weight), never stored — resorting is just editing the fields. |
30
+
31
+ > **Roadmap = the planned feature/value work. Backlog = the erratic work. Slice = one launchable piece of either.**
32
+ > You edit the **YAML**; you launch **slices** (by `invoke` key) and **backlog items** (by id). `SLICES.md` / `BACKLOG.md` are the human-readable renders, generated and never hand-edited.
33
+
34
+ ---
35
+
36
+ ## Quickstart
37
+
38
+ ```bash
39
+ # 1) one-time: install deps + put the `roadmap` CLI on your PATH
40
+ git clone https://github.com/ConnorBritain/roadmap.git
41
+ cd roadmap && npm install && npm link
42
+
43
+ # 2) in any repo, author docs/roadmap/roadmap.yaml (see "The roadmap.yaml model")
44
+
45
+ # 3) from ANYWHERE inside that repo (root or a subdir; the roadmap is auto-discovered):
46
+ roadmap # interactive console: pick terminal / wave / cap, then launch
47
+ roadmap plan # the text plan: recommended cap + what's runnable (no prompts)
48
+ roadmap next # the single highest-priority ready thing across roadmap + backlog
49
+ roadmap render # regenerate docs/SLICES.md (+ docs/BACKLOG.md when a backlog exists)
50
+ roadmap validate # structural + cycle checks
51
+ roadmap fan -w 1 # spin up wave 1 (lead + slice sessions); add -d to preview first
52
+
53
+ # and the erratic-work loop:
54
+ roadmap backlog add "wt adapter mangles quotes" -k bug --tier P0 --why "breaks every fanout"
55
+ roadmap grab b1 # launch that one item in its own worktree + session
56
+ roadmap promote b2 --pi auth # or fold a bigger one into the roadmap as a sprint
57
+ ```
58
+
59
+ That's the whole loop: `cd` into a repo, type `roadmap ...`, it finds the roadmap and fires.
60
+
61
+ ### Using it in Codex
62
+
63
+ - Codex reads [`AGENTS.md`](AGENTS.md) from this repo automatically, so repo conventions live there now.
64
+ - You can drive everything from the shared terminal with `npm run plan`, `npm run validate`, `npm run render`, or `node scripts/cli.mjs ...`.
65
+ - `npm run mcp` starts the same MCP server the Claude plugin uses.
66
+ - The fanout launcher still opens `claude` worker sessions today; the rest of the repo is usable from Codex directly.
67
+
68
+ ---
69
+
70
+ ## The three surfaces
71
+
72
+ The same engine (`roadmap.yaml` plus the graph brain) driven three ways.
73
+
74
+ ### 1 · The `roadmap` CLI (from your shell)
75
+
76
+ Run from anywhere inside a repo. `docs/roadmap/roadmap.yaml` is found by walking up from your cwd, and every subcommand runs with cwd set to that repo root. Two ways to drive it:
77
+
78
+ - **Interactive console.** Bare `roadmap` in a terminal opens a guided picker: terminal, then max concurrency, then wave, then lead?, then launch / preview / save. Walk the prompts with the arrow keys and hit Enter. Best when you want to *see* what's runnable and choose. (Piped or non-interactive, bare `roadmap` prints the text plan instead, so scripts and CI are unaffected; `roadmap go` forces the console.)
79
+ - **Flag-fed.** Every choice as a flag: `roadmap fan -w 1 -c 2 -t wt`. No prompts, same outcome, for muscle memory, aliases, and scripts.
80
+
81
+ | Command | What it does |
82
+ |---|---|
83
+ | `roadmap` / `roadmap go` | The **interactive console** (above). Hot-loads this repo's roadmap and walks you through the launch. Worker permission mode isn't asked here; it comes from `meta.worker_mode`. |
84
+ | `roadmap plan [-c N] [--review-ceiling N] [--use-free-ram] [-j]` | **Recommended cap** (and what constrains it — CPU / RAM / work / review / disk), the execution **waves** (priority-ordered), and per-node launch commands. Spawns nothing. `-j/--json` emits the plan for tooling. |
85
+ | `roadmap next` | The **single highest-priority ready thing** across the roadmap AND the backlog, with its pickup brief. Roadmap wins ties. Read-only. |
86
+ | `roadmap show <name>` | One slice's detail: what / priority / stashed prompt / read-order / next / gate / branch. |
87
+ | `roadmap set <name> f=v [...]` | Edit a slice's fields from the shell: YAML-scalar values (`priority='{tier: P1, weight: 60}'`), `f=@file` for multiline (prompts/briefs), `f=null` deletes. Same allow-list + pre-write gate as the MCP tools. |
88
+ | `roadmap render [-c N] [-s]` | Regenerate `docs/SLICES.md` (+ `docs/BACKLOG.md` when a backlog exists) from the YAML (`-s/--stdout` prints SLICES instead of writing). |
89
+ | `roadmap validate` | Structural, dependency, and cycle checks. Non-zero exit on error. |
90
+ | `roadmap backlog [list\|add\|set]` | The erratic-work tracker: `add "title" [-k kind] [--tier PN] [--weight N] [--why reason] [--slice invoke]` (first add creates `backlog.yaml`), `set <id> f=v ...`, bare = priority-sorted open items. |
91
+ | `roadmap grab <id> [-t term] [--dry]` | Launch **one backlog item** in its own worktree (`<root>/backlog-<id>`, branch `backlog/<id>`) with a synthesized kickoff brief (the item's `prompt` embedded). Marks it `in_progress`. |
92
+ | `roadmap promote <id> --pi <pi> [--id sN]` | Promote a backlog item into a roadmap **sprint** (item id becomes the invoke key; title/est/gate/touches/prompt/priority carry; `promoted_to` back-links). Both YAMLs validated before either is written. |
93
+ | `roadmap linear status\|auth\|setup\|provision\|sync\|post-update` | Optional **Linear** integration (see [Linear](#linear-optional--project-manage-from-linear-while-agents-execute)): `status [--probe]` state check, `auth` env-var instructions, `setup --team KEY` guided config, `provision` (labels + views + guidance texts), `sync [--dry] [--push-only] [--pull-only]`, `post-update --pi <id> --body <text>` (digest → project update). |
94
+ | `roadmap review [--since <rev\|date>] [-j]` | The **date-anchored review digest**: shipped vs captured vs aging vs new PIs vs sprawl since `meta.last_review` (git-snapshot diff). The `/debrief` and `/retro` engine; works with zero Linear. |
95
+ | `roadmap dispatch <key> [--to claude]` | Send one slice/backlog item to a **cloud agent** via its Linear issue (v0.5 seam, pending live verification). `roadmap fan --cloud` does the whole wave — no worktrees, no disk ceiling. |
96
+ | `roadmap fan [-t wt\|warp\|tmux\|print\|background] [-c N] [-w N] [--track A] [--lead-claude] [-d] [-o file] [--worker-mode <m>] [--autonomous --yes-spawn-autonomous]` | Launch a wave: a lead pane/tab plus one per slice, each in its own worktree with a synthesized kickoff brief. **Launches by default**; `-d/--dry` or `-o/--out` to preview. `--track <lane>` fans out only the slices in that lane. Worker **and** lead sessions take `--permission-mode` from `meta.worker_mode` (falls back to `plan`); `--worker-mode` overrides per run. Terminal defaults per platform (win32 to `wt`, else `tmux`). |
97
+ | `roadmap cleanup [-r] [-f]` | Prune fanout worktrees merged into the base branch and clean. **Dry by default**; `-r/--remove` acts; `-f/--force` includes unmerged/dirty. Only touches worktrees under the worktree root. |
98
+ | `roadmap mcp` | Run the MCP server (stdio JSON-RPC) directly, for debugging or non-plugin registration. The plugin starts it for you. |
99
+ | `roadmap watch` | Watch this roadmap's fanout PRs and print a line as each becomes ready / conflicts / merges. The plugin runs it as a monitor; this is the manual pane version. |
100
+ | `roadmap sync` / `roadmap init` | Reserved on the CLI. Reconcile and bootstrap live as the `/sync` and `/init` **plugin skills** (surface 2). |
101
+
102
+ Short flags (`-w -c -t -d -o -j -r -f -lc -wm`) expand to their long forms; positional slice keys pass through untouched.
103
+
104
+ ```bash
105
+ # See the plan + why the cap is what it is (the binding constraint is reported):
106
+ roadmap plan
107
+ # Concurrency cap: 5 (recommended)
108
+ # bound by: review (PR review/merge bottleneck, soft ceiling)
109
+ # machine: 24 cores, 59.6GB total / 20.6GB free
110
+ # ceilings: 12 [CPU] · 13 [RAM] · 23 [work] · 5 [review] · 41 [disk]
111
+ # Wave 1, 5 concurrent: [P0] auth-sessions, billing-invoices, search-index, ...
112
+
113
+ roadmap fan -w 1 # launch: lead + one watched session per slice (default)
114
+ roadmap fan -w 1 -d # preview the launch script, spawn nothing
115
+ roadmap fan -w 1 -o wave1.sh # write the script to a file to inspect/run yourself
116
+ roadmap fan -c 3 # override the recommended cap
117
+ roadmap fan --autonomous --yes-spawn-autonomous # headless workers that commit/push/PR (double-acked)
118
+ ```
119
+
120
+ **Safety.** `fan` launches by default, but an interactive launch just opens watchable panes (you're at the keyboard). Preview without spawning via `-d` or `-o`. The only unattended mode, `--autonomous` (headless `claude -p` that commits/pushes/PRs), additionally requires `--yes-spawn-autonomous`. **No launched session ever merges:** each opens a PR and stops; the lead (or you) merges. If `tmux` isn't on PATH (e.g. you're in PowerShell), `fan` prints the script and how to run it in WSL instead of failing.
121
+
122
+ ### 2 · The Claude Code plugin (inside a session)
123
+
124
+ Install it as a plugin (see [Install](#install)) and the roadmap becomes an *in-session* surface: slash-command **skills**, **agents**, and a startup **hook**.
125
+
126
+ - **Skills** (`skills/*/SKILL.md`)
127
+ - `/slice <key>`: orient on one slice (read-only) — what, priority, the stashed `prompt` (relayed verbatim), read-order, next action, gate, branch. With a prompt stashed, this is the whole pickup: slash command + slice name, nothing else.
128
+ - `/sync`: reconcile statuses against merged PRs and the tracker, harvest PR-body "Leftovers" into proposed backlog captures, then re-render `SLICES.md`.
129
+ - `/init`: a PM-style interview that bootstraps a `roadmap.yaml` (warm-start from existing docs, or cold).
130
+ - `/fanout`: compute the waves and launch (wraps the same scheduler and adapters as the CLI).
131
+ - `/backlog`: capture + triage erratic work — normalizes your dump into prioritized items, then offers `grab` or `promote` per item.
132
+ - `/imagine`: divergent strategy interview on a live roadmap — vision drift, bets, risks/cuts — whose every conclusion lands **in the graph** (north-star pointer, new PIs, thin scheduled slices). `/init` bootstraps; `/imagine` re-plans.
133
+ - `/prioritize`: convergent tier-by-tier triage of ready slices + open backlog with a forced reason per placement ("these two can't both be P1 — which ships first and why?"); source-aware (an item from a public Linear intake team is weighted knowingly); writes in one atomic `bulk_set`.
134
+ - `/debrief`: the atomic lookback — date-anchored digest under hard high-signal rules, captain's-log entry in `docs/roadmap/REVIEWS.md`, anchor update. No graph mutations.
135
+ - `/retro`: the full review-and-redirect ritual — debrief's lookback + per-bet double-down/kill/defer decisions applied to the graph + optional `/imagine` handoff.
136
+ - **Hook** (`hooks/hooks.json`): a `SessionStart` hook injects the at-a-glance plus the current ready-wave and the backlog open-count, so a fresh session immediately knows what's runnable (and, on first run, installs the `yaml` dep).
137
+ - **Agents** (`agents/*.md`): four specialized subagents Claude invokes across the roadmap, fanout, and review lifecycle.
138
+
139
+ | Agent | Role | Read/write | Suggested model |
140
+ |---|---|---|---|
141
+ | **roadmap-bootstrapper** | Cold/warm-start: reads the repo's existing roadmap docs, tracker, sprint dirs, and `git log`, and **drafts a `roadmap.yaml`**. Used by `/init` to pre-fill before the interactive confirmation. | reads repo, proposes YAML | sonnet |
142
+ | **slice-scoper** | Takes a thin `scheduled` slice and **fills it in**: infers `touches`/`owns` by grepping the code, drafts `read_order`, `est_sessions`, and the `gate`, and writes the sprint spec, turning it into a `next`-ready slice. | reads code, proposes slice fields | sonnet/opus |
143
+ | **roadmap-auditor** | Read-only **drift and gap finder**: audits `roadmap.yaml` against reality (merged PRs, strategy docs, sprint dirs) and reports stale statuses and un-surfaced work. | read-only report | sonnet |
144
+ | **wave-shepherd** | The **lead-pane brain**: after a fanout wave produces PRs, reviews each against its slice's gate and scope and recommends a safe **merge order** (respecting deps, flagging conflicts). Reviews; never merges. | read-only review | opus |
145
+
146
+ The CLI and the plugin share the same scripts: the CLI is your *shell* entry, the plugin is the *in-session* entry. The interactive PM interview stays a **skill** (not an agent), because a forked subagent can't hold a back-and-forth with you.
147
+
148
+ ### 3 · MCP (agent-callable)
149
+
150
+ The plugin ships its own MCP server — named **`graph`** in `.mcp.json`, auto-started on install (plugin tool ids read `mcp__plugin_roadmap_graph__*`) — so an agent drives the roadmap with typed tools instead of shelling out and parsing text:
151
+
152
+ - **Read:** `plan`, `ready_wave`, `show`, `validate`, `backlog_list` return structured JSON.
153
+ - **Mutate (roadmap):** `add_pi`, `add_sprint`, `set_status`, `set_fields`, `bulk_set` (atomic multi-slice edit: one validate, one write, one render — all-or-nothing), `prune` edit `roadmap.yaml` through the YAML Document API (comments preserved), refuse any edit that would corrupt the graph (duplicate invoke key, unresolved dependency, cycle, bad priority/execution block), and re-render `SLICES.md` in the same step.
154
+ - **Mutate (backlog):** `backlog_add` (creates `backlog.yaml` on first capture), `backlog_set`, and `backlog_promote` (spans both files: both validated before either is written).
155
+ - **Linear:** `linear_status` (zero-network state check) and `linear_sync { dry, push, pull }` — always registered, politely erroring with setup guidance when `meta.linear` is absent.
156
+ - **Cloud dispatch:** `dispatch { key }` fires one cloud session; `fan_cloud { wave, cap, confirm }` conducts a whole wave — **previews by default, fires only on `confirm: true`**, returning the session URLs. This is the conductor pattern: a local session plans the wave, fires cloud workers on its own plan (no worktree/disk), and reconciles their PRs via `/sync`.
157
+
158
+ Launched worker sessions are told to file leftovers before opening their PR — `backlog_add` if the MCP is available, `roadmap backlog add` if the CLI is linked, else a **Leftovers** section in the PR body that `/sync` harvests.
159
+
160
+ Mutators are natural `ask`-list entries in a consuming repo's `.claude/settings.json` (reads can be `allow`-listed). Separately, launched fanout sessions inherit whatever other MCP servers your repo already has wired, so a worker can drive your issue tracker or database while it works its slice.
161
+
162
+ ---
163
+
164
+ ## The roadmap.yaml model
165
+
166
+ ```yaml
167
+ meta:
168
+ schema_version: 1
169
+ program: Q3-PLATFORM
170
+ default_gate: | # inherited by sprints whose gate is 'default'/{{default}}
171
+ npm test
172
+ base_branch: main # worktree base + PR base (default main)
173
+ remote: origin # git remote (default origin)
174
+ terminal: tmux # default fanout adapter: tmux|warp|wt|background|print
175
+ worker_mode: plan # launched sessions' --permission-mode: plan|auto|acceptEdits|bypassPermissions
176
+ agent_cmd: "claude --permission-mode {mode} {prompt}" # optional: launch a different agent
177
+ default_concurrency: 3
178
+ # Optional: teach the resource classifier a bespoke runner / override per-class cost
179
+ weight_patterns: { heavy: ["my-e2e-suite"], medium: ["my-bundler"] }
180
+ weight_cost: { heavy: { ram: 5, cores: 3 } }
181
+ # Optional: the renderer cross-links these in SLICES.md (omit any you don't have)
182
+ links: { narrative: ROADMAP.md, status: ../STATUS.md, tracker: roadmap/TRACKER.md }
183
+
184
+ pis:
185
+ - id: auth # stable; == branch slug
186
+ title: Authentication
187
+ status: active # active|next|scheduled|complete|blocked|paused|gated|optionality
188
+ initiative: Launch readiness # optional; groups this PI's Linear project under a named Initiative
189
+ priority: { tier: P1 } # optional; STRATEGIC → Linear project priority (not slice-derived)
190
+ target_date: 2026-09-01 # optional; YYYY-MM-DD → Linear project target date
191
+ sprints:
192
+ - id: s1
193
+ title: Login flow
194
+ status: complete
195
+ invoke: auth-login # the slice key, stable, unique across the file
196
+ prs: ["#42"]
197
+ - id: s2
198
+ title: Session tokens
199
+ status: active
200
+ invoke: auth-sessions
201
+ deps: [s1] # sibling sprint id | pi-id/sprint-id | a whole PI id
202
+ est_sessions: 3 # focused sessions remaining (drives rollups + scheduling)
203
+ touches: [src/session.ts] # files written; used for two-wave contention detection
204
+ gate: |
205
+ {{default}}
206
+ PLUS the session integration tests
207
+ read_order: ["docs/auth.md (the design)"]
208
+ resume_action: Wire JWT issuance + refresh; thread through middleware.
209
+ priority: # optional; sort is derived (tier asc, weight desc), never stored
210
+ tier: P1
211
+ weight: 60
212
+ reason: launch blocker for the pilot
213
+ prompt: | # optional author-stashed pickup instructions — embedded VERBATIM
214
+ Start from the failing e2e test in tests/session.e2e.ts. # in the kickoff brief; shown
215
+ Do not touch the middleware pipeline. # by /slice and roadmap show
216
+ track: A # optional lane label (forward-compat with the three-track partition)
217
+ execution: # optional per-slice staffing-strategy hint (see below)
218
+ mode: agent-team
219
+ concurrency: 5
220
+ min_concurrency: 4
221
+ team:
222
+ - role: verifier
223
+ - role: implementer
224
+ count: 3
225
+ - role: reviewer
226
+ rationale: "16 disjoint fault-class files; verifier-first; one reviewer reconciles."
227
+ ```
228
+
229
+ - **`invoke`** is the slice key you launch with. Stable and unique across the file, so renaming a title never breaks a reference.
230
+ - **`deps`** are the DAG edges; the exec-plan line and wave map are *derived* from them.
231
+ - **`touches`/`owns`** mechanize the two-wave pattern: two ready slices that write the same file never share a wave; a convergence sprint just `deps`-on the divergent ones.
232
+ - **`gated_on: <name>`** marks a human-gated slice. It never auto-schedules; it surfaces under "held on a human."
233
+ - **`worker_mode`** sets the `--permission-mode` launched sessions start in; **`weight`** (`heavy|medium|light`) optionally overrides a sprint's inferred resource class.
234
+ - **`agent_cmd`** templates every INTERACTIVE worker/lead launch (`{mode}` + `{prompt}` tokens) so fanout can spawn codex or any other CLI agent; the default reproduces today's claude command byte-for-byte. Autonomous headless launches stay claude.
235
+ - **`priority`** (`{ tier: P0–P3, weight: 0–100, reason }`, all optional) decides who gets a scarce cap slot within a wave, badges the renders (`[P0]`), and drives `roadmap next`. Two unprioritized slices order exactly as before — an existing roadmap schedules and renders identically.
236
+ - **`prompt`** is the stashed init prompt: `/slice <key>` relays it, the synthesized kickoff brief embeds it verbatim (`## 0.5 Author instructions`), and it's updatable as new info comes in via `roadmap set <key> prompt=@notes.md` or the `set_fields`/`bulk_set` tools.
237
+ - **`execution`** declares HOW to staff the slice (see [Execution strategy hints](#execution-strategy-hints)); **`track`** tags the slice's lane for `--track`.
238
+
239
+ ### Execution strategy hints
240
+
241
+ Agents chronically **under-parallelize** — a lone subagent where a team fits, 2–3 workers where 5+ are fruitful, rarely reaching for Agent Teams. The optional per-slice `execution:` block lets the author *declare* the staffing so the launched session works at the intended topology instead of choosing by gut. **Every field is optional and backward-compatible: a slice that omits the block behaves exactly as before, and an existing `roadmap.yaml` validates and renders unchanged.**
242
+
243
+ ```yaml
244
+ execution:
245
+ mode: agent-team # solo | subagents | dynamic-workflow | agent-team
246
+ concurrency: 5 # suggested LIVE worker count
247
+ min_concurrency: 4 # floor — /sync warns if a run used fewer on disjoint files
248
+ team: # composition (omit for solo); roles: verifier|implementer|reviewer|researcher|integrator
249
+ - role: verifier
250
+ - role: implementer
251
+ count: 3
252
+ - role: reviewer
253
+ rationale: "16 disjoint fault-class files; verifier-first; one reviewer reconciles."
254
+ ```
255
+
256
+ **Modes** (the topology rubric):
257
+
258
+ | `mode` | When | What the directive tells the session |
259
+ |---|---|---|
260
+ | `solo` | Atomic, exploratory, or branching-sequential work. | Single agent, no fan-out. |
261
+ | `subagents` | A scoped sprint: lead-merges + disjoint-file workers (the current default). | Spawn N background subagents per CLAUDE.md § Subagent Hand-off. |
262
+ | `dynamic-workflow` | An in-slice pipeline whose steps depend on each other. | Run a step-gated pipeline; don't collapse it to one pass. |
263
+ | `agent-team` | Many genuinely-independent file-clusters needing peer coordination. | Invoke Agent Teams now (`CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`) with the named count + composition. |
264
+
265
+ The block renders as an **imperative directive** at the top of the slice's read-out — in `SLICES.md`, in `roadmap show` / `/slice`, and verbatim in each launched session's kickoff brief:
266
+
267
+ ```
268
+ ▶ EXECUTION: agent-team — 5 workers (1 verifier · 3 implementers · 1 reviewer).
269
+ The touched files are disjoint. DO NOT run solo or fewer than 4. Invoke Agent Teams now (set CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1).
270
+ Rationale: 16 disjoint fault-class files; verifier-first; one reviewer reconciles.
271
+ ```
272
+
273
+ **Validation** (`roadmap validate`) checks the enums (`mode`, `role`), the integer bounds (`concurrency`/`min_concurrency`/`count` ≥ 1), `min_concurrency ≤ concurrency`, and that a declared `team` head-count agrees with `concurrency` when both are present. When `execution` is absent or `concurrency` is unset, a *suggested* floor is computed from the slice's `touches` (the count of distinct disjoint top-level dir clusters, capped at 6) and surfaced as a hint — never a hard default. After a wave, `/sync` flags any slice that declared a `min_concurrency` floor, touches disjoint dirs, yet ran with fewer live workers (*"slice X ran 2 workers; min_concurrency 4 — under-parallelized"*).
274
+
275
+ **`--track`** lets one person fan out only their lane: `roadmap fan --wave 1 --track A` keeps just the wave's slices tagged `track: A` (forward-compat with the three-track partition).
276
+
277
+ ---
278
+
279
+ ## The backlog (backlog.yaml)
280
+
281
+ Roadmap work is planned, feature-driven, value-driven. But there's a second kind of work — follow-ups, necessary chores, trivial fixes, urgent/critical items — that **surfaces erratically** and needs a tracker, not a plan. That's `docs/roadmap/backlog.yaml`, rendered to `docs/BACKLOG.md` (priority-tier sections, untriaged last, in-progress / promoted / recently-closed tables). `SLICES.md` carries a one-line pointer with the open count.
282
+
283
+ ```yaml
284
+ meta:
285
+ schema_version: 1
286
+ items:
287
+ - id: fix-wt-quoting # stable slug; auto b1..bN when omitted at add
288
+ title: wt adapter mangles prompts containing quotes
289
+ kind: bug # bug | chore | followup | urgent | idea
290
+ status: open # open | in_progress | promoted | done | dropped
291
+ priority: { tier: P1, weight: 70, reason: breaks every Windows fanout }
292
+ source: { slice: fanout-adapters, date: 2026-07-06 } # where it surfaced
293
+ refs: [fanout-adapters] # related roadmap slices
294
+ touches: [scripts/fanout.mjs]
295
+ est_sessions: 0.5
296
+ gate: default # inherits the roadmap's meta.default_gate
297
+ prompt: | # embedded verbatim in the grab kickoff brief
298
+ Repro: roadmap fan -t wt with a prompt containing '"'.
299
+ Fix the wtSafe escaping; add a run.mjs case.
300
+ ```
301
+
302
+ **Capture** anywhere work surfaces: `/backlog` (in-session dump → normalized items), `roadmap backlog add` (shell), `backlog_add` (agents), or automatically at the end of a slice — every kickoff brief tells the worker to file leftovers before opening its PR, and `/sync` harvests any that landed as a PR-body "Leftovers" section instead.
303
+
304
+ **Consume** by size:
305
+
306
+ - **Small / self-contained** → `roadmap grab <id>`: its own worktree (`<root>/backlog-<id>`, branch `backlog/<id>`) and session, kickoff brief synthesized from the item (prompt embedded), item marked `in_progress`.
307
+ - **Bigger / belongs in the plan** → `roadmap promote <id> --pi <pi>`: becomes a `scheduled` sprint (the item id becomes the invoke key; title/est/gate/touches/prompt/priority carry over) with a `promoted_to` back-link on the item. Both YAMLs are validated before either is written.
308
+ - **Not sure what's next?** → `roadmap next` picks the single highest-priority ready thing across both trackers (roadmap wins ties) and prints its pickup brief.
309
+
310
+ ---
311
+
312
+ ## Linear (optional) — project-manage from Linear while agents execute
313
+
314
+ Add `meta.linear` and the roadmap projects itself into Linear: **the YAML stays canonical; Linear is a projection plus a proposal inbox.** Humans see and steer the plan on a board; agents keep executing from the graph; nothing is written twice.
315
+
316
+ ```yaml
317
+ meta:
318
+ linear:
319
+ team: ENG # push target (team key). Auth = LINEAR_API_KEY env var, never a file.
320
+ granularity: slices # pis (Projects only) | slices | slices+backlog — what leaks to Linear
321
+ horizon: all # all | near — near keeps scheduled/optionality slices off the board until promoted
322
+ verbosity: brief # title | brief | full — issue-description detail
323
+ cycles: off # off | on — on mirrors the team's active cycle from slice status (active+next = this week's batch)
324
+ history: off # off | window | full — whether DONE slices project as completed issues (progress % becomes real)
325
+ stale_days: 3 # optional — flag committed work (active/next) with no journal note in N days ('stale' label + view)
326
+ pull: propose # off | propose (walk the inbox in /sync) | auto
327
+ status_map: { blocked: "Blocked" } # optional exact-name overrides; defaults map by state TYPE
328
+ watch: # inbound sources — e.g. a public "Submit an issue" team
329
+ - { team: PUB, project: "Submit an issue", kind: bug, priority: { tier: P3 } }
330
+ ```
331
+
332
+ **Mapping.** PI ↔ Linear **Project** (grouped under an **Initiative** when `pi.initiative` is set) · slice / backlog item ↔ **Issue** · `priority.tier` P0–P3 ↔ Urgent/High/Medium/Low · `status` ↔ workflow state by TYPE (`active`→In Progress; `next`/held→Todo; `scheduled`/`optionality`→Backlog; `complete`→Done; `status_map` overrides by name) · `est_sessions` → the issue's native **estimate** (rounded to an integer, clamped to `estimate_max`) — a sortable board column, not prose. Issue ids are written back into the YAML (`linear: ABC-123`) — the mapping's source of truth survives any machine.
333
+
334
+ **Project enrichment.** A PI's project carries a rich `content` body (the full theme + exit criteria + deps — the uncapped project doc, so nothing truncates) and a concise `description` subtitle (the exit's first sentence). Optional `pi.priority` (a **strategic** tier, *not* derived from slice heat — an urgent slice shouldn't hijack a PI's ranking) → the project's Linear priority; optional `pi.target_date` (`YYYY-MM-DD`) → its target date. Every project also gets a **color + icon by initiative** (same initiative → same hue + glyph), so the board reads as grouped lanes instead of Linear's random per-project assignment. Declare meaningful styling in `meta.initiatives` (`{ <name>: { icon, color } }`, e.g. `Lumen: { icon: WritingAI }`, `Trust surface: { icon: Shield }`) so grouping is *signal* rather than a coincidence of first-seen order — a declared initiative also gets its **header** styled to match. Undeclared initiatives keep Linear's default header, and their projects use the deterministic fallback palette. Icon names are a fixed Linear set pushed best-effort — an unrecognized name degrades to "no icon" (color still groups) rather than failing the sync. `validate` warns when a `meta.initiatives` entry names an initiative no PI references (a typo, or a half-applied rename).
335
+
336
+ **Estimates & the split-don't-extend rule.** `est_sessions` rides the issue's native estimate field, so session cost sorts and rolls up on the board. Set your Linear team to the **Linear scale** (`1..5`) for a direct 1-point = 1-session read (Fibonacci/T-shirt would distort it), and leave `meta.linear.estimate_max` at its default `5`. `validate` warns when a slice's estimate exceeds the max — the deliberate signal to **split** an oversize slice, not extend the scale: a slice bigger than one agent session isn't a slice. (Raise `estimate_max` to `7` only if you genuinely extend the team's scale.)
337
+
338
+ **Milestones — stages within a project.** A slice can carry `milestone: "<stage>"` (e.g. `harness` / `hardening` / `ship`); the sync creates the distinct milestones on the PI's Linear project and attaches each issue, turning a project's flat issue list into legible stages on the roadmap/timeline view. Milestones are **project-scoped** (the same name under two PIs is two milestones) and entirely opt-in — no `milestone` fields anywhere → the milestone sync is a no-op. Idempotent (skips existing milestones by name, re-attaches an issue only when its stage drifts) and best-effort (a `projectMilestone` API rejection is a skip, not a failure).
339
+
340
+ **The plate — Linear's "My Issues" as your active-work hopper.** Assigning *everything* to yourself is no signal; instead `meta.plate` is a curated list of slice/backlog keys the sync assigns to **you** (Linear's built-in My Issues tab = `assignee: you`). So initiatives/projects/views answer "how's the whole effort" at their tiers, and My Issues answers "what's on my desk right now." The live plate is `meta.plate` **∪ whatever you're actively working** (active slices, `in_progress` items) — so starting work always surfaces it. Curate it with `roadmap plate add|rm|set|clear` (or a planning skill), and completed slices **auto-drain** on the next sync (blocked ones stay as a reminder). Each assigned issue carries a `plate` label, so a hand-assignment you make directly in Linear is never disturbed. `meta.linear.plate_max` (default 7) keeps the explicit list signal-rich; the feature is entirely off until `meta.plate` exists.
341
+
342
+ **The journal — a progress trail on each issue, so in-flight work survives a dead session.** The plate makes work *visible* on My Issues; the journal makes it *resumable*. As an agent works a slice it posts notes to the mapped issue's comment stream — `roadmap linear note <key> "…" [--kind progress|blocker|done]` (or the `issue_note` MCP tool) — at checkpoints (a gate cleared, a blocker hit, session end). On pickup, an agent reads the stream first (`roadmap linear notes <key>` / `issue_notes`), so a session that died mid-flight is picked up from where it left off, not from zero — the kickoff brief and dispatch guidance both instruct this loop. A **session-end `Stop` hook** also auto-posts a **git-derived snapshot** (branch · recent commits · uncommitted paths) whenever the current branch maps cleanly to a mapped slice with real work — best-effort and heavily guarded (not a roadmap repo / no key / not a slice branch / nothing to report → silent no-op), so it never blocks or slows a session. PI-level rollups go to the project update (`roadmap linear post-update` / `project_update`). All of it is written tracker-neutral, so a future `jira.mjs` mirrors it.
343
+
344
+ **Push** (`roadmap linear sync`, or automatically inside `/sync` when authed): diff-based and idempotent — an unchanged roadmap sends zero ops. Descriptions follow the `verbosity` lever, never copy read-order/prompt, and always end with a machine footer (`roadmap: slice=<invoke> · pick up: /slice <invoke>` + a SLICES.md link) — so an agent dispatched *from Linear* (via Linear's own agent delegation or hosted MCP) self-orients in one command. Set `branch_convention: "{pi}/{linear}-{sprint}"` and Linear auto-links every fanout PR to its issue.
345
+
346
+ **Pull.** New issues in `watch` sources become **proposed backlog items** carrying `source.linear: {team, project, issue}` — so `/prioritize` can weight work by where it came from (a public intake team ≠ a maintainer capture), with the watch's default `priority` as the implicit weighting. Edits to mapped issues (state/priority changes made in Linear) become proposed deltas. With `pull: propose` (recommended), `/sync` walks the inbox with you — keep / edit / skip per item; nothing enters the graph unconfirmed. The sync cursor is per-machine (`.roadmap-linear-state.json`, git-ignored) and only advances once the inbox is handled, so unhandled proposals reappear rather than vanish.
347
+
348
+ **Detection is graceful.** No `meta.linear` → every Linear behavior is off and the tool is byte-identical to before. Configured but no `LINEAR_API_KEY` → one advisory line, everything else works. The session-start hook reports state with zero network; `roadmap linear status --probe` is the only networked check. Bootstrap: `roadmap linear auth` (key instructions) → `roadmap linear setup --team <KEY>` → `roadmap linear sync --dry`.
349
+
350
+ **Per-PI override.** A PI can set its own `linear.granularity` (e.g. keep an internal PI's slices off a shared board) or `linear.verbosity` (quiet a noisy PI's issue descriptions to `title`, or richen an active one to `full`). Creating one that conflicts with the global requires an explicit `yes_linear_override: true` ack — otherwise the mutation is rejected with instructions and nothing is written; `roadmap validate` warns on stored mismatches.
351
+
352
+ ### Topology: Linear as the board
353
+
354
+ The recommended workspace shape at agent scale: **one team per actively-managed repo** (dispatch routing is deterministic, workflow states and `status_map` compose 1:1, and the issue identifier tells you the repo), **PIs = Projects, slices/items = Issues, native priority = tier**, plus **one shared intake team** (a public "Submit an issue" board) wired as a `watch` source. Repos not under agent management get no team.
355
+
356
+ `roadmap linear provision` shapes the workspace idempotently: creates the labels the graph knows (`roadmap` marker on every synced issue, `kind:*` for backlog items, `track:*` for the lanes present, `status:*` for held work), the standard views (**Ready wave · In flight · Held on human · Backlog triage · Recently shipped** plus a **Track X** view per lane; view API rejection degrades to a manual checklist), and prints two guidance texts — the workspace agent guidance and the **repo dispatch contract** for `CLAUDE.md`/`AGENTS.md`. Projects carry PI theme + exit criteria as descriptions.
357
+
358
+ **A clean board, not a wall.** The projection is honest and navigable, not a 1:1 dump:
359
+ - **Empty projects are skipped.** A PI whose slices are all shipped doesn't create a bare 0-issue project (already-mapped projects stay in sync).
360
+ - **Project names are the PI headline.** A title authored `Headline — subhead` projects as just **Headline**; the subhead moves into the description. No context lost, no tacky names.
361
+ - **Only `active` shows In Progress.** Held work (`blocked`/`paused`/`gated`) maps to Todo with a `status:<held>` label, so the board's In-Progress count means real live work and the "Held on human" view filters the rest. (The pull inbox also suppresses the round-trip echo, so held slices don't generate false status proposals every sync.)
362
+ - **Initiatives group the projects.** A PI declares `initiative: <name>` and sync creates the Linear Initiative (the tier above projects) and attaches the PI's project — turning a flat wall of projects into a handful of strategic groups you can steer. *(The initiative API is behind graceful degradation, pending live verification.)*
363
+
364
+ ### Cloud dispatch
365
+
366
+ `roadmap dispatch <key>` sends one slice/backlog item to a **Claude Code cloud session** — the default `claude-cloud` transport fires the Routines API directly (**no Linear plan required, no worktrees, no disk ceiling**; bounded only by the firing account's Claude plan). Multi-account workstations hot-swap automatically: routine credentials live in `~/.claude-routines.json` keyed by account email, and dispatch fires as **whoever is currently `claude /login`'d** (see [DEPLOYMENT.md § Cloud dispatch](docs/DEPLOYMENT.md)). When the slice is also Linear-mapped, the session URL is commented onto the issue — the board links to the live session. ⚠ Routines fire is a beta API.
367
+
368
+ `roadmap fan --cloud` does it for a whole wave; the cap defaults to the review ceiling (machine ceilings vanish, but a human still merges). The alternative `--to claude|codex|oz` transport posts an @-mention capsule comment on the Linear issue instead — useful when the workspace has that agent's integration installed (Linear's native coding sessions are paid-plan-gated).
369
+
370
+ ---
371
+
372
+ ## Estimation & timeline (optional) — pairs with [agent-time](https://github.com/ConnorBritain/agent-time)
373
+
374
+ `target_date` is the one roadmap date that's usually a guess. [**agent-time**](https://github.com/ConnorBritain/agent-time) — a local-first estimation skill — prices a task in calibrated *agent-rounds → wall-clock minutes* (never human hours) and self-corrects from logged outcomes. Wire it in and the roadmap turns those durations into a **projected timeline**:
375
+
376
+ - **`roadmap estimate <slice|--all>`** tags each classified slice (`shape` + optional `risks`) with a cached `estimate` (low/expected/high minutes + confidence). Idempotent; `--force` refreshes. An unclassified slice is skipped, not guessed.
377
+ - **`roadmap estimate timeline`** rolls those durations up along the **same wave / dependency / concurrency schedule the fanout actually runs** — a wave counts as its slowest slice, waves accumulate — into a `projected_target_date` per PI. That fills Linear's `targetDate` wherever you haven't set an explicit commitment (**an explicit `target_date` always wins**). Honesty is enforced at the date, not just the report: an **unpriced** slice *suppresses* its PI's date (a PI is dated only when every remaining slice is estimated), and **blocked/gated** slices are excluded as a labelled optimistic frontier — both are surfaced, never folded into the number as a silent zero.
378
+ - **`roadmap estimate log <slice> --status pass|fail|partial|abandoned`** closes the **calibration loop** — it records the slice's outcome to agent-time so the next estimate self-corrects. Idempotent per estimate (safe to re-run). The journal Stop-hook fires it automatically when a mapped slice finishes. Actual rounds/minutes auto-fill **only if agent-time's round-counter (`PostToolUse`) hook ran in that session** — otherwise pass `--actual-rounds N` (agent-time rejects an outcome with no actuals). Enable that hook per-repo from agent-time's `hooks/README.md` to make auto-calibration real.
379
+ - `estimate`, `timeline`, and `estimate_log` are also **MCP tools**, so a session picking up or finishing a slice can drive them in-band.
380
+
381
+ Config lives in `meta.estimation` (`engine` path, `hours_per_day` throughput, `expected|high` point). **agent-time itself is untouched** — the roadmap is just another caller of its `estimate --json` CLI. Install the [`agent-time-estimator`](https://github.com/ConnorBritain/agent-time) skill (or set `meta.estimation.engine`) and the default resolution finds it. The two are built to work hand-in-hand: the same calibrated numbers that size one task plan the whole program.
382
+
383
+ ---
384
+
385
+ ## Riding the wave: discipline + the review ritual
386
+
387
+ Two second-order effects of agent-scale work, both encoded:
388
+
389
+ **Sprawl curbing (advisory, never blocking).** Helpful agents love filing follow-up scope; unchecked, every sprint spawns two backlog items and a sibling sprint. The kickoff brief now hard-forbids worker sessions from adding sprints/PIs (leftovers go to the **backlog only**; "YAGNI applies to captures too"), the `add_sprint`/`add_pi` tool descriptions carry the same scope-discipline nudge, and `/sync` + the review digest surface **sprawl warnings**: a capture ratio ((captured items + added sprints) per completed slice, threshold `meta.discipline.capture_ratio`, default 2) plus an unconditional flag on any PI that appeared since the last review.
390
+
391
+ **Coherence wave packing.** Under a cap, the scheduler now prefers **finishing started PIs over opening fresh ones** (then closest-to-done first) — strictly *below* declared priority, so a P0 in a fresh PI still wins. Same-PI siblings fill the cap contiguously, `roadmap plan` prints `(closes auth)` on waves that finish a PI, and the digest reports **PIs in flight** (the fragmentation count). Opt out with `meta.discipline.coherence: false`.
392
+
393
+ **The review ritual — three modalities.** This is how the human stays in control of the deluge:
394
+
395
+ - **`/debrief`** — atomic lookback, **no graph mutations**: `roadmap review` diffs the graph against the date-anchored snapshot (`meta.last_review.commit`, via `git show`) and the skill presents it under hard style rules (≤15 lines; recommendations in "X instead of Y" form, tied to the north star; agent-originated scope named; no cheerleading), then logs a ≤10-line hand-authored entry to `docs/roadmap/REVIEWS.md` and re-anchors.
396
+ - **`/imagine` + `/prioritize`** — the forward atomics (strategy interview; tier triage with forced reasons).
397
+ - **`/retro`** — the composition: the debrief lookback, then per-bet **double-down / kill / defer** (every kill names what the freed sessions buy; every sprawl-flagged sidequest gets an explicit keep-or-drop), decisions applied through the mutation tools, optional `/imagine` handoff, and the close covers the decisions. When Linear is wired, the digest posts as project updates (`roadmap linear post-update`).
398
+
399
+ `roadmap review [--since <rev|date>] [--json]` is the engine: shipped vs captured vs aging vs new PIs vs sprawl, computed from git history — works with zero Linear.
400
+
401
+ ---
402
+
403
+ ## Feasibility pre-checks (the disk ceiling)
404
+
405
+ Fanning out N worktrees costs real disk. `roadmap plan` / `fan` / `grab` estimate the per-worktree cost (the tracked tree's size × 1.3, or `meta.worktree_gb` when your gates install `node_modules`/build artifacts per worktree — that's the calibration knob) and compare it against free space on the volume holding `meta.worktree_root`. Disk joins CPU / RAM / work / review as a **fifth ceiling**: the recommended cap auto-dials down and the plan reports `bound by: disk (need ~X GB/worktree, Y GB free)`. When even **one** worktree won't fit, `fan` and `grab` refuse to launch before creating anything. If the environment can't be probed (no git HEAD, unsupported statfs), the ceiling silently drops out — never blocking a plan on a failed probe.
406
+
407
+ ---
408
+
409
+ ## Install
410
+
411
+ > **Full deployment guide** — every surface (CLI, Claude Code plugin, standalone MCP, Claude Desktop, Codex, CI), exactly where config vs. secrets live, Linear setup per environment, and the planned Jira shape: **[docs/DEPLOYMENT.md](docs/DEPLOYMENT.md)**. The short versions follow.
412
+
413
+ ### The `roadmap` CLI
414
+
415
+ ```bash
416
+ git clone https://github.com/ConnorBritain/roadmap.git
417
+ cd roadmap && npm install && npm link
418
+ ```
419
+
420
+ `npm link` puts `roadmap` on your PATH in every shell. On Windows it writes `roadmap.cmd`/`roadmap.ps1` shims (PowerShell and cmd) plus a unix bin (WSL/bash; run `npm link` once in each Node environment you use). `npm unlink -g roadmap` removes it.
421
+
422
+ ### In Codex
423
+
424
+ No plugin install is required. Open the repo in Codex, use the commands above, and rely on [`AGENTS.md`](AGENTS.md) for repo-local guidance.
425
+
426
+ For MCP usage in agent environments, run:
427
+
428
+ ```bash
429
+ npm run mcp
430
+ ```
431
+
432
+ The checked-in [`.mcp.json`](.mcp.json) remains the Claude-plugin entrypoint (server name `graph`).
433
+
434
+ **Alias fallback (no npm):** drop a shim in your shell profile instead.
435
+
436
+ ```powershell
437
+ # PowerShell, $PROFILE
438
+ function roadmap { node "$HOME\Code\roadmap\scripts\cli.mjs" @args }
439
+ ```
440
+ ```bash
441
+ # bash/zsh, ~/.bashrc / ~/.zshrc
442
+ roadmap() { node "$HOME/Code/roadmap/scripts/cli.mjs" "$@"; }
443
+ ```
444
+
445
+ ### As a Claude plugin
446
+
447
+ The repo is its own marketplace (`.claude-plugin/marketplace.json`). Add it, then install:
448
+
449
+ ```bash
450
+ # from a GitHub clone:
451
+ claude plugin marketplace add ConnorBritain/roadmap
452
+ # or from a local checkout:
453
+ claude plugin marketplace add /path/to/roadmap
454
+
455
+ claude plugin install roadmap@roadmap # user scope; --scope project to pin per-repo
456
+ ```
457
+
458
+ That wires the skills, agents, the SessionStart hook, the PR-watch monitor, and the MCP server in one step (new sessions pick them up; `/mcp` reconnects the current one). The plugin bundles its MCP via `.mcp.json` as `graph`, so don't also `claude mcp add` a second copy of the server.
459
+
460
+ ### Upgrading from `slice-roadmap` (≤ 0.1.x)
461
+
462
+ The plugin, marketplace entry, and npm package were renamed **`slice-roadmap` → `roadmap`** (and the bundled MCP server `roadmap` → `graph`) in 0.2.0. Old installs won't auto-update — migrate once:
463
+
464
+ - **npm:** `npm unlink -g slice-roadmap`, then `npm link` again from the repo (per Node environment). The `roadmap` bin name itself is unchanged.
465
+ - **Plugin:** `claude plugin uninstall slice-roadmap`, re-add the marketplace, `claude plugin install roadmap@roadmap`.
466
+ - **⚠ Permission allow-lists:** any `settings.json` entries naming `mcp__plugin_slice-roadmap_roadmap__*` tools **silently stop matching** — rewrite them as `mcp__plugin_roadmap_graph__*`.
467
+ - **Skills:** `/slice` is unchanged; `/slice-sync` → `/sync`, `/slice-init` → `/init`, `/slice-fanout` → `/fanout` (plus new `/backlog`).
468
+ - **Env:** the api-lane variable is now `ROADMAP_API_KEY` (was `SLICE_ROADMAP_API_KEY`).
469
+ - **Generated files:** the first `roadmap render` after upgrading rewrites SLICES.md boilerplate with the new skill names — a one-time diff.
470
+
471
+ ### Recommending it in a consuming repo
472
+
473
+ Don't commit a device-specific alias into a repo. Point contributors at this tool from your onboarding docs (e.g. a CONTRIBUTING note): *"Drive the roadmap from your shell. Clone `roadmap`, `npm install && npm link`, then run `roadmap` from anywhere in this repo."* A consuming repo only ever carries its own `docs/roadmap/roadmap.yaml` and `backlog.yaml` (plus the generated `SLICES.md` / `BACKLOG.md`).
474
+
475
+ ---
476
+
477
+ ## What's built
478
+
479
+ - **Graph brain** (`graph.mjs`): dependency resolution (sibling / fully-qualified / whole-PI deps), cycle detection, wave scheduling with two-wave file-contention + priority-first cap packing, sessions-remaining and exec-plan derivation.
480
+ - **Priority** (`lib/priority.mjs`): the shared tier/weight/reason model — validation, the derived comparator, tier badges.
481
+ - **Backlog** (`lib/backlog-core.mjs` + `backlog.mjs`, `grab.mjs`, `promote.mjs`, `next.mjs`): the erratic-work tracker — capture/triage/launch/promote, `BACKLOG.md` rendering, the item→node adapter that reuses the fanout brief machinery, and cross-tracker pick-next.
482
+ - **Renderer** (`render.mjs`): hierarchical `SLICES.md` (per-PI sections, nested sprint tables, priority badges, derived exec-plan lines, cross-PI wave map, held-on-human, backlog pointer) + `BACKLOG.md`.
483
+ - **Scheduler** (`scheduler.mjs`): recommended-cap eval (CPU / RAM / independent-work / review / **disk** ceilings, reporting which binds) plus the waves.
484
+ - **Fanout** (`fanout.mjs`): `tmux`, `wt`, `warp`, `print`, `background` adapters; per-slice worktree plus synthesized kickoff brief (stashed `prompt` embedded, leftover-capture instruction); disk hard-block; the interactive console (`wizard.mjs`); guarded launch (`--dry`/`--out` preview, autonomous double-ack); `cleanup.mjs` worktree pruning.
485
+ - **Shared mutation store** (`lib/store.mjs`): the one read → mutate → validate → write → re-render path under every mutating surface (MCP, `set`, `backlog`, `promote`), including the validate-both-before-writing-either two-file promote.
486
+ - **Plugin surface**: five skills (`slice`, `sync`, `init`, `fanout`, `backlog`), four agents, and a `SessionStart` hook (ready wave + reconcile nudge + backlog count).
487
+ - **MCP server** (`mcp.mjs`, server `graph`): a bundled, hand-rolled JSON-RPC stdio server with read tools (plan / ready_wave / show / validate / backlog_list) and comment-preserving, schema-validated mutate tools (add_pi / add_sprint / set_status / set_fields / bulk_set / prune / backlog_add / backlog_set / backlog_promote) that re-render the generated views on every edit.
488
+ - **PR-watch monitor** (`watch-prs.mjs` + `lib/pr-watch-core.mjs` + `monitors/monitors.json`): polls `gh` for the fanout branches and notifies the lead on each PR phase transition.
489
+ - **Tests**: `npm test` runs the zero-dependency suite over the pure brain (graph, recommender + disk ceiling, priority, backlog, brief, plan, render, validate, CLI core, wizard core, MCP core, PR-watch core).
490
+
491
+ The resource classifier matches build/test runner commands, not languages. It ships patterns for the common runners (`npm`/`yarn`/`pnpm`, `jest`, `vitest`, `tsc`, `pytest`, `tox`, Maven, Gradle, `make`, CMake/CTest, `go`, `cargo`, and more), ordered by how common they are, and `meta.weight_patterns` teaches it any bespoke runner.
492
+
493
+ ## Requirements & license
494
+
495
+ Node 18.15+ (for `fs.statfsSync`, the disk pre-check) and a one-time `npm install` (for the `yaml` parser). MIT licensed.