ADR-016: Vault Organization and Source-of-Truth Chain
Status
Accepted (2026-05-03). Implemented across commits eff820e12, 5ae863778, ae9c4cf8e, d54313f13, 3d9aa508a plus ralph repo 0.2.0.
Context
Before this restructure the repo had four parallel doc trees rooted at the top level:
/docs-code/ Obsidian vault for codebase knowledge (architecture, domains, infrastructure)
/docs-staff/ mkdocs source for internal staff docs
/docs-public/ mkdocs source for customer-facing help
/docs/ ad-hoc bucket: ADRs, conversations, plans, features, marketing, benchmarks, cto, ...
/specs/ design intent for in-flight features (ralph workspace)
This shape evolved organically, not by design. Three problems compounded:
-
Audience mixing in folder names.
docs-code/→ developer,docs-staff/→ internal,docs-public/→ customer. Thedocs-prefix repeated three times across top-level dirs gave them visual weight equal toapps/andpackages/, while their actual relationship was "different audiences for the same kind of content." -
Source-of-truth was implicit. When code disagreed with
docs-staff/docs/lockouts/index.md(the business rules), the doc was canonical. When code disagreed withdocs-code/domains/checkout.md(the architecture wiki), the code was canonical. Nothing in the layout signaled this. Agents had to infer authority from prose. -
Agent-first navigation was a side effect. Every artifact was for both humans and agents, but the org-chart split (staff/public/dev) optimized for human audiences. Agents reading the vault have to grep across three trees to answer "what's the canonical source for X?"
Metrognome's product-development model is also unusual: AI agents do most of the implementation, with Aaron acting as architect and reviewer. That makes the docs more load-bearing than typical:
- Specs are first-class permanent docs. They get written before implementation, ratchet through review, and stay updated as intent changes. They are not transient PM artifacts.
- Business rules drive code. A refund policy isn't documentation that follows the code; it's the constraint the code must satisfy.
- Agents need predictable file paths. Glob-driven schema (
features/*/spec.md) beats prose discovery every time.
The restructure had to express these choices in folder shape, not just prose.
Decision
Single vault rooted at /docs/
The whole /docs/ tree is one Obsidian vault (.obsidian/ at the root, not nested inside a subdir). Agents and Aaron share this vault. Whole-tree grep is the navigation primitive; per-subtree READMEs are the hubs.
docs/
.obsidian/
README.md vault entry, authority chain, layout map
business/ immutable product rules (staff site)
ops/ staff procedures, admin runbooks (staff site)
help/ customer-facing reference (public site)
marketing/ brand, ICP, positioning, KPIs
features/ design intent + plans + ralph artifacts
decisions/ ADRs (this file)
engineering/ architecture, domains, infrastructure, agent tooling
sites/ mkdocs publish wrappers (outside docs/ — see below)
staff/
public/
Audience-specific containers (code/, staff/, public/) are gone. Subtrees are organized by purpose (business rules vs procedures vs help vs ad strategy vs architecture), not by audience. Agents subsume all human audiences anyway — they read everything.
Source-of-truth chain
The folder structure encodes a hierarchy. Higher overrides lower; drift downstream is a bug to fix.
- Business logic (
business/) — immutable rules about how the product works. Code conforms. When code drifts from a rule, the code is wrong; never silently update the rule. - Spec (
features/<name>/spec.md) — canonical design intent for an implementation. Bridges business to code. Updated when intent changes; specs are not ephemeral. - Code — the running thing. Subordinate to spec, which is subordinate to business logic.
Every domain has a parallel chain across these subtrees: business/checkout/index.md → features/<checkout-feature>/spec.md → engineering/domains/checkout.md → actual code.
Audience hierarchy
Audience-narrower subsets are projections of agent-wide content, not separate corpora.
- Agent docs = the entire vault. Agents read everything.
- Staff docs =
business/+ops/published as docs.metrognome.com viasites/staff/. - Public docs =
help/published as help.metrognome.com viasites/public/.
mkdocs sites are thin publication wrappers, not content silos. Each sites/<site>/mkdocs.yml uses docs_dir: ../../docs and an explicit nav: listing the published pages. Vault-only content (engineering/, features/, marketing/, decisions/) is not in any nav.
sites/ lives outside docs/
mkdocs forbids site_dir inside docs_dir. With docs_dir: docs/, no Vercel outputDirectory configuration can satisfy both mkdocs and Vercel if the wrapper is nested inside docs/. So mkdocs wrappers live at repo root in /sites/staff/ and /sites/public/.
Folder-per-feature with role-named files
Inside features/, every feature is a folder. Files inside are named by role, not by feature.
features/<name>/
spec.md canonical design intent (the source of truth)
plan.md implementation plan with **Status:** + checkboxes (ralph drives this)
prompt.md ralph protocol for this divergence
progress.txt cross-iteration learnings (auto-grown by ralph)
research.md background, when needed
runbook.md ops procedure when applicable
retro.md post-mortem when applicable
deploy-checklist.md one-time deploy artifacts
Strict folder-always — even single-file features get a folder. Two reasons:
- Glob discoverability.
**/spec.mdreturns every design intent in the vault.**/plan.mdreturns every implementation plan. Cross-feature reasoning becomes one glob. - Self-describing filenames.
Read('features/posthog/spec.md')is unambiguous in a tool result.Read('features/posthog/index.md')requires folder context to interpret. Removing prefix-parsing from filenames lowers cognitive load per file.
Subject lives in the folder name, role lives in the filename — same convention as everywhere else in the vault (business/lockouts/index.md, engineering/architecture/api/overview.md).
Ralph integrated to the convention
Ralph (aaron-hogan/ralph 0.2.0) was updated to look for files at docs/features/<name>/{spec,plan,prompt,progress.txt} instead of the prior docs/specs/<name>-{plan,prompt,progress}.md pattern.
Consequences
What gets easier
- Agent navigation —
docs/features/<name>/spec.mdis always where the canonical intent lives. No prefix to parse, no audience folder to choose between. Glob**/{spec,plan,runbook,retro}.mdfinds everything by role. - Authority disputes — when something is wrong, the chain (business > spec > code) tells you which side moves. ADR-016 (this doc) names the rule.
- mkdocs sites stay thin — adding a new published page is a single nav entry. Reorganizing vault content doesn't require restructuring published sites.
- Ralph fits cleanly — the
<name>/{spec,plan,prompt}.mdshape matches how ralph thinks about a feature.
What gets harder
- mkdocs
docs_dir: ../../docsis non-standard. New contributors need the comment inmkdocs.ymlto understand the shape. - Vercel root directory for
docs-staffanddocs-publicprojects had to be repointed once at restructure time. Future site configuration changes happen in two places (vercel.json + mkdocs.yml) instead of one. - Strict folder-always means even a one-file feature creates a folder. Minor but adds an extra
mkdir.
What this rules out
- Specs as ephemeral PM artifacts. They stay in
features/after shipping and get updated as intent changes. We don't have a separate "PRD" concept; spec is the canonical artifact. - Per-audience doc trees at top level. No reverting to
/docs-staff/or/internal/style. Audience is a projection (mkdocs nav), not a layout. - Skill-as-source-of-truth. Skills like
mg-checkoutwere a stand-in for vault content that didn't exist yet. With domain pages in place underengineering/domains/, the skill content gets folded back in and the skills retire (Phase 2).
Related
- ADR-013: Domain skills for agent development — the predecessor model this restructure replaces. mg-* skills will retire (extraction → engineering/domains/).
- Ralph repo: aaron-hogan/ralph 0.2.0 — feature-folder convention.
- features/README.md — index + per-feature layout reference.
- README.md — vault entry, authority/audience map, conventions.