agentleFS
lxsmnsyclxsmnsyc/agent-skills/skills/parallel-roadmap/SKILL.md

parallel-roadmap

Skill4 starsChanged 14 days agoMITView on GitHub

Plan and run feature roadmaps as a dependency graph so several coding agents can work at the same time without blocking each other. Covers goal discovery, breaking work into right-sized nodes with typed dependencies, blindspot review, contract-first interfaces, wave scheduling, running waves of agents in git worktrees, and keeping long-term memory in the repo. Use this skill whenever the user wants to plan a feature, write or revise a roadmap, break a big change into tasks, convert an existing plan, proposal or ADR set into parallel work, run the next batch of roadmap work with agents, check roadmap status, or asks how to make agents work concurrently, even if they never say "roadmap" or "DAG".

The file

Show its rules and text

We split this skill into the rules it gives an agent

29 rules. About 0 are common, 7 are distinctive, and 22 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈7

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 22

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Ask yourself what the user needs right now, then go to that phase.

    line 12
  2. Very specific:

    Use the repo's existing decision record system when there is one (for example docs/decisions/NNNN-*.md).

    line 51
  3. Distinctive:

    Every dependency has a kind.

    line 76
  4. Distinctive:

    Before you plan, learn how the repo already plans.

    line 86
  5. Distinctive:

    When importing a prose plan, keep a link from each node back to the paragraph it came from.

    line 97
  6. Very specific:

    Read references/decomposition.md before this step.

    line 113
  7. Distinctive:

    Prefer vertical slices over horizontal layers.

    line 152
  8. Distinctive:

    Put contract-freezing nodes, spikes for risky unknowns, and changes to hot shared files in the first wave.

    line 154
  9. Very specific:

    Leave ship: auto unless the user asks otherwise (see "Pull request or direct commit").

    line 157
  10. Very specific:

    Run plan.py <root> status.

    line 159
  11. Very specific:

    Read references/blindspots.md.

    line 170
  12. Very specific:

    Write a premortem in reviews/premortem.md: assume the roadmap failed, list the five most likely reasons, and turn each into a mitigation, a …

    line 173
  13. Very specific:

    Read references/orchestration.md before this step.

    line 194
  14. Very specific:

    Stop at gates. At checkpoints, end the session to keep the orchestrator's context small.

    line 201
  15. Very specific:

    Read references/memory.md.

    line 209
  16. Very specific:

    Read the new outcome.md files.

    line 211
  17. Distinctive:

    Update the briefs of downstream nodes whose upstream outcome deviated from the plan.

    line 215
  18. Very specific:

    Write a short report to reviews/wave-<n>.md and tell the user what changed.

    line 218
  19. Very specific:

    Write the node: Use the same brief template and rubric, and set added: <date>.

    line 225
  20. Very specific:

    Check the impact: Run plan.py <root> impact <id>.

    line 226
  21. Very specific:

    Start it: If impact says it can start now and nothing active overlaps, spawn it right away instead of waiting for the wave to end.

    line 228
  22. Very specific:

    Run plan.py <root> status with the current script and note the new warnings (hot files, merge orders for shared files).

    line 234
  23. Very specific:

    Branches: If the repo has more than one integration branch (pr-review's branch_policy.py tells), add the branches: map to GOAL.md and a …

    line 238
  24. Very specific:

    Stories: Look for groups of todo nodes that together make one user-facing feature and do not make sense shipped apart.

    line 239
  25. Very specific:

    Coverage: If the roadmap was imported from existing documents, add the "Coverage" section to GOAL.md and map every source step.

    line 240
  26. Very specific:

    Run plan.py <root> check, then show the user plan.py <root> overview.

    line 242
  27. Very specific:

    Never change status fields or the briefs of active nodes during an upgrade.

    line 244
  28. Very specific:

    Write for an agent that has none of this conversation.

    line 252
  29. Very specific:

    Keep GOAL.md and the roadmap CLAUDE.md short.

    line 253

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Parallel roadmap

A linear roadmap makes every item wait for the one above it. Most of those waits are not real. A feature usually needs another feature's interface, not its finished code. This skill plans work as a graph of nodes with typed dependencies, freezes the shared interfaces first, and then runs every node whose inputs are ready at the same time, one agent per node, each in its own worktree.

Pick the entry point

Ask yourself what the user needs right now, then go to that phase. Do not run all phases when the user asks for one thing.

The user wants toStart at
weigh whether a goal is worth its cost before planning itthe goal-debate skill, then 1. Discover
cut the scope of a roadmap that grows faster than it ships, or is over its budgetthe goal-debate skill with --roadmap, then Change
plan something new1. Discover
add one feature that needs several nodes ("add a sign-in form")2. Decompose, as a story
turn an existing plan, proposal, ADR batch or backlog into a roadmap0. Survey, then 2. Decompose
review or harden a plan3. Stress-test
run the next batch of work6. Execute
add a feature or change scope while work is runningChange (below)
know where things standshow plan.py <root> overview
close out a roadmap8. Close
bring a roadmap made with an older version of this skill up to dateUpgrade (below)

Files

A roadmap lives in the repo, so it is versioned with the code and survives device changes. Use docs/roadmaps/<slug>/ when the repo has a docs/ folder, otherwise roadmaps/<slug>/.

<root>/                       # e.g. docs/roadmaps/perf-batch/
  GOAL.md                     # L0: outcome, constraints, non-goals, verification commands
  CLAUDE.md                   # L0: rules for agents working on this roadmap (short)
  contracts/<name>.md         # frozen interfaces between nodes
  contracts/<name>.change-request.md
  nodes/<id>/brief.md         # planner writes: goal, typed deps, owned paths, size, acceptance
  nodes/<id>/log.md           # worker's private notes, never read by other nodes
  nodes/<id>/outcome.md       # worker's distilled result, the only thing that flows downstream
  reviews/                    # premortem, adversarial review, wave reports
  archive.md                  # one line per done node whose folder was removed (plan.py archive)

Templates for each file are in templates/. Copy them; do not invent new fields, because scripts/plan.py reads the frontmatter.

Token spend lives in the briefs too. When a node closes, the orchestrator sets spent: to the tokens its worker, reviewer and fix rounds used, from the agents' usage reports. With budget: {tokens: N} in GOAL.md (usually from a goal debate), plan.py reports spend against the budget and a forecast at the current rate, and warns at 80% and when the forecast goes over. Over budget means stop and cut scope, or rerun the goal debate with the actual spend.

Status lives in exactly one place: the status field of each brief. done means the node's change landed on its target branch: its pull request merged, or its direct commit was pushed. For a story's child, that is the story branch. In repos with several stages (dev -> next -> main), released means the work reached the last one. In repos that publish from one branch, it means the work was published. The curator sets it when a release node merges. Other documents link to the roadmap instead of restating status. Repos that track status in three places (a strategy doc, an ADR header and a proposal list) drift apart within weeks.

Use the repo's existing decision record system when there is one (for example docs/decisions/NNNN-*.md). Only create <root>/decisions/ when the repo has nothing.

The script

scripts/plan.py is the source of truth for the graph. Do not schedule by reading the briefs and reasoning about them, because it is easy to miss an edge or an overlap. Run the script.

python3 <skill>/scripts/plan.py <root> status          # validate, waves, critical path, parallelism
python3 <skill>/scripts/plan.py <root> check           # validation only, exit 1 on errors
python3 <skill>/scripts/plan.py <root> ready --json    # nodes that can start now, with model and context files
python3 <skill>/scripts/plan.py <root> context <id>    # the files an agent on <id> should load, with token estimates
python3 <skill>/scripts/plan.py <root> impact <id>     # what adding <id> does: overlaps, contracts, critical path
python3 <skill>/scripts/plan.py <root> verify [<id>]   # run verify commands; finds todo nodes that are already fulfilled
python3 <skill>/scripts/plan.py <root> refine          # outline nodes close enough to break into full briefs now
python3 <skill>/scripts/plan.py <root> overview        # readable summary for the user, grouped by milestone
python3 <skill>/scripts/plan.py <root> can-merge <id> ...  # may the orchestrator merge this PR without the user?
python3 <skill>/scripts/plan.py <root> archive [--apply]   # remove done nodes nothing open still needs

Options: --max-parallel N (default 4; 1, or run: sequential in GOAL.md, means sequential mode), --budget TOKENS (default 20000), --upto must|should|could|later, --cwd DIR (where verify commands run, the repo root).

verify runs project commands (tests, builds) in the directory given by --cwd. That is usually the user's own checkout, which they may be working in. Before the first verify in a session, check git status: if the tree has uncommitted changes, tell the user what will run and ask first, or run it in a separate worktree.

Dependency kinds

Every dependency has a kind. The kind decides when the dependent node can start.

  • contract: the node needs only an interface, type, schema or file format. It can start once that contract is frozen. Needs via: <contract>.
  • behavior: the node needs real runtime behavior, but can be built against a stub of the contract and integrated later. It starts when the contract is frozen. The script lists it under "integration pending" until the upstream node is done. Needs on and via.
  • hard: the node needs the other code to exist, for example a refactor of the same function. It starts when the upstream node is done. Needs on and a why.

Agents label too many dependencies as hard. For each one, ask: "could this start against a frozen interface and a stub?" If yes, it is contract or behavior. A hard dependency without a why is a warning.

0. Survey (existing repos)

Before you plan, learn how the repo already plans. Look for:

  • Planning documents: strategy or roadmap files, proposals, ADRs, backlogs, ## Order or Next steps sections.
  • Global counters that parallel branches will collide on: ADR numbers, migration numbers, numbered step lists, generated files. Record them in GOAL.md under "Numbered resources".
  • Verification: the check command, how long it takes, and whether two copies can run at once (shared database containers, fixed ports).
  • Hot files that many features touch: route registries, config, barrel exports, the main plan document itself.
  • Resources that only one task can use at a time: load tests, benchmarks, a database container on a fixed port.
  • Whether the target branches accept direct pushes. Branch protection or a ruleset that requires pull requests rules out direct commits there (gh api repos/{owner}/{repo}/rules/branches/<branch>). Set merge.commits: off in GOAL.md when every change must go through a pull request.
  • The branching model. Run pr-review's branch_policy.py (or look for dev, develop, next, release/* branches and CONTRIBUTING). When the repo uses more than one integration branch, write the policy into the branches: frontmatter of GOAL.md, so every node gets the right target.
  • Whether the repo is private (gh repo view --json visibility). Pushing branches to a private repo can trigger billed CI. If the user does not want that, workers keep branches local and checks run locally.

When importing a prose plan, keep a link from each node back to the paragraph it came from. Do not rewrite the source documents.

Account for every step of the source. Each step or item in the documents you import maps to exactly one of: a node, an inbox entry (parked for later, with the reason), already built (fulfilled_by), or dropped (with the reason). Write that mapping in GOAL.md under "Coverage". A step that silently disappears is the most common import mistake, and the user cannot see it from the plan alone.

Check each imported item against the code before writing its node. Planning documents go stale, and items listed as pending are often already built. Spend a minute per item: grep for the names it introduces, look for its tests, search git log. Already built items become done nodes with fulfilled_by: set, or are left out with a note in GOAL.md. Partly built items get a brief for the remainder only.

1. Discover

Work out the goal with the user in a short feedback loop. Write GOAL.md from the template: outcome, priorities, constraints, non-goals, verification commands, numbered resources, open questions. Keep it under about 1,500 tokens because every agent loads it.

If a goal debate ran first (<root>/debate/debate.md, approved), build GOAL.md from it: the settled structure is the outcome, each axis budget becomes a constraint, rejected alternatives become non-goals, and open risks become first-wave spikes. For a large or costly goal with no debate, offer one before decomposing.

Agree on what "must" means for this roadmap, usually a release or a user-visible milestone. Without that line, everything becomes a must and priorities stop meaning anything.

2. Decompose

Read references/decomposition.md before this step. It holds the sizing rubric, the split strategies and the merge rules.

A node is one change: a change a reviewer can read in one sitting and that is safe to merge on its own. It ships as a pull request, or as one direct commit (see "Pull request or direct commit" below). That sets the size range. Most nodes are M. There is no limit on how many nodes a roadmap has; a big goal needs many. What signals a plan cut too fine is its shape: chains of S nodes on the same files, or a plan that is mostly S. plan.py check warns about both, because each extra node costs a worktree, a review and a merge.

Pull request or direct commit

A pull request is for a person to review and approve. Some nodes are never read on their own by a person. For them the pull request only adds overhead: a push, CI runs, a draft, a merge. Such a node ships as one direct commit onto its target branch instead. It still gets its worker, worktree, review and checks. Only the pull request is skipped.

plan.py decides, and gives the result as ship in ready --json. A node ships as a commit when the orchestrator may land it without the maintainer (the same policy can-merge applies) and one of these holds:

  • It is a story child on the story branch. The maintainer reviews it in the story pull request.
  • Under merge.mode: auto, it is S, or a docs or chore node. Set ship: commit to allow larger nodes up to max_size.

Everything else ships as a pull request. That covers stories themselves, early children and the excluded types (releases, hotfixes, contracts, gates). Under the default merge.mode: maintainer, it also covers every node that is not a story child. ship: pr on a brief, or merge.commits: off in GOAL.md, always keeps the pull request. When the checks at landing time fail can-merge, the node falls back to a pull request for the maintainer.

Detail where it is near, outline where it is far

A roadmap can cover months or years. Planning all of it down to pull-request-sized briefs wastes effort, because far-off work changes before anyone reaches it. So cut in layers:

  • Near work (the next few waves) gets full briefs, as below.
  • Far work gets outline: true nodes: a title, a goal paragraph, a priority, rough dependencies and a size guess (XL is fine). No owned paths, acceptance criteria or contracts yet. plan.py schedules outlines in the forecast, never starts them, and skips its shape checks for them.
  • Milestones group the plan into stages that mean something to the user (a release, a quarter). List them in order in GOAL.md (milestones: [...]) and tag nodes with milestone:. plan.py status reports each milestone's open nodes, outlines, and the wave its last node lands in.
  • Refinement happens as work approaches. plan.py <root> refine lists outline nodes within the next two waves (--horizon N to change it). Break each into one or more full briefs at that point, using what the finished nodes taught. The curator does this at every checkpoint, so outlines become briefs a little ahead of the agents.

Stories: one feature, one branch

A request like "add a sign-in form" is one feature to the user, but often several nodes of work. Make it a story: a type: story node whose brief holds the feature's goal and acceptance, with child nodes that set story: <story id>. The story is a small roadmap on one feature branch:

  • The story branch is feat/<story id>, cut from the story's target (the main branch, or dev with a branch policy).
  • Each child is a normal node with its own brief, worker, worktree and review. It lands on the story branch, so children run in parallel and build on each other there. By default a child lands as one direct commit, with no pull request of its own: the maintainer reviews it in the story pull request.
  • When every child is done, the story itself is one pull request from the story branch into its target. The maintainer reviews the feature as a whole. By default the orchestrator lands children on the story branch itself (merge.stories: auto), since nothing reaches the main branch without the story pull request.
  • Early children. Some children must land on the parent branch before the story: a split of a hot file, a fix to a bug on the base, a dependency bump, or a contract that nodes outside the story use. Mark them early: true. They target the story's target branch and follow its rules, and the story branch merges them in after they land. An early child cannot need a child that is not early.
  • From outside the story, a dependency on a child waits for the whole story. The same holds for a contract a child freezes. That code is only on the story branch until the story merges, and plan.py schedules it that way. If an outside node only needs one child, make that child early.
  • A story's own dependencies apply to all its children. Children take the story's priority and milestone when theirs are empty.

Use a story when the feature should reach users in one piece and its parts do not make sense alone. Keep separate top-level nodes when each part is useful on its own: they ship sooner. A far-off story can stay outline: true with no children; plan.py refine lists it when it is near, and refining it means writing its children. Stories do not nest.

For each detailed node, write nodes/<id>/brief.md with priority, typed dependencies, owned paths (globs), size, acceptance criteria and a verify command when the acceptance can be checked by one. Keep briefs short: what the worker cannot get from the contracts and dependency outcomes, and nothing else. Then:

  1. Prefer vertical slices over horizontal layers. "Login, full stack" runs beside "signup, full stack". "UI, then API, then DB" is a chain.
  2. Name every shared interface as a contract in contracts/, with status: draft and defined_by set to the node that will freeze it.
  3. Put contract-freezing nodes, spikes for risky unknowns, and changes to hot shared files in the first wave.
  4. Set a priority on every node by weighing its value to the project against its size (see "Priority" in references/decomposition.md): must is needed now, should is important but the goal can be reached without it, could is worth doing when capacity is free, and later is parked and not scheduled. Propose the priorities, then let the user confirm them, because value is the user's call.
  5. Give each node a type (feature, fix, hotfix, refactor, docs, release, experiment, ...). An experiment node runs a hypothesis fixed by a goal debate: set hypothesis: to that debate.md, make the success threshold its acceptance, and record the result in outcome.md, also when it misses. plan.py gates experiments, so nothing builds on a result before the user has seen it. A threshold on a timing or size metric counts as met only when the gain is larger than the noise: measure it with perf-pass's bench.py, and treat "within noise" as missed. A threshold on a count (spec examples passed, cases that match a reference implementation) is exact. With a branch policy in GOAL.md, the type decides the branch its pull request targets, and plan.py shows it as -> dev. Set target only to override. Promotions between stages are type: release nodes with from and target (for example from: dev, target: next), gated, and depending on the work they ship; plan.py check warns when a release node does not wait for open work on its from branch. Give a release node the milestone it ships, and check also warns about open nodes of that milestone it does not wait for. When the repo publishes from one branch (changesets or tags), set release: in GOAL.md and give each release a node with a milestone. plan.py then holds back work of later milestones until the release ships (see "Releasing from one branch" in references/orchestration.md).
  6. Leave ship: auto unless the user asks otherwise (see "Pull request or direct commit"). Set ship: pr on a node the maintainer should see on its own even though the policy would allow a commit.
  7. Reserve global numbers up front with reserves: (for example reserves: [migration 00043, adr 0067]). The script fails when two nodes reserve the same one. Tag nodes that need a single-use resource with exclusive:, for example exclusive: [loadtest].
  8. Run plan.py <root> status. Fix every error. Then work on the result:
    • A long critical path means too many hard edges. Challenge them, or split the nodes on the path.
    • A node deferred because of an owned path overlap, or a "shared ... plan the merge order" note, means several nodes edit the same file. Prefer splitting that file by feature in an early, behavior-preserving node, so each later node owns its own module (see "Split hot files by feature first" in references/decomposition.md). Otherwise accept the serialization or plan the merge order.
    • An XL node must be split.
    • Parallelism under about 1.5x means the plan is still mostly linear.
    • A warning that a could node is needed by a must node means the low-priority work is really urgent. The script treats it as must. Either accept that and raise it, or cut the dependency so the must work does not wait on it.
    • "All must work placed by wave N", the must line, is the number that matters most. If it is too late, move work out of must, or remove must nodes' dependencies on lower-priority work.
    • A warning about S nodes in a hard chain on the same files means they should be one node. Merge them.

3. Stress-test

Read references/blindspots.md. Scale the effort to the plan: for a few nodes, the checklist and a short premortem are enough. For a plan of about six nodes or more, or one that touches shared core code, do all three:

  1. Go through the checklist and either cover each category or mark it N/A with a reason.
  2. Write a premortem in reviews/premortem.md: assume the roadmap failed, list the five most likely reasons, and turn each into a mitigation, a new node or a spike.
  3. Spawn a reviewer agent with fresh context, using the prompt in references/blindspots.md. Give it only the roadmap directory and the repo, not your reasoning, because a reviewer that sees your reasoning tends to agree with it. It checks only the three areas where errors change the plan's shape: contracts against the real code, owned paths around shared files, and dependency edges. Save the result in reviews/adversarial.md and apply what holds up.

Show the user the plan and get their approval before execution. This is the cheapest point to change direction. Paste the output of a fresh plan.py <root> overview run into the chat: the goal, each milestone with its nodes, the must line, the critical path and what to refine next. Do not restate the plan from memory, because the script is the source of truth and a plan edited after the last run drifts from what you remember. Below it, list the main risks and every assumption the user should confirm.

Show the overview again whenever the plan changes shape: after an addition (Change), an upgrade, or a curator pass that added, split or dropped nodes.

4. Contracts

The first wave freezes contracts: types, signatures, schemas, event names, stub or fake implementations, and contract tests that any real implementation must pass. When a contract-freezing node is done, set the contract's status: frozen and bump its version.

Contracts are the gate that matters most. A wrong contract wastes every parallel branch built on it, so stop for user review after the contract wave unless the user said not to.

5. Schedule

plan.py status prints the waves. Waves are a forecast; execution always asks the script what is ready now. Mark nodes that need a human review afterwards with gate: true.

The scheduler fills each wave by priority first and critical path second, so must work never waits behind could work, and could nodes use the slots that are left. Use --upto must to see the shortest plan that reaches the goal, and --upto later to include parked work.

6. Execute

Read references/orchestration.md before this step. In short:

  1. plan.py <root> refine lists outline nodes that are about to be needed; break them into briefs first. plan.py <root> verify closes todo nodes whose acceptance already holds. Then plan.py <root> ready --json lists the nodes to start.
  2. Set each one to status: active and commit that. The orchestrator is the only writer of status.
  3. Before the first child of a story starts, create the story branch from the story's target and set the story to status: active. A ready node with "action": "story-pr" is a story whose children are all done: open its pull request yourself, without a worker (see "Stories" in references/orchestration.md).
  4. Spawn one agent per node with isolation: worktree, using templates/worker-prompt.md and the model the script suggests. Spawn them in one message so they run at the same time. In sequential mode (mode in ready --json), start only the first node, and the worktree is optional (see "Sequential mode" in references/orchestration.md). Each worker first checks whether its work already exists. For a node that fixes a problem, it then proves the problem on the target before changing code (see "Unproven problems" in references/orchestration.md). No proof, no pull request. Then it builds on a branch from the node's target (target in ready --json, or the main branch when there is no branch policy). With ship: pr it opens one pull request against that target. With ship: commit it opens none, and the orchestrator lands the branch as one commit (see "Direct commits" in references/orchestration.md).
  5. Each change is reviewed once and checked once, as the review field of ready --json says (set by review: in GOAL.md, default auto). In fresh mode the orchestrator spawns one reviewer with the pr-review skill. In self mode the worker reviews its own branch. The orchestrator works from the replies and the script output, and does not review or check a second time. Then the pull request goes to the maintainer, unless plan.py <root> can-merge allows the orchestrator to merge it (see "Auto-merge" in references/orchestration.md). A ship: commit node that passes can-merge lands as one commit. One that fails gets a pull request for the maintainer. Agents never approve their own work. A node is done when its change lands on its target. Run the curator (phase 7) at checkpoints.
  6. Stop at gates. At checkpoints, end the session to keep the orchestrator's context small. The next session resumes from the repo (see "Keeping the orchestrator's context small" in references/orchestration.md). Then go back to step 1.

One change per node is the default, because every piece of work then merges on its own and nothing waits for a large integration branch. A story is the exception: a feature branch scoped to one feature, which merges as soon as that feature is done. Use a branch for the whole roadmap only when the user asks for it.

For long roadmaps, scripts/wave.workflow.js runs one wave as a Workflow (fan-out plus curator), driven by the ready --json output.

7. Curate (after every wave)

Read references/memory.md. One curator pass per wave:

  • Read the new outcome.md files.
  • Promote lasting code rules to nested CLAUDE.md files next to the code they apply to. Promote decisions to the repo's decision records.
  • Turn rules that a test, type or lint rule can enforce into new nodes, instead of prose.
  • Resolve contract change requests: accept (bump the version, list affected nodes) or reject (tell the requesting node to adapt).
  • Update the briefs of downstream nodes whose upstream outcome deviated from the plan.
  • Record estimate against actual in <roadmaps-dir>/CALIBRATION.md.

Write a short report to reviews/wave-<n>.md and tell the user what changed.

Change: additions during development

New ideas arrive while waves are running. That is normal, and the graph makes it cheap: a new node only has to fit around the nodes it touches, not around the whole list. Read references/changes.md for the full procedure. In short:

  1. Triage. Decide with the user whether the idea belongs in this roadmap, in a separate roadmap, or in <root>/inbox.md to look at later, and give it a priority. Base it on evidence: security problems seen in the wild, data loss, broken production behavior and blocked users are must. Feature ideas without such evidence are usually should or lower. A new must pushes back the must line, so say what it costs. If it changes the outcome in GOAL.md, it is a scope change, so say that plainly before adding it.
  2. Write the node. Use the same brief template and rubric, and set added: <date>.
  3. Check the impact. Run plan.py <root> impact <id>. It shows whether the node can start now, which nodes it overlaps (including running ones), which contracts it uses, and how it changes the critical path and the number of waves.
  4. Fit it in without disturbing running work. Never edit the brief of an active node. If the new work changes what an active node is building, let that node finish against its brief and add a follow-up node with a hard dependency on it. If the new work needs a contract to change, write a change request; do not edit a frozen contract.
  5. Start it. If impact says it can start now and nothing active overlaps, spawn it right away instead of waiting for the wave to end.

Upgrade a roadmap made with an older version

Every field added since the first version is optional, so an old roadmap still loads. Upgrading is a short pass that changes no work, only how the plan is described. Do it in this order, and show the user the proposals in steps 3, 4 and 6 before writing them, because they change how the plan reads:

  1. Run plan.py <root> status with the current script and note the new warnings (hot files, merge orders for shared files). Fix errors first; warnings can wait for the user.
  2. Give GOAL.md a frontmatter block if it has none. Keep its body as it is.
  3. Milestones. Propose a milestones: list (releases, quarters, or whatever stages the user talks about) and a milestone: for each open node. Done nodes can stay untagged.
  4. Outlines. Propose outline: true for todo nodes that will not start within the next two or three waves and whose briefs are mostly guesswork. Keep their text as notes; it is rewritten when plan.py refine lists them. Leave active, done and near nodes alone.
  5. Branches. If the repo has more than one integration branch (pr-review's branch_policy.py tells), add the branches: map to GOAL.md and a type: to each open node.
  6. Stories. Look for groups of todo nodes that together make one user-facing feature and do not make sense shipped apart. Propose a type: story node for each group and story: on its members. Leave active and done nodes out.
  7. Coverage. If the roadmap was imported from existing documents, add the "Coverage" section to GOAL.md and map every source step.
  8. Where they help, add verify: commands, exclusive: tags for single-use resources, and fulfilled_by: on nodes that turn out to be done already (plan.py verify finds candidates).
  9. Run plan.py <root> check, then show the user plan.py <root> overview.

Never change status fields or the briefs of active nodes during an upgrade.

8. Close

When every node is done or dropped: check that GOAL.md acceptance holds, move lasting decisions out of the roadmap, make sure nested CLAUDE.md files hold the lasting learnings, and add a final calibration entry. Leave the roadmap directory in place as history, or delete it if the user prefers. Its outcomes should no longer be needed by anyone.

Writing the files

  • Write for an agent that has none of this conversation. A brief must make sense on its own together with the files from plan.py context.
  • Keep GOAL.md and the roadmap CLAUDE.md short. They load for every node.
  • Outcomes describe what was built, where the code is, deviations from the contract, stubs left behind, and gotchas. They do not retell the work.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.