roadmap is a CLI and a Claude Code plugin. It turns one YAML file into your repo's plan of record (a hierarchical, dependency-aware graph), then fans that plan out into parallel Claude Code sessions, each scoped to a single unit of work in its own git worktree.
- One source of truth.
docs/roadmap/roadmap.yamlholds the PIs, sprints, deps, file-ownership, session estimates, gates, and kickoff briefs. - Generated view.
docs/SLICES.mdis rendered from the YAML; never hand-edit it. - Derived, never stored. Per-PI exec-plan lines (
(S0 ∥ S1)→S2→S3), the cross-PI "ready now" wave map, and "sessions remaining" rollups are all computed fromdeps+touches+status. - Deterministic fanout. A scheduler decides which slices can run concurrently under a cap (which it recommends from a CPU/RAM and review eval), then launches each in its own worktree and Claude Code session.
- 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_patternsteaches it anything bespoke. Nothing is hardcoded to one stack.
roadmap has a small, deliberate vocabulary:
| Term | What it is |
|---|---|
| Roadmap | The whole graph: every PI and sprint in roadmap.yaml. The map of all the work. |
| PI (Program Increment) | A top-level initiative or epic. Groups related sprints; carries a status, dependencies, and exit criteria. |
| 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. |
| 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. |
| Wave | The set of slices that can run concurrently right now: mutually dependency-free, sharing no files, under the cap. |
| 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. |
Roadmap = the whole plan. Slice = one launchable piece of it. You edit the roadmap (the YAML); you launch slices (by
invokekey).SLICES.mdis the human-readable render of the roadmap, generated and never hand-edited.
# 1) one-time: install deps + put the `roadmap` CLI on your PATH
git clone https://github.com/ConnorBritain/roadmap.git
cd roadmap && npm install && npm link
# 2) in any repo, author docs/roadmap/roadmap.yaml (see "The roadmap.yaml model")
# 3) from ANYWHERE inside that repo (root or a subdir; the roadmap is auto-discovered):
roadmap # interactive console: pick terminal / wave / cap, then launch
roadmap plan # the text plan: recommended cap + what's runnable (no prompts)
roadmap render # regenerate docs/SLICES.md
roadmap validate # structural + cycle checks
roadmap fan -w 1 # spin up wave 1 (lead + slice sessions); add -d to preview firstThat's the whole loop: cd into a repo, type roadmap ..., it finds the roadmap and fires.
The same engine (roadmap.yaml plus the graph brain) driven three ways.
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:
- Interactive console. Bare
roadmapin 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, bareroadmapprints the text plan instead, so scripts and CI are unaffected;roadmap goforces the console.) - 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.
| Command | What it does |
|---|---|
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. |
roadmap plan [-c N] [--review-ceiling N] [--use-free-ram] [-j] |
Recommended cap (and what constrains it), the execution waves, and per-node launch commands. Spawns nothing. -j/--json emits the plan for tooling. |
roadmap render [-c N] [-s] |
Regenerate docs/SLICES.md from the YAML (-s/--stdout prints instead of writing). |
roadmap validate |
Structural, dependency, and cycle checks. Non-zero exit on error. |
roadmap fan [-t wt|warp|tmux|print|background] [-c N] [-w N] [--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. 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). |
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. |
roadmap mcp |
Run the MCP server (stdio JSON-RPC) directly, for debugging or non-plugin registration. The plugin starts it for you. |
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. |
roadmap sync / roadmap init |
Reserved on the CLI. Reconcile and bootstrap live as the /slice-sync and /slice-init plugin skills (surface 2). |
Short flags (-w -c -t -d -o -j -r -f -lc -wm) expand to their long forms; positional slice keys pass through untouched.
# See the plan + why the cap is what it is (the binding constraint is reported):
roadmap plan
# Concurrency cap: 5 (recommended)
# bound by: review (PR review/merge bottleneck, soft ceiling)
# machine: 24 cores, 59.6GB total / 20.6GB free
# ceilings: 12 [CPU] · 13 [RAM] · 23 [work] · 5 [review]
# Wave 1, 5 concurrent: auth-sessions, billing-invoices, search-index, ...
roadmap fan -w 1 # launch: lead + one watched session per slice (default)
roadmap fan -w 1 -d # preview the launch script, spawn nothing
roadmap fan -w 1 -o wave1.sh # write the script to a file to inspect/run yourself
roadmap fan -c 3 # override the recommended cap
roadmap fan --autonomous --yes-spawn-autonomous # headless workers that commit/push/PR (double-acked)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.
Install it as a plugin (see Install) and the roadmap becomes an in-session surface: slash-command skills, agents, and a startup hook.
- Skills (
skills/*/SKILL.md)/slice <key>: orient on one slice (read-only) by its what, read-order, next action, gate, and branch./slice-sync: reconcile statuses against merged PRs and the tracker, then re-renderSLICES.md./slice-init: a PM-style interview that bootstraps aroadmap.yaml(warm-start from existing docs, or cold)./slice-fanout: compute the waves and launch (wraps the same scheduler and adapters as the CLI).
- Hook (
hooks/hooks.json): aSessionStarthook injects the at-a-glance plus the current ready-wave, so a fresh session immediately knows what's runnable (and, on first run, installs theyamldep). - Agents (
agents/*.md): four specialized subagents Claude invokes across the roadmap, fanout, and review lifecycle.
| Agent | Role | Read/write | Suggested model |
|---|---|---|---|
| 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 /slice-init to pre-fill before the interactive confirmation. |
reads repo, proposes YAML | sonnet |
| 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 |
| 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 |
| 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 |
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.
The plugin ships its own MCP server (.mcp.json, auto-started on install), so an agent drives the roadmap with typed tools instead of shelling out and parsing text:
- Read:
plan,ready_wave,show,validatereturn structured JSON. - Mutate:
add_pi,add_sprint,set_status,set_fields,pruneeditroadmap.yamlthrough the YAML Document API (comments preserved), refuse any edit that would corrupt the graph (duplicate invoke key, unresolved dependency, cycle), and re-renderSLICES.mdin the same step. Seed and scaffold a roadmap, flip a slice to complete with its PR, or prune finished work, all schema-safe and atomic.
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.
meta:
schema_version: 1
program: Q3-PLATFORM
default_gate: | # inherited by sprints whose gate is 'default'/{{default}}
npm test
base_branch: main # worktree base + PR base (default main)
remote: origin # git remote (default origin)
terminal: tmux # default fanout adapter: tmux|warp|wt|background|print
worker_mode: plan # launched sessions' --permission-mode: plan|auto|acceptEdits|bypassPermissions
default_concurrency: 3
# Optional: teach the resource classifier a bespoke runner / override per-class cost
weight_patterns: { heavy: ["my-e2e-suite"], medium: ["my-bundler"] }
weight_cost: { heavy: { ram: 5, cores: 3 } }
# Optional: the renderer cross-links these in SLICES.md (omit any you don't have)
links: { narrative: ROADMAP.md, status: ../STATUS.md, tracker: roadmap/TRACKER.md }
pis:
- id: auth # stable; == branch slug
title: Authentication
status: active # active|next|scheduled|complete|blocked|paused|gated|optionality
sprints:
- id: s1
title: Login flow
status: complete
invoke: auth-login # the slice key, stable, unique across the file
prs: ["#42"]
- id: s2
title: Session tokens
status: active
invoke: auth-sessions
deps: [s1] # sibling sprint id | pi-id/sprint-id | a whole PI id
est_sessions: 3 # focused sessions remaining (drives rollups + scheduling)
touches: [src/session.ts] # files written; used for two-wave contention detection
gate: |
{{default}}
PLUS the session integration tests
read_order: ["docs/auth.md (the design)"]
resume_action: Wire JWT issuance + refresh; thread through middleware.invokeis the slice key you launch with. Stable and unique across the file, so renaming a title never breaks a reference.depsare the DAG edges; the exec-plan line and wave map are derived from them.touches/ownsmechanize the two-wave pattern: two ready slices that write the same file never share a wave; a convergence sprint justdeps-on the divergent ones.gated_on: <name>marks a human-gated slice. It never auto-schedules; it surfaces under "held on a human."worker_modesets the--permission-modelaunched sessions start in;weight(heavy|medium|light) optionally overrides a sprint's inferred resource class.
git clone https://github.com/ConnorBritain/roadmap.git
cd roadmap && npm install && npm linknpm 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 slice-roadmap removes it.
Alias fallback (no npm): drop a shim in your shell profile instead.
# PowerShell, $PROFILE
function roadmap { node "$HOME\Code\roadmap\scripts\cli.mjs" @args }# bash/zsh, ~/.bashrc / ~/.zshrc
roadmap() { node "$HOME/Code/roadmap/scripts/cli.mjs" "$@"; }The repo is its own marketplace (.claude-plugin/marketplace.json). Add it, then install:
# from a GitHub clone:
claude plugin marketplace add ConnorBritain/roadmap
# or from a local checkout:
claude plugin marketplace add /path/to/roadmap
claude plugin install slice-roadmap@roadmap # user scope; --scope project to pin per-repoThat 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, so don't also claude mcp add roadmap (you would get two servers named roadmap).
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 (plus the generated SLICES.md).
- Graph brain (
graph.mjs): dependency resolution (sibling / fully-qualified / whole-PI deps), cycle detection, wave scheduling with two-wave file-contention, sessions-remaining and exec-plan derivation. - Renderer (
render.mjs): hierarchicalSLICES.md(per-PI sections, nested sprint tables, derived exec-plan lines, cross-PI wave map, held-on-human). - Scheduler (
scheduler.mjs): recommended-cap eval (CPU / RAM / independent-work / review ceiling, reporting which binds) plus the waves. - Fanout (
fanout.mjs):tmux,wt,warp,print,backgroundadapters; per-slice worktree plus synthesized kickoff brief; the interactive console (wizard.mjs); guarded launch (--dry/--outpreview, autonomous double-ack);cleanup.mjsworktree pruning. - Plugin surface: four skills (
slice,slice-sync,slice-init,slice-fanout), four agents, and aSessionStarthook. - MCP server (
mcp.mjs+lib/mcp-core.mjs): a bundled, hand-rolled JSON-RPC stdio server with read tools (plan / ready_wave / show / validate) and comment-preserving, schema-validated mutate tools (add_pi / add_sprint / set_status / set_fields / prune) that re-renderSLICES.mdon every edit. - PR-watch monitor (
watch-prs.mjs+lib/pr-watch-core.mjs+monitors/monitors.json): pollsghfor the fanout branches and notifies the lead on each PR phase transition. - Tests:
npm testruns the zero-dependency suite over the pure brain (graph, recommender, brief, plan, render, validate, CLI core, wizard core, MCP core, PR-watch core).
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.
Node 18+ and a one-time npm install (for the yaml parser). MIT licensed.