v1.67.0 ·
The roadmap picture that every move rewrote
The problem
The roadmap's only picture is two Mermaid files, .aidlc/roadmap/graph-backlog.mmd and
graph-full.mmd (packages/cli/src/roadmap/graph.ts). They need GitHub or an editor extension to
render, a Mermaid node cannot carry a link or a summary, and both files are committed and rebuilt on
every move (moveItem, packages/cli/src/roadmap/paths.ts:492-497). So every promotion edits two
shared generated files in whichever checkout ran it.
Measured on this repository's roadmap on 2026-10-06: 132 items (inbox 2, backlog 10, done 103,
hold 17), 26 items with a dependency, 7 with more than one, 39 edges, 49 items touching an edge,
23 roots, no cycles, no missing ids. 40 titles carry a backtick, quote, < or &. 93 items have a
promoted_to; 92 of those instances have a state folder in the checkout and 73 a
retrospective.md. Every hold item's last history entry carries a reason starting parked — or
declined — .
How it could be solved
Three decisions, each about keeping the picture from becoming one more thing the roadmap has to maintain. The first was where the page lives. Any committed page would need rebuilding on every move, which is the problem itself. So the page is made only when asked for, and written into git's own folder, which every working copy shares and git never commits. The price is freshness: the page is only as current as the last time someone made it, so it says when that was. And a teammate sees it only if someone sends them the file.
The second was how to show text nobody controls. Titles often carry quotes and angle brackets, so every piece of item text passes through one escaping function. Elements are named by their position, never by item id. Each item's side panel is an HTML template, not data inside the script. Either alternative would have needed a second kind of escaping. Behind that, the page accepts only its own script and styles, each matched by a fingerprint of its exact text, so anything that slipped past the escaping still would not run. The cost is that the markup can carry no inline styles.
The third was how much the browser does. The map's layout is worked out when the page is made, with no graph library, and the script only zooms, pans, collapses and highlights. That keeps the script small and the output checkable: the same items give the same bytes, apart from the line saying when. Ages are stored as dates and counted by the page, so even a copy made tomorrow differs by that line alone. What it gives up is redrawing: collapsing a branch leaves its gap. The first layout stacked every tree in one column, and on this project's own roadmap it fitted on screen at a fifth of its size, so the trees are now packed side by side.
How AIDLC solves it
The roadmap opens as one HTML page instead of two Mermaid files.
aidlc roadmap viewwrites one self-contained page and opens it in the default browser: a kanban board of every item by status and, below it, a zoomable map of thedepends_onchains.--no-openonly writes it;--out <path>writes it elsewhere. Default location:<git-common-dir>/aidlc/roadmap.html— shared by every worktree, never committed. Outside a git repo it goes in the project's own.aidlcfolder.- The board: backlog in
roadmap nextorder with ranks and ready items marked; the latest 20 done items with the rest behind "show all"; parked/declined and the reason on hold cards; links to each item file, instance folder, retrospective and GitHub pull requests; a side panel with the executive summary and dependencies; search across every column. - The map: each item under its first dependency, dashed links to the rest, unknown ids as red dashed nodes, blocked items marked, unlinked items behind a toggle; wheel/pinch zoom, drag pan, fit to screen, collapse a branch, click a node to highlight its whole chain.
- Moves write only the item.
moveItemno longer rebuildsgraph-backlog.mmd/graph-full.mmd, so a promotion stops leaving two shared generated files modified. aidlc doctor(safe tier,roadmap-mermaid-graphs) deletes those two files while their first line is still the generated header; a file someone replaced is left and reported.aidlc roadmap graphis now an alias ofview.
Visible to users on upgrade: the next aidlc update or aidlc doctor deletes the two .mmd
files under .aidlc/roadmap/ (the deletion shows in git status; commit it). aidlc roadmap graph opens a browser where it used to rewrite files — a script that called it after a hand move
should drop the call or add --no-open. The roadmap skill now says to run aidlc roadmap view
when asked to see the roadmap.
Changes
23 files under packages/, +2,780 / −242. 21 files outside it (state, knowledge, two regenerated
skill files), +964 / −4. 11 commits; each task commit carries its Task: trailer.
packages/cli/src/roadmap/view-model.ts,view-html.ts,view-assets.ts,open-browser.ts(new);roadmap/graph.ts(Mermaid renderer replaced bylayoutMap);roadmap/next.ts(pickNextAt);roadmap/paths.ts(moveItem).packages/cli/src/commands/roadmap.ts—viewCommand,defaultViewPath,viewwith aliasgraph.packages/cli/src/doctor/migrations/roadmap-mermaid-graphs.ts(+index.ts).packages/content/skills/04-roadmap.md,packages/content/docs/roadmap.md; regenerated.aidlc/skills/aidlc-roadmap.md,.agents/skills/aidlc-roadmap/SKILL.md,packages/website/src/data/cli-reference.json.- Tests: six new files and a fixture (87 tests across the seven touched files);
roadmap-graph.test.tsrewritten from Mermaid to layout; pins inroadmap-sync-purity.test.tsand the website'scli-reference.test.tsupdated forview. .aidlc/knowledge/— decisionsroadmap-view-outside-tree,roadmap-view-layout-in-ts; moduleroadmap-view.