TODO Metadata Layer and Graph
What is it?
The TODO metadata layer turns the Markdown roadmap under todo/ into a queryable graph without making Markdown any less canonical. Each roadmap file carries a small YAML frontmatter block with a stable ID; a generator reads every file (frontmatter, Implementation Order tables, cross-references and stamps) and writes a derived JSON cache. Tools then answer "what is ready to work on", "what blocks this", and "what references this section" from the cache instead of from fragile grep sweeps.
How does it work?
flowchart LR md[todo/**/*.md] --> build[build.py] build --> cache[(build/todo-cache.json)] cache --> validate[validate.py] cache --> query[query.py] cache --> render[render.py] cache --> mcp[mcp_server.py] mcp --> agents[Claude Code and Codex] validate --> ci[todo-graph.yml CI gate]
- Frontmatter. Each file starts with fields such as
id,domain,statusandtitle. The authoritative spec is TODO Frontmatter Spec, with a machine-readable JSON Schema. - Generator.
build.pyparses every roadmap file and emitsbuild/todo-cache.json, which is gitignored and always regenerated, never edited. - Validator.
validate.pychecks the cache for broken cross-references, duplicate IDs, dangling in-file anchors and similar structural faults. - Queries.
query.pyanswers questions over the cache, with TSV, Markdown or JSON output and a hard output ceiling that fails closed rather than truncating. - Rendering.
render.pydraws the graph as Mermaid, Graphviz, ASCII or a Gantt view; the result is published as TODO Dependency Graph. - MCP server.
mcp_server.pyexposes the read-only query verbs to AI agents; see MCP Usage.
Dependencies are tracked at two levels. File-level depends_on frontmatter is supported but unused today, while the Depends On column of every Implementation Order table carries section-level dependencies across files. On 2026-09-28, query.py stats reported 233 roadmap files and 715 cross-file section dependencies.
What are its interfaces?
| Command | Purpose |
|---|---|
bash scripts/todo-graph/build-and-validate.sh |
Rebuild the cache and run the validator (make todo-graph) |
python3 scripts/todo-graph/query.py section-ready |
Open sections that waited on another file and no longer do (sections with no cross-file dependency are excluded by design, so this is not a list of all runnable work) |
python3 scripts/todo-graph/query.py section-blocked / section-blocking |
What waits on what, ranked |
python3 scripts/todo-graph/query.py backlinks <id> |
Every reference to a roadmap file |
python3 scripts/todo-graph/query.py deferred-by <id> |
Stamps that parked work on a file |
python3 scripts/todo-graph/query.py code <id> |
Source files a roadmap file names |
python3 scripts/todo-graph/query.py stats |
Totals by status and domain |
make todo-graph-render-mermaid |
Regenerate the published graph page |
make todo-graph-mcp |
Run the MCP server in the foreground |
The CI gate is todo-graph.yml, which rebuilds and validates on every push that touches todo/.
How do I use it?
After editing any roadmap file, rebuild the cache as the last step before committing, because the pre-commit lint refuses a stale cache:
bash scripts/todo-graph/build-and-validate.sh --keep-cache
# [validate.py] 10/10 checks passed, 0 failure(s), 0 warning(s)
Then query it:
python3 scripts/todo-graph/query.py section-ready --limit 5
python3 scripts/todo-graph/query.py backlinks documentation-site --format markdown
A full rebuild of all 233 files took 2.2 seconds on the WSL2 development host on 2026-09-28.
What is not implemented yet?
The remaining gaps are parked and operator-gated:
- Parser residuals. The Markdown scanner does not model multi-line link reference definitions or the interaction of lazy continuation lines with nested containers; both need a backtracking block parser, and three attempts were reverted on measurement. See HTML Blocks Join the Tracker.
- Control-plane parsers. Several hooks and runner scripts still carry their own fence and clause parsing instead of the shared tracker, and the rewrite hook still swallows two failure classes; all are control-plane edits parked for an operator: section 37, section 38, section 29. Whether Check 7 should delegate unresolved symbols to the LSP bridge is an operator decision: section 11.
- Inline scanner. The code-span scanner still marks span ends with an in-band NUL character; no roadmap line triggers it today, but a NUL outside a code span would. One Accepted stamp in another roadmap file names a tier rather than a section number, so its reference is dropped from the graph until that stamp is corrected. Both are parked in section 44.
- Push-hook fixture. The pre-push hook passes the pushed commit to the identity gate, and that caller contract is pinned, but no end-to-end fixture yet pushes a commit whose OID differs from
HEAD. See The Hook Certifies Repository HEAD.
How does it compare with Windows 11 and Linux?
Windows teams track work in project-board databases and use CODEOWNERS for ownership; the Linux kernel uses the MAINTAINERS file with get_maintainer.pl and coordinates dependencies in patch cover letters. Neither keeps a validated, in-tree dependency graph over its plans, with CI refusing a broken cross-reference and a query surface that AI agents can call directly.