roadmap
ProgressionMatrixStructure
Phased multi-workstream grid — phases across the top, workstreams down the side.
Variant
Use to show what ships in each phase across multiple parallel workstreams. Cells render as state-token discs (pass/warn/fail/skip).
planningswimlanemilestonesagile
When to use
- Phased delivery across workstreams. When the question is what each team ships in each phase. Workstreams down the side, phases across the top, deliverables in the cells — the whole plan reads in one glance.
- State markers are the second channel. Every cell can lead with
[x]shipped,[-]in flight,[!]missed,[?]uncertain,[ ]planned, or[/]out of scope. The audience sees both 'what' and 'how it's going' without a separate status slide. A status key is emitted automatically below the grid for the markers present (suppressed only on thestatusvariant, which already labels every cell). - The key's words are a DEFAULT, not a fixed vocabulary. 'Shipped' is right for a product plan and wrong for a legislative one. Write a label set above the grid — `
[{[x], Enacted}, {[-], In committee}]— and those states are renamed; the ones you do not name keep theirs. The key is the MARKER you already type in a cell, brackets included. The defaults are declared in this manifest'slabelSet, which is also whatlint:deck` checks your keys against, so a key that would be dropped is reported before you render. - Phase headers carry meta pills. Append `
Q2 2026` to a phase header and the renderer anchors a meta pill on the right of the column. Use it for date, owner, or status tags that frame the phase.
When not to use
- One workstream. A single row of phases is a
timelineorlist-steps, not a roadmap. Roadmap earns its grid only when at least two workstreams move in parallel. - No state markers. A grid of bare deliverables loses half its value. Add state markers (
[x][-][!][?][ ][/]) so the audience reads progress alongside scope. - Past five workstreams. More than five rows compresses cell text and the lane stripes lose their categorical read. Group adjacent workstreams or split by phase.
Common mistakes
- Writing the deliverable text before the state marker in a cell. Each cell must LEAD with the state marker (
[x] Shipped item), not follow it — a marker placed after the text isn't recognized as the cell's state. - Keying a label set on the state NAME rather than the marker.
[{shipped, Enacted}]binds to nothing and the row is dropped. A key is the marker exactly as a cell spells it —[x],[-],[!],[?],[ ],[/]— brackets included. The brackets are load-bearing: a bare space key collapses to empty under the parser's whitespace tidy and would take the[ ]row with it. - Naming a state the grid does not carry. A key row for a marker no cell uses would point at nothing, so it is dropped.
lint:decknames the key when that happens — the rendered key is not the place to discover it.
Authoring
<!-- _class: roadmap -->
## What ships in each phase, by workstream.
| Workstream | Foundation `{Q2 2026}` | Hardening `{Q3 2026}` | Scale `{Q4 2026}` |
| --- | --- | --- | --- |
| First workstream | [x] Shipped item | [-] In-flight item | [ ] Planned item |
| Second workstream | [x] Shipped item | [/] Out-of-scope item | [ ] Planned item |
The key under the grid names each marker the cells carry.Slots
| Slot | Selector | Required | Description |
|---|---|---|---|
title | h2 | yes | Slide heading naming the plan. |
rows | table | yes | A markdown table. The header row lists the phases (each may carry a date pill, written {Q2 2026} in inline code); the first column is the workstream name; each cell leads with a state marker [x]/[-]/[!]/[?]/[ ]/[/] then the deliverable. |
key | p > code:only-child | no | OPTIONAL label set renaming the status key: [{[x], Enacted}, {[-], In committee}], one inline-code span alone in its paragraph. The key is the MARKER you already type in a cell ([x] [-] [!] [?] [ ] [/]), brackets included — a bare space key collapses to empty and would drop its row. Naming a subset is the normal case; the rest keep the default words declared in this manifest's labelSet. The paragraph is consumed so it names the key rather than also printing as an eyebrow, and a one-code paragraph that is not a label set is left alone. |
Anatomy
┌─────────────────────────────────────────┐
│ header │
│ Phased roadmap heading. │
│ │
│ ┌───────────┬───────────┬───────────┐ │
│ │ │ Q1 │ Q2 │ │
│ ├───────────┼───────────┼───────────┤ │
│ │ Track A │ [x] done │ [-] wip │ │
│ │ Track B │ [ ] plan │ [/] skip │ │
│ └───────────┴───────────┴───────────┘ │
│ footer 1/19 │
└─────────────────────────────────────────┘Variant decision rule
- default (no modifier) — A plain phased grid — deliverables with state markers, no extra framing.
horizons— The plan is framed as Now/Next/Later strategic horizons rather than literal calendar phases.status— Delivery state itself is the headline read — every cell already labels its own state explicitly, so the auto-emitted legend key is suppressed.swimlane— Each team's track should read as its own lane rather than a uniform grid — emphasizes team ownership over the grid structure.milestones— The phases are named, dated release gates (Beta/RC/GA) rather than generic quarters — pins a dated path.
Variants
horizons — horizons
Bets spread across three horizons.
<!-- _class: roadmap horizons -->
`Three-horizon planning`
## horizons spreads the bets across three horizons.
| Workstream | Horizon 1 `{Now}` | Horizon 2 `{Next}` | Horizon 3 `{Later}` |
| ------------- | ------------------------ | ------------------------ | ------------------------- |
| Signal Intake | [x] Connector v1 | [-] Dedupe pass | [ ] Auto-routing |
| Scoring | [x] Equal weights | [-] Per-team weights | [/] Decision profiles |status — status
Delivery state at a glance.
<!-- _class: roadmap status -->
`Layout · roadmap status`
## status reads delivery state at a glance.
| Workstream | Foundation `{Q2 2026}` | Hardening `{Q3 2026}` | Scale `{Q4 2026}` |
| ------------- | -------------------- | ------------------------ | ------------------------- |
| Signal Intake | [x] Connector v1 | [-] Dedupe pass | [?] Auto-routing |
| Scoring | [x] Equal weights | [-] Per-team weights | [ ] Decision profiles |
| Decision Log | [x] Append schema | [!] Outcome pairing | [ ] Auditor export |swimlane — swimlane
One track per team.
<!-- _class: roadmap swimlane -->
`Layout · roadmap swimlane`
## swimlane gives each team its own track.
| Workstream | Foundation `{Q2 2026}` | Hardening `{Q3 2026}` | Scale `{Q4 2026}` |
| ------------- | -------------------- | ---------------------- | ------------------------- |
| Signal Intake | Connector v1 | Dedupe pass | Auto-routing |
| Scoring | Equal weights | Per-team weights | Decision profiles |
| Decision Log | Append schema | Outcome pairing | Auditor export |milestones — milestones
The dated path, pinned.
<!-- _class: roadmap milestones -->
`Layout · roadmap milestones`
## milestones pins the dated path.
| Workstream | Beta `{Q2 2026}` | RC `{Q3 2026}` | GA `{Q4 2026}` |
| ------------- | -------------------- | ---------------------- | ------------------------- |
| Signal Intake | Connector v1 | Dedupe pass | Auto-routing |
| Scoring | Equal weights | Per-team weights | Decision profiles |
| Decision Log | Append schema | Outcome pairing | Auditor export |Guides
- The six answerswhat each state marker means
- Marks in layoutsthis layout’s words for each mark, and renaming them with a label set
- Pills a component placesthe pill slots this component fills from position
Related
- ganttcontinuous task bars across a date axis rather than discrete phase cells
- kanbancurrent state by stage rather than phased schedule
- list-stepssingle workstream sequence without parallel lanes
- verdict-gridoptions scored against shared criteria, not phased delivery
- checklistsingle list with state markers, no workstream dimension