v2.15.0 ·
Roadmap items say which milestone they serve
The roadmap could tell you what state every item was in. It could not tell you what any of it was for.
In one project I run, the roadmap has 96 items and 51 of them are in hold/. Many were parked against a goal, "Stage 2" or "first-customer readiness", written as prose in the hold reason. No tool could count that. So the question I actually ask, what is still missing for the thing we are working on now, was answered from memory or from a page somebody kept by hand.
What changed
A repo can now add a milestones.yaml file next to its roadmap folders: an ordered list where each milestone has an id, a title and a one-line exit test. Every item then names one in a milestone: line, or none for Unassigned.
Nothing about a milestone is stored except that list. Its status is worked out each time: not started with no items, done once it has items and every one is done or declined, and the first one that is not done is current. A parked item keeps its milestone open, which is the point. "We parked it" is not "we finished it".
aidlc roadmap status prints the answer in plain text, so it works in a chat with Claude or Codex. It opens with one line per milestone and its status. Under each milestone it lists what is done, in flight, next, parked, open and dropped, then everything Unassigned. aidlc roadmap view opens on a Milestones tab with the same groups and the same counts, because both read one function.
aidlc roadmap next and autopilot now pick from the current milestone first, and fall back to the usual order when it has nothing ready.
Adopting it on a big roadmap
Nobody is going to hand-edit 61 files. aidlc roadmap assign-milestones lists every open item without a milestone. The agent drafts one per item from its summary and the exit tests, and writes them with --set. Every pair is checked before anything is written, and nothing is committed. The person reads the diff and commits it.
I ran it on a copy of that 96-item roadmap with two milestones. It found 61 open items with no milestone, and each --set added exactly one line.
What it does not do
Done items are not required to carry the field. Backfilling years of finished work would be a cost with no reader, so they show as Unassigned and nothing complains.
The required field adds friction to every new item. That is on purpose, and a missing one is reported by aidlc roadmap status and aidlc doctor rather than guessed at. A repo without the file sees no change at all.
There are no dates, forecasts or nested milestones. And the real test, that project's roadmap with every open item assigned and reviewed, happens after this ships.