roadmap-planner
Derive an execution roadmap from a project's vision/spec docs by first principles, then diff that fresh derivation against the existing roadmap to prove the task ORDER is correct. Use this whenever th
SKILL.md.claude/skills/roadmap-planner/SKILL.md
GitHubroadmap-planner
Prove an execution roadmap's task order is correct by re-deriving it from the source of truth (the vision + spec), then diffing the derivation against the existing plan.
The core insight: a roadmap is a schedule over a dependency graph. Most planning errors are not "wrong task" — they are producer-after-consumer: a task that produces something (a contract, a schema, an SDK, a service) is scheduled after a task that consumes it. Reading the roadmap top-to- bottom never catches this; only building the actual dependency graph does. So we derive the tasks from use-cases, wire the graph explicitly, and let a deterministic pass find every ordering violation.
You produce two artifacts, never a silent overwrite:
- a freshly-derived, dependency-ordered roadmap (a proposal), and
- a delta report vs the existing roadmap — ordering violations, missing/extra tasks, circular dependencies found + how they were broken, and compaction candidates.
The human reviews the delta and decides what to adopt. The existing roadmap is often hand-crafted with context the spec doesn't capture; the derivation's job is to challenge it, not replace it.
Inputs (parameterize per project)
- Corpus — the vision/spec/requirements docs to derive from. Point it at wherever the project keeps
its source of truth (a
docs/spec/**tree, a product-requirements doc, a genesis/seed file, ADRs). Actors + use-cases usually live in the requirements/product docs; modules/engines/services in the architecture/design docs. If the project has no written spec, derive from the README + issue tracker and flag the thin provenance as a finding. - Existing roadmap — the plan to validate. Default:
project.json → roadmap.path(this baseline's default isdocs/roadmap-execution-plan.md). - Buckets — the delivery lanes, project-defined. Set them in the
tasks.jsontop-levelbucketsarray; they only rank ties in ordering. A single-lane project can use one bucket (e.g.app); a platform/product split might useplatform,product,web,app. There is no fixed lane set.
If the user names a different corpus or roadmap, use those. If no roadmap exists yet, skip the delta and emit only the derived roadmap.
The method (10 steps)
Steps 1–4 are read-heavy discovery — run them as a multi-agent workflow when the corpus is large (see "Execution engine"). Steps 5–10 are synthesis + mechanical graph work in main context.
A running rule for every step: derive AND reconcile. Do not derive in a vacuum. The spec usually already declares modules (e.g. a module-boundaries chapter) and actors (e.g. a user-roles chapter). Derive fresh from use-cases, then reconcile against what the spec declares. Every disagreement (a module you derived that the spec omits, or vice-versa) is a finding, not something to silently paper over.
Actors → use-cases. Read the corpus and list every actor and the use-cases each performs. The union of use-cases is the complete solution. Capture each use-case with a stable id, its actor, and a one-line intent. Cite the source doc/section. This is the ground truth everything else traces to.
Black-box → modules. Treat the system as one black box that satisfies all use-cases, then break it into
nfunctional modules by cohesion (a module owns a coherent slice of the use-cases). Name modules by capability, not technology.Interfaces + NFRs. For each module, state its high-level interface (the intent it exposes to other modules — not signatures) and extract the non-functional requirements that bear on it (security/tenancy, performance, availability, compliance, versioning, maintainability/diagnosability). NFRs become task constraints (a hard
deps/seamDepsedge when they gate) and feed the non-functional scoring lens (Step 8b) — they are not free-floating prose.Platform vs solution. Cluster modules into platform (reusable, product) vs solution (customer-specific assembly). This is the level-1 system design. A module that encodes customer logic is solution; a reusable capability is platform. Record the rationale per module. 4a. Inherited-default seams (cross-cutting). Extract the project's inherited-defaults family — the cross-cutting concerns every feature is expected to pick up automatically (commonly security, audit, tenancy, and observability; a project's spec may name its own). These concerns create no hard
depsedge — feature code compiles and runs without them — so a plain producer→consumer graph scatters them to the tail. For each concern: (a) apply the contract/backend split — a seam/contract task (the interface every consumer is written against; scheduled early) and a backend task (the concrete sink/implementation; deferrable); (b) draw a softseamDepsedge from each first-consumer task to the seam/contract task (Step 8). The helper floats the seam early and relaxes it (advisory) only if a hard edge legitimately forbids earliness. Reconcile: if the project treats a concern as an automatic default, a feature epic with no seam edge to that applicable default is itself a finding — a seam-after-consumer waiting to happen — not something to pass over.Epics. Cluster use-cases by high-level intent →
nepics. An epic is a coherent capability a demo/release can show. Each use-case lands in exactly one epic.Typed tasks. Within each epic, split its use-cases into three task categories: Infrastructure (scaffolding, storage, wiring, contracts), Business Logic (domain rules, engines), Interface (APIs, UI, SDKs). One use-case may yield tasks in more than one category.
Bucket + intra-epic order. Map each typed task onto one of the 4 buckets (platform / solution / web / app) and arrange within the epic. Natural intra-epic flow is usually Infrastructure → Business Logic → Interface, and platform → solution → web/app — but that is a heuristic, not the truth. The truth is the dependency graph (Step 8), which overrides any bucket heuristic.
Dependency graph + cycle-breaking (DETERMINISTIC). Give every task a stable id and declare its dependency edges (
A depends on Bmeans B must ship before A). Then run the helper:node .claude/skills/roadmap-planner/scripts/graph.mjs analyze <tasks.json>. It topologically sorts, detects cycles, and flags any task ordered before a task it depends on. On a cycle, split both tasks into independent sub-tasks that break it (e.g. extract the shared contract A and B both need into a third task both depend on), update the edges, and re-run. This is recursive — keep splitting until the graph is acyclic. The judgment (what depends on what, how to split) is yours; the cycle detection + topo-sort is the script's. Also declareseamDeps(soft/seam edges) alongsidedepsfor the Step-4a inherited-default concerns: the helper floats seams early, relaxes any a hard edge forbids (advisory, never a gridlock), and — whenorderis present — flags aseam-after-consumer(an admitted seam scheduled at/after its consumer) as a blocker (exit 3). Seereferences/graph-schema.md. 8b. Priority scoring — two lenses (WSJF). The edges answer "is this order legal?"; the score answers "among legal orders, which is good?" Impact is stakeholder-relative — a single impact number hard-codes one stakeholder (usually business) and starves engineering-discipline work (the meta-cause of seam-after-consumer). So score each task through two lenses:functionalValue(business value — product-owned) andnonFunctionalValue(maintainability / diagnosability / security-posture — owned by the architecture owner, not the feature stakeholder; that ownership is the structural seat that stops engineering from being business-scored). The helper ranks the topologically-ready set byweightedAverage(functionalValue, nonFunctionalValue; weights) / effort(top-levelweights, default 50/50) — it never crosses a hard edge, so it only sequences work that is already eligible. This buys deferral for free: a low-value/high-effort task (e.g. a deferred backend from Step 4a) floats as late as its dependents allow — no milestone node needed. Genuine hard phase-gates staydeps. For a judgment call the score gets wrong, setscoreOverride+ a requiredoverrideReason(a human-directed call; auditable). Scoring is advisory — it never blocks. Seereferences/graph-schema.md.Ordered roadmap. The topological order (with buckets + epics preserved) is the derived execution roadmap. Emit it. Sanity-check the emitted order: the helper proves the order is legal, not sensible — if a backend/Infrastructure/hardening task lands before the Business-Logic it supports, that is an under-scored or under-anchored deferral (raise its consumers' scores, add the real gate as a
dep, or set ascoreOverride), not a valid plan.Compaction. Re-run
node .claude/skills/roadmap-planner/scripts/graph.mjs compact <tasks.json>to list merge candidates — tasks in the same epic+bucket with no dependency between them (parallelizable → one slice), or a chainA → Bwhere B depends only on A in the same bucket (collapsible). Reducing task count raises velocity: every extra task boundary is intake/spec/review ceremony. Merge where it doesn't hide a real dependency or blow up slice size. Compaction never reorders across a real edge.
The graph helper (scripts/graph.mjs)
The deterministic core of Step 8/10. It reads a tasks JSON and does the mechanical graph work so
"is the order correct?" is a computed answer, not a vibe. Full I/O contract + the tasks JSON schema:
references/graph-schema.md. Quick reference:
node .claude/skills/roadmap-planner/scripts/graph.mjs analyze <tasks.json>— topo-sort; report cycles (with the cycle path), and order violations (a task whoseorderis ≤ a dependency'sorder, i.e. scheduled too early). Exit 0 = acyclic + no violations; exit 2 = cycle; exit 3 = ordering violation(s).node .claude/skills/roadmap-planner/scripts/graph.mjs order <tasks.json>— print one valid dependency-respecting order (stable: ties broken by bucket rank then id) — the Step 9 order.node .claude/skills/roadmap-planner/scripts/graph.mjs compact <tasks.json>— list Step-10 merge candidates.
The JSON is your structured output from Steps 1–7 (tasks with id, epic, bucket, category,
title, deps, and — for validating an existing roadmap — order = its current position). You build
it; the script judges it. Keep the intermediate tasks.json in the workspace so a re-run is cheap.
Execution engine (large corpus → multi-agent workflow)
Steps 1–4 read the whole corpus (here: ~45 spec chapters). That is a fan-out shape: one reader per
doc-cluster extracting {actors, use-cases, modules, interfaces, NFRs} as structured JSON, merged in
main context. Use the Workflow tool for this when the corpus is more than a handful of files —
parallel readers, then a synthesis/dedup barrier, then the (single-context) Steps 5–10. For a small
corpus, a single-context read is fine. The workflow is the engine; this skill is the recipe it runs.
Fan-out sketch (adapt to the corpus):
- Readers (parallel): partition the corpus (e.g. requirements/roles/ACs in one cluster; architecture modules/engines/services in another; the API/UI/data chapters). Each returns structured actors/use-cases/modules/NFRs with source citations.
- Synthesis (barrier): dedup + reconcile into one actor/use-case/module set; flag spec-vs-derived disagreements.
- Order + compact: build
tasks.json, run the helper, break cycles, emit derived roadmap + delta.
Output
Write two files (default under docs/roadmap/, or where the user says):
derived-<YYYY-MM-DD>.md— the derived, dependency-ordered roadmap: actors/use-cases traceability table, module + platform/solution split, epics, and the ordered typed tasks with their deps.delta-<YYYY-MM-DD>.md— findings vs the existing roadmap, ranked by severity:- Ordering violations (producer-after-consumer) — the highest-value finding; name the task, the prerequisite it precedes, and the fix.
- Circular dependencies found + how they were broken.
- Missing / extra tasks — in the derivation but not the roadmap (or vice-versa), each traced to a use-case (or flagged as unjustified).
- Compaction candidates — over-fragmented epics that can merge without hiding a dependency.
- Spec-vs-derivation disagreements (Step-1/4 reconciliation).
Lead the delta with a one-paragraph verdict: is the current order sound, and what are the top 3 fixes?
Constraints
- Never blindly overwrite the existing roadmap. Emit a proposal + delta; the human adopts.
- The dependency graph is the source of truth for order, not the bucket/category heuristics. If the graph and the heuristic disagree, the graph wins and that disagreement is a finding.
- Every task traces to a use-case; every use-case traces to an actor + a spec citation. A task with no use-case behind it is a finding (possible gold-plating). A use-case with no task is a gap.
- Deterministic where it can be. Cycle detection, topo-sort, and violation-flagging go through the helper, not eyeballing. The model supplies judgment; the script supplies proof.
- Reduce, then stop. Compaction serves velocity; don't over-merge into mega-tasks that hide dependencies or exceed a sane slice size.