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".
In this repository10 other files it gives its agents.
- changesetsSkill
- goal-debateSkill
- perf-passSkill
- plain-writingSkill
- pr-authorSkill
- pr-reviewSkill
- repo-setupSkill
- security-fixSkill
- ts-styleSkill
- ui-styleSkill
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
- Distinctive: line 12
Ask yourself what the user needs right now, then go to that phase.
- Very specific: line 51
Use the repo's existing decision record system when there is one (for example docs/decisions/NNNN-*.md).
- Distinctive: line 76
Every dependency has a kind.
- Distinctive: line 86
Before you plan, learn how the repo already plans.
- Distinctive: line 97
When importing a prose plan, keep a link from each node back to the paragraph it came from.
- Very specific: line 113
Read references/decomposition.md before this step.
- Distinctive: line 152
Prefer vertical slices over horizontal layers.
- Distinctive: line 154
Put contract-freezing nodes, spikes for risky unknowns, and changes to hot shared files in the first wave.
- Very specific: line 157
Leave ship: auto unless the user asks otherwise (see "Pull request or direct commit").
- Very specific: line 159
Run plan.py <root> status.
- Very specific: line 170
Read references/blindspots.md.
- Very specific: line 173
Write a premortem in reviews/premortem.md: assume the roadmap failed, list the five most likely reasons, and turn each into a mitigation, a …
- Very specific: line 194
Read references/orchestration.md before this step.
- Very specific: line 201
Stop at gates. At checkpoints, end the session to keep the orchestrator's context small.
- Very specific: line 209
Read references/memory.md.
- Very specific: line 211
Read the new outcome.md files.
- Distinctive: line 215
Update the briefs of downstream nodes whose upstream outcome deviated from the plan.
- Very specific: line 218
Write a short report to reviews/wave-<n>.md and tell the user what changed.
- Very specific: line 225
Write the node: Use the same brief template and rubric, and set added: <date>.
- Very specific: line 226
Check the impact: Run plan.py <root> impact <id>.
- Very specific: line 228
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.
- Very specific: line 234
Run plan.py <root> status with the current script and note the new warnings (hot files, merge orders for shared files).
- Very specific: line 238
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 …
- Very specific: line 239
Stories: Look for groups of todo nodes that together make one user-facing feature and do not make sense shipped apart.
- Very specific: line 240
Coverage: If the roadmap was imported from existing documents, add the "Coverage" section to GOAL.md and map every source step.
- Very specific: line 242
Run plan.py <root> check, then show the user plan.py <root> overview.
- Very specific: line 244
Never change status fields or the briefs of active nodes during an upgrade.
- Very specific: line 252
Write for an agent that has none of this conversation.
- Very specific: line 253
Keep GOAL.md and the roadmap CLAUDE.md short.
≈ “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.
Files
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 to | Start at |
| weigh whether a goal is worth its cost before planning it | the goal-debate skill, then 1. Discover |
| cut the scope of a roadmap that grows faster than it ships, or is over its budget | the goal-debate skill with --roadmap, then Change |
| plan something new | 1. 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 roadmap | 0. Survey, then 2. Decompose |
| review or harden a plan | 3. Stress-test |
| run the next batch of work | 6. Execute |
| add a feature or change scope while work is running | Change (below) |
| know where things stand | show plan.py <root> overview |
| close out a roadmap | 8. Close |
| bring a roadmap made with an older version of this skill up to date | Upgrade (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 needsOptions: --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. Needsvia: <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. Needsonandvia.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. Needsonand awhy.
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,
## OrderorNext stepssections. - Global counters that parallel branches will collide on: ADR numbers, migration numbers, numbered step lists, generated files. Record them in
GOAL.mdunder "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>). Setmerge.commits: offinGOAL.mdwhen every change must go through a pull request. - The branching model. Run pr-review's
branch_policy.py(or look fordev,develop,next,release/*branches and CONTRIBUTING). When the repo uses more than one integration branch, write the policy into thebranches:frontmatter ofGOAL.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. Setship: committo allow larger nodes up tomax_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: truenodes: 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.pyschedules 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 withmilestone:.plan.py statusreports each milestone's open nodes, outlines, and the wave its last node lands in. - Refinement happens as work approaches.
plan.py <root> refinelists outline nodes within the next two waves (--horizon Nto 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, ordevwith 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.pyschedules it that way. If an outside node only needs one child, make that childearly. - 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:
- Prefer vertical slices over horizontal layers. "Login, full stack" runs beside "signup, full stack". "UI, then API, then DB" is a chain.
- Name every shared interface as a contract in
contracts/, withstatus: draftanddefined_byset to the node that will freeze it. - Put contract-freezing nodes, spikes for risky unknowns, and changes to hot shared files in the first wave.
- Set a priority on every node by weighing its value to the project against its size (see "Priority" in
references/decomposition.md):mustis needed now,shouldis important but the goal can be reached without it,couldis worth doing when capacity is free, andlateris parked and not scheduled. Propose the priorities, then let the user confirm them, because value is the user's call. - Give each node a
type(feature, fix, hotfix, refactor, docs, release, experiment, ...). Anexperimentnode runs a hypothesis fixed by a goal debate: sethypothesis:to thatdebate.md, make the success threshold its acceptance, and record the result inoutcome.md, also when it misses.plan.pygates 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'sbench.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 inGOAL.md, the type decides the branch its pull request targets, andplan.pyshows it as-> dev. Settargetonly to override. Promotions between stages aretype: releasenodes withfromandtarget(for examplefrom: dev,target: next), gated, and depending on the work they ship;plan.py checkwarns when a release node does not wait for open work on itsfrombranch. Give a release node themilestoneit ships, andcheckalso warns about open nodes of that milestone it does not wait for. When the repo publishes from one branch (changesets or tags), setrelease:inGOAL.mdand give each release a node with a milestone.plan.pythen holds back work of later milestones until the release ships (see "Releasing from one branch" inreferences/orchestration.md). - Leave
ship: autounless the user asks otherwise (see "Pull request or direct commit"). Setship: pron a node the maintainer should see on its own even though the policy would allow a commit. - Reserve global numbers up front with
reserves:(for examplereserves: [migration 00043, adr 0067]). The script fails when two nodes reserve the same one. Tag nodes that need a single-use resource withexclusive:, for exampleexclusive: [loadtest]. - Run
plan.py <root> status. Fix every error. Then work on the result:- A long critical path means too many
hardedges. 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
couldnode is needed by amustnode means the low-priority work is really urgent. The script treats it asmust. Either accept that and raise it, or cut the dependency so themustwork 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 removemustnodes' 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.
- A long critical path means too many
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:
- Go through the checklist and either cover each category or mark it N/A with a reason.
- 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. - 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 inreviews/adversarial.mdand 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:
plan.py <root> refinelists outline nodes that are about to be needed; break them into briefs first.plan.py <root> verifycloses todo nodes whose acceptance already holds. Thenplan.py <root> ready --jsonlists the nodes to start.- Set each one to
status: activeand commit that. The orchestrator is the only writer ofstatus. - 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" inreferences/orchestration.md). - Spawn one agent per node with
isolation: worktree, usingtemplates/worker-prompt.mdand the model the script suggests. Spawn them in one message so they run at the same time. In sequential mode (modeinready --json), start only the first node, and the worktree is optional (see "Sequential mode" inreferences/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" inreferences/orchestration.md). No proof, no pull request. Then it builds on a branch from the node's target (targetinready --json, or the main branch when there is no branch policy). Withship: prit opens one pull request against that target. Withship: commitit opens none, and the orchestrator lands the branch as one commit (see "Direct commits" inreferences/orchestration.md). - Each change is reviewed once and checked once, as the
reviewfield ofready --jsonsays (set byreview:inGOAL.md, defaultauto). Infreshmode the orchestrator spawns one reviewer with the pr-review skill. Inselfmode 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, unlessplan.py <root> can-mergeallows the orchestrator to merge it (see "Auto-merge" inreferences/orchestration.md). Aship: commitnode that passescan-mergelands as one commit. One that fails gets a pull request for the maintainer. Agents never approve their own work. A node isdonewhen its change lands on its target. Run the curator (phase 7) at checkpoints. - 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.mdfiles. - Promote lasting code rules to nested
CLAUDE.mdfiles 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:
- Triage. Decide with the user whether the idea belongs in this roadmap, in a separate roadmap, or in
<root>/inbox.mdto 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 aremust. Feature ideas without such evidence are usuallyshouldor lower. A newmustpushes back the must line, so say what it costs. If it changes the outcome inGOAL.md, it is a scope change, so say that plainly before adding it. - Write the node. Use the same brief template and rubric, and set
added: <date>. - 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. - 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
harddependency on it. If the new work needs a contract to change, write a change request; do not edit a frozen contract. - Start it. If
impactsays 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:
- Run
plan.py <root> statuswith the current script and note the new warnings (hot files, merge orders for shared files). Fix errors first; warnings can wait for the user. - Give
GOAL.mda frontmatter block if it has none. Keep its body as it is. - Milestones. Propose a
milestones:list (releases, quarters, or whatever stages the user talks about) and amilestone:for each open node. Done nodes can stay untagged. - Outlines. Propose
outline: truefor 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 whenplan.py refinelists them. Leave active, done and near nodes alone. - Branches. If the repo has more than one integration branch (pr-review's
branch_policy.pytells), add thebranches:map toGOAL.mdand atype:to each open node. - Stories. Look for groups of todo nodes that together make one user-facing feature and do not make sense shipped apart. Propose a
type: storynode for each group andstory:on its members. Leave active and done nodes out. - Coverage. If the roadmap was imported from existing documents, add the "Coverage" section to
GOAL.mdand map every source step. - Where they help, add
verify:commands,exclusive:tags for single-use resources, andfulfilled_by:on nodes that turn out to be done already (plan.py verifyfinds candidates). - Run
plan.py <root> check, then show the userplan.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.mdand the roadmapCLAUDE.mdshort. 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.
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
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.

