ADR-0023: Frontmatter DAG and /sdd:graph Skill
Context and Problem Statement
Relationships between SDD artifacts are real but invisible to tooling. ADRs reference each other through prose ("Related: 📝 ADR-0009, 📝 ADR-0011", "Supersedes 📝 ADR-0003"), specs name their governing ADRs in ## Overview paragraphs, and the chain from decision → spec → requirement → code is reconstructed by humans reading multiple files. 📝 ADR-0020 already formalized the code-to-artifact direction via file-level governing comments, but the artifact-to-artifact direction remains unstructured prose. This blocks every higher-order capability we could want: impact analysis ("what breaks if I deprecate 📝 ADR-0008?"), orphan detection ("which specs have no implementing code?"), lineage queries ("show me the full chain from SPEC-0014 to its tests"), and any future semantic search or RAG layer that would need a parseable contract over the artifact graph.
How should the plugin make artifact relationships first-class so that they can be queried, traversed, and consumed by both humans and tooling — including any future local MCP for graph/RAG workflows?
Decision Drivers
- Markdown-native principle: 📝 ADR-0015 already eliminated
.claude-plugin-design.jsonin favor of CLAUDE.md sections. A new sidecar manifest for graph metadata would re-introduce the split-truth problem that decision was meant to fix. - Structured beats fuzzy at this scale: The corpus is 23 ADRs and 18 specs with explicit, named relationships. A graph captures what's actually true; vector embeddings would synthesize what's only approximately true. The graph is the right primitive.
- Foundation for future MCP: Whether or not we eventually ship a local MCP with embeddings + reranking (the user's "GraphRAG + KNN + reranking" goal), that MCP needs a parseable graph as input. Building the graph layer now creates the contract; the MCP becomes a downstream consumer rather than a coupled rewrite.
- Authoring ergonomics: Authors already write these relationships — just in prose at the bottom of the file. Lifting them into frontmatter is a re-shape, not a new burden, and it's where MADR already puts machine-readable metadata.
- Backfill path: 23 ADRs and 18 specs encode their edges in "Related" / "More Information" / "Supersedes" prose today. Any solution that requires retroactive manual annotation across all of them will stall.
- Complements 📝 ADR-0020: Code-to-artifact edges already exist via governing comment blocks. Formalizing artifact-to-artifact edges completes the graph without re-litigating the code side.
Considered Options
- Option 1: Frontmatter DAG +
/sdd:graphskill (artifact→artifact edges in MADR/OpenSpec frontmatter, traversal via a new skill, code edges supplied by 📝 ADR-0020 governing comments) - Option 2: Separate
.sdd-graph.yamlmanifest at the project root listing all edges - Option 3: Status quo — relationships live in prose; humans grep and read
- Option 4: Jump straight to a local MCP with embeddings + GraphRAG + reranker, deriving relationships from semantic similarity
Decision Outcome
Chosen option: "Option 1 — Frontmatter DAG + /sdd:graph skill", because it puts the relationships exactly where MADR already locates structured metadata (the YAML frontmatter), preserves the markdown-native principle from 📝 ADR-0015, completes the graph started by 📝 ADR-0020, and produces the parseable contract that any future MCP layer (Option 4 territory) would consume — without forcing us to commit to that ML build today. Three sub-decisions are bundled into this ADR because they are tightly coupled to the schema and would otherwise resurface the next time someone touches the graph:
Sub-decision 1: Edge schema (forward-only, artifact-level)
ADRs gain these optional frontmatter fields:
supersedes: [ADR-0003] # hard replacement; old artifact moves to status: superseded
extends: [ADR-0008, ADR-0009] # builds on without replacing (e.g., ADR-0011 extends ADR-0008)
enables: [ADR-0016] # this decision unblocks another (ADR-0015 enables ADR-0016)
governs: [SPEC-0007, SPEC-0010] # which specs this decision governs
related: [ADR-0010] # weak association, no semantic claim
Specs gain these optional frontmatter fields:
implements: [ADR-0009, ADR-0011] # which ADRs this spec realizes
requires: [SPEC-0007] # capability dependency on another spec
extends: [SPEC-0007] # behavioral extension (e.g., SPEC-0010 extends SPEC-0007)
supersedes: [SPEC-0XXX]
Reverse edges (ADR → implementing specs, SPEC → implementing code, ADR → dependent ADRs) are derived at graph-build time by inverting the forward edges. There is no governed-by: on specs or implemented-by: on ADRs — those are computed, not authored.
Sub-decision 2: Granularity is artifact-level in v1
Edges link whole artifacts (ADR ↔ ADR, ADR ↔ spec, spec ↔ spec). Requirement-level edges (e.g., SPEC-0014 REQ "Cross-Module Aggregation" governed-by ADR-0016) are explicitly out of scope for v1. They would make /sdd:check and /sdd:audit sharper, but they multiply authoring overhead and are best added once the artifact-level graph proves its value.
Sub-decision 3: Backfill is assisted, not manual
Backfilling 23 ADRs and 18 specs by hand will not happen. The /sdd:graph skill includes a backfill mode that parses existing prose ("Related:", "Supersedes", "More Information", ## Overview references to ADR-XXXX/SPEC-XXXX) and proposes a per-file diff for human review. The author accepts, edits, or rejects each proposed edge. No edges are added without explicit consent.
/sdd:graph skill shape (v1 verbs)
| Verb | Purpose |
|---|---|
impact <id> | Downstream artifacts and code affected if <id> changes |
ancestors <id> | Upstream chain (what <id> depends on, transitively) |
chain <id> | Full lineage: ADR → spec → requirement → code, both directions |
orphans | Code with no governing artifact; specs with no implementing code; ADRs with no implementing spec |
cycles | Detect circular dependencies (sanity check) |
backfill | Propose edges from prose for human review |
Output formats: ASCII DAG (default for hierarchical traversal verbs chain / impact / ancestors), markdown table (default for flat results orphans / cycles, or via --table), --mermaid for visual graphs, --json for downstream tooling consumption (this is the contract a future MCP would call). See SPEC-0018 REQ "Output Formats" for the full layout rules and JSON schema.
Consequences
- Good, because artifact relationships become parseable — impact analysis, lineage queries, and orphan detection are straightforward graph traversals
- Good, because the same schema serves
/sdd:graphnow and any future local MCP later — no rework when the MCP arrives - Good, because it aligns with 📝 ADR-0015 (markdown-native config) by keeping metadata in the artifact rather than a sidecar file
- Good, because it complements 📝 ADR-0020 (governing comment reform) — code→artifact edges from comments plus artifact→artifact edges from frontmatter make the full graph
- Good, because
/sdd:auditand/sdd:checkget sharper: when an ADR changes, the audit can name exactly which specs and code paths are at risk - Good, because the assisted backfill mode means existing artifacts can be lifted into the graph without a manual marathon
- Bad, because forward-only edges mean reading a spec's frontmatter does not directly show what governs it —
/sdd:graph ancestorsis required to answer that. Mitigated by the skill being cheap and by the markdown body still naming governing ADRs in the## Overview. - Bad, because artifact-level granularity means
/sdd:checkcannot pinpoint which specific requirement a code file violates — only that the file's governing spec has drifted. Acceptable in v1; requirement-level edges are a deferrable v2. - Bad, because every artifact that adds frontmatter edges becomes slightly noisier at the top. The noise is structured and bounded (5 edge types max, mostly empty) and is the price of parseability.
- Neutral, because this ADR does not commit to a future MCP — it only ensures that if/when one is built, the graph layer is already in place and the schema is the contract. The "GraphRAG + KNN + reranking" question is deferred until we know whether
/sdd:graphis sufficient or whether fuzzy queries become a real pain.
Confirmation
Implementation will be confirmed by:
- The MADR template in
skills/adr/SKILL.mddocuments the new optional frontmatter edge fields (supersedes,extends,enables,governs,related) - The OpenSpec template in
skills/spec/SKILL.mddocuments the new optional frontmatter edge fields (implements,requires,extends,supersedes) skills/graph/SKILL.mdexists and follows the established SKILL.md format with YAML frontmatter- Running
/sdd:graph impact ADR-0008returns a list of artifacts and code files that depend on 📝 ADR-0008 - Running
/sdd:graph orphansreturns code files lacking governing comments and specs lacking implementing code - Running
/sdd:graph backfillparses existing prose in the 23 ADRs + 18 specs in this repo and produces a per-file diff of proposed frontmatter edges for human review - The skill emits
--jsonoutput that a future MCP could consume directly without re-parsing markdown - Cycle detection rejects any backfill proposal that would introduce a circular dependency