Skip to content

Documentation governance

This page defines how Vox documentation is organized and how to keep it from drifting.

This page is the policy. The mechanism — sources, site build, generated pages, and which gate catches which drift at which stage — is How Vox documentation works.

SurfacePrimary audienceOwnsMust not become
README.mdevaluators, first-time visitorsshort front door, quick start, tone, links into the booka second FAQ or architecture dump
docs-astrosite visitorsStarlight site entry + local preview (pnpm dev under docs-astro/)a contributor policy page
docs/src/explanation/faq.mdreaders and evaluatorscommon product and architecture questionsa troubleshooting runbook
docs/src/how-to/troubleshooting-faq.mdoperators and contributorsoperational fixes and environment troubleshootingthe main public FAQ
AGENTS.mdcontributors and agentsrequired cross-tool contributor policy, secret-management entry point, short architecture pointersthe general table of contents for the whole repo or a tool-specific troubleshooting log
docs/src/reference/readers and contributorslookup material, contracts mirrored in prose, stable operational referencesspeculative planning or marketing copy
docs/src/architecture/contributorscurrent architecture, authority maps, research, and roadmapsquick-start or beginner onboarding
docs/src/contributors/contributorscontributor hub, documentation governance, contributor-facing process guidancepublic product marketing
docs/agents/contributors and automationinventories, governance, machine-oriented support docsduplicated public documentation
docs/agents/*.jsoncontributors and automationmachine-readable IDE feature matrix, doc inventory, script registrymust not become hand-edited prose
contracts/code and CImachine-readable specs and schemaslong-form human explanation

Folder placement communicates ownership. Frontmatter communicates how a page should appear in the book.

Use one of these category values in frontmatter:

categoryMeaning
Getting Startedfirst-stop pages and front-door onboarding
Tutorialsguided learning
How-To Guidesgoal-oriented instructions
Conceptsconceptual understanding
Librarygeneral (non-Vox) curated knowledge pages under docs/src/library/, indexed by the KB
Language Referencestable lookup information
API Reference — Cratesper-crate API surface
Examplesworked examples
Architecture Decisions (ADRs)architecture decisions
Architecture SSOTscurrent architecture, authority maps (research and roadmap pages appear under Internals — see below)
CI & QualityCI and quality-specific references
Contributorscontributor-facing governance and process docs
Operationsrunbooks and operational catalogs
archivetombstoned pages (excluded from the sidebar)

These display labels are the enforced vocabulary — VALID_CATEGORIES in crates/vox-doc-pipeline/src/pipeline/lint.rs matches them exactly, with no alias normalisation. They must stay in sync with the sections array in contracts/documentation/docs-sidebar-section-order.v1.json.

Use status when the distinction matters to readers:

statusUse for
approvedaccepted ADR or policy text that is normative but not yet reflected everywhere in code/docs
currentdocumented behavior or process the repo actively relies on
experimentalimplemented but intentionally unstable or gated
legacystill present but not the preferred path
researchinvestigation, findings, or synthesis not equivalent to shipped behavior
roadmapfuture-facing implementation plans
deprecatedretained only for migration or compatibility notice

Do not use status to make aspirational pages sound shipped.

Pages with status: research or status: roadmap are grouped under a collapsed Internals sidebar section, shown last, instead of under their category. They render a status banner and a noindex robots tag, and they are omitted from the sitemap and from every published llms.txt variant. They stay searchable in the on-site search, labelled as Internals. Pages with status: deprecated or status: legacy keep their category but also get a banner and noindex.

The single source for this rule is docs-astro/src/utils/page-status.mjs; the sidebar, route metadata, sitemap filter and llms exclusion all read it. No category or frontmatter rewrite is needed — set status honestly and the page lands in the right place.

Use this template for new pages so docs lint passes on first run:

---
title: "Page title"
description: "One specific sentence about what this page covers."
category: "Architecture SSOTs"
status: "current"
topic: "doc-governance" # prefLabel from contracts/documentation/kb-taxonomy.v1.yaml
domain: "documentation" # prefLabel from the same file
authorship: "human" # human | llm-assisted | llm-generated (+ authorship_model for LLM)
training_eligible: true
# capabilities: [cli.secrets] # optional: capability ids this page explains
---
# Page title
<!-- kb:summary -->
40 to 120 words that say what the page is for and what it decides.
<!-- /kb:summary -->

New pages must also carry the KB facets and summary block shown above; see KB facets (taxonomy contract).

Note on temporal metadata: The “Last updated” date is the committer date of the newest commit touching the page’s source file, computed at build time by docs-astro/src/utils/git-dates.mjs. Commits listed in the repo-root .git-blame-ignore-revs, chore(ssot): auto-regenerate commits, formatting commits (style: and chore: fmt-style subjects) and bulk commits touching more than 100 files are skipped, and renames are followed. Frontmatter last_updated is ignored; do not add it. To keep a future mechanical sweep from resetting dates, add its commit SHA to .git-blame-ignore-revs.

To support deterministic drift detection without LLM dependencies (DRIFT-02, DRIFT-03), authored frontmatter optionally accepts:

  • owner: owning team or contributor (e.g. team-infra)
  • review_cadence: review period (e.g. "90d", "180d")
  • code_anchors: list of code paths or symbol spans the document relies on (e.g. crates/vox-cli/src/main.rs, crates/vox-compiler/src/parser/mod.rs#Parser).

Forbidden Keys in Authored Frontmatter:

  • last_updated: derived automatically from Git history. Hand-authoring is a hard lint error (hand-authored-last-updated).
  • last_verified / last_verified_commit: managed exclusively by the Freshness Ledger (contracts/reports/docs-freshness/ledger.v1.json). Hand-authoring is a hard lint error (hand-authored-last-verified).

A page may declare which capabilities it explains with an optional capabilities: [<capability id>, …] frontmatter key (flow or block list). Ids come from contracts/capabilities/capability-index.v1.json, for example cli.secrets.get, mcp.vox_check, surface.mesh or crate.vox-secrets.

  • vox ci capability-index validates every claimed id, so an unknown id fails vox ci ssot-drift with the page path and the id.
  • A claim adds the page as a doc link on each claimed capability (after its page-level default), and gives the page its own doc.<path> row. Pages that claim nothing get no row.
  • The doc lint is a line scanner: it does not parse YAML and does not check capabilities. The index generator is the check: a page whose capabilities: key it cannot read (for example a bare string instead of a list), or that has no closing ---, fails vox ci capability-index with the page path. Other malformed frontmatter that makes no claim is skipped. docs/src/archive/ is never read.
  • Regenerate with vox ci capability-index --write; never edit the index by hand.

Fast local lint loop:

  • cargo run -p vox-doc-pipeline -- --lint-only --paths architecture/my-page.md
  • cargo run -p vox-doc-pipeline -- --lint-only --paths architecture/my-page.md --fix

Authoring guardrail:

  • Do not start a line with a single backtick in prose (for example `vox ... at line start). Use normal prose with inline code or a full triple-backtick fence.

Every new or renamed page under docs/src/ (outside archive/ and *.generated.md) must carry KB facets so the knowledge base can filter, cite and gate training on it. The vocabulary is contracts/documentation/kb-taxonomy.v1.yaml; the typed schema is contracts/documentation/kb-facets.v1.schema.json (generated from vox_kb_facets::Facets).

Required facets:

  • topic and domain: exact prefLabel values from the taxonomy. A synonym (altLabel) or a retired alias is a lint error that names the right label.
  • authorship: human, llm-assisted or llm-generated. Add authorship_model whenever the authorship is LLM. Never write a value you cannot vouch for.
  • A page-one summary directly under the H1, independent of description and stripped from MENS training (shape below).
# Page title
<!-- kb:summary -->
40 to 120 words that say what the page is for and what it decides.
<!-- /kb:summary -->

Training eligibility is forced to false for origin: web-promoted pages and for LLM authorship unless human_attested_by names the human reviewer. Only a human sets human_attested_by; agents must never write it.

Promoted (origin: web-promoted) pages need sources[], each with url, date (YYYY-MM-DD) and hash (blake3: plus 64 hex characters). Quotes are capped at 50 words each and 200 words per page.

Optional facets: kb_tier, trust_tier, scope, review_by, verified_at, supersedes, superseded_by, sensitivity.

Rule idFix
facet-missing-topic, facet-missing-domainadd the facet with a taxonomy prefLabel
facet-unknown-topic, facet-unknown-domain, facet-deprecated-labeluse the prefLabel the message suggests
facet-domain-mismatchpick a topic that belongs to the page’s domain, or fix the domain
facet-missing-summary, facet-summary-placementput the kb:summary block directly under the H1
facet-summary-word-countkeep the summary between 40 and 120 words
facet-missing-authorship, facet-missing-authorship-modeladd authorship (and authorship_model for LLM authorship)
facet-training-eligible-contradictiondrop training_eligible: true, or add human_attested_by after human review
facet-missing-sources, facet-source-fieldgive every source a url, date and blake3 hash
facet-quote-over-capshorten or paraphrase the quote
facet-invalid-dateuse YYYY-MM-DD
facet-unknown-keyrename the misspelled frontmatter key (for example training_eligble) to the facet the message names
facet-invalid-attestationname the human reviewer in human_attested_by (not a placeholder such as false, none, todo or an AI name), or remove the key
facet-parse-errorfix the facet value named in the message
facet-backlog-stale (warning)run --tighten-facet-backlog
facet-contract-unreadablerestore the taxonomy and backlog under contracts/documentation/

Docs that predate the contract are listed, with the rule ids they still violate, in contracts/documentation/kb-facet-backlog.v1.yaml. A listed doc is excused only for its listed rule ids; editing it does not force compliance, but fixing it should be followed by:

cargo run -p vox-doc-pipeline -- --tighten-facet-backlog

The backlog only shrinks. Adding a row or rule id is USER-AUTHORIZED-ONLY: it needs a re-seed (--seed-facet-backlog --epoch-note "<why>"), which bumps the epoch, and the fast-tier gate rejects any growth that lacks one. Even a re-seed cannot list a doc that does not exist at the base ref: a new or renamed doc is never excused. Never hand-edit the file.

For a sustained doc vs code vs contract triage loop (aspiration vs fulfillment, historicity, and prioritized backlog), use the Documentation Reality Audit Program. Machine-readable claims and findings live under contracts/reports/docs-reality-audit/; CI validates them via vox ci docs-reality-audit verify (also included in vox ci ssot-drift).

Use one authority tier per documentation domain. The canonical registry is contracts/documentation/canonical-map.v1.yaml.

TierMeaningTypical locationCI expectation
A-specnormative machine-readable contractcontracts/, schema-backed registriescontract validator must pass
B-canonone canonical human page for the domainusually docs/src/reference/ (or one ADR)no second canon for same domain id
C-generatedcode-derived docs*.generated.md and include fragmentsgeneration verify command must pass
D-indexnavigation, index, compatibility stubs, research maps; Starlight sidebar is the D-index — do not maintain a committed research catalogarchitecture/ci pointers and index pagesmust link to canon, not restate canonical behavior

Rules:

  • Do not label a page as “SSOT” unless it is the sole B-canon page for its domain id in the canonical map.
  • D-index pages should summarize links only. If behavior text duplicates a B-canon page, remove it.

When adding or moving a page:

  1. If the source of truth is machine-readable, put the contract in contracts/ and link to it from docs/src/reference/.
  2. Register the domain in contracts/documentation/canonical-map.v1.yaml with spec_paths, one canon_doc, and any alias stubs.
  3. If the subject is a communication protocol or transport boundary, make the machine-readable artifact discoverable from contracts/index.yaml and mirror it from one canonical docs/src/reference/ page.
  4. If the page teaches or explains the user-facing language, keep it in docs/src/.
  5. If the page is mainly for contributors or automation, prefer docs/src/contributors/ or docs/agents/.
  6. If the page is research or planning, keep it under docs/src/architecture/ and label it clearly with status: research or status: roadmap.
  7. If a page exists only as a compatibility stub, make it a short redirect and avoid duplicating the canonical content.

Forward-facing docs should describe the architecture that exists now.

Prefer:

  • “Vox documents a compiler pipeline that generates Rust and TypeScript artifacts.”
  • “Mens currently defaults to code-oriented training lanes.”
  • “This page is research, not a claim that the capability is fully shipped.”

Avoid:

  • “Vox already does everything in this section automatically” unless the code path is current and documented.
  • “Mens answers architecture questions” unless that retrieval or QA path is explicitly wired and tested.
  • “SSOT” in titles when the page is only a convenience summary, pointer, or index.

Use this lightweight review matrix for high-drift surfaces:

If you changeAlso review
authority ownership, stubs, or canonical pathingcontracts/documentation/canonical-map.v1.yaml, vox ci check-docs-ssot, and affected alias pages
crates/vox-cli/src/** command surfacedocs/src/reference/cli.md, command-compliance docs, contributor references that mention the command
secret or env handlingAGENTS.md, Secrets SSOT
agent instruction layering or shell-discipline policyAGENTS.md, Agent instruction architecture, and relevant tool-specific overlays such as GEMINI.md
doc structure, nav, or new pagesthis page, docs/src/adr/002-diataxis-doc-architecture.md, docs-astro sidebar
architecture claimsDoc-to-code acceptance checklist, relevant explanation/reference pages
contracts or schema-backed behaviormatching contracts/ files and the mirrored reference pages
communication protocols, transport routes, or streaming semanticscontracts/communication/protocol-catalog.yaml, Communication protocols reference, and the owning protocol page such as MCP / Populi / runtime docs
Mens training or corpus behaviorMens native training SSOT, Mens training data contract
Codex research_metrics, mesh/cost telemetry env knobs, or telemetry trust boundariesTelemetry and research_metrics contract, env-vars, Telemetry trust SSOT
apps/editor/vox-vscode/ (extension host, webview UI, Oratio/MCP wiring)apps/editor/vox-vscode/README.md, VS Code to MCP compatibility; speech capture / Oratio pages when capture or tool surfaces change
  • Front door surfaces: review on every material product-language or contributor-experience change.
  • Architecture and reference pages: review when the owning code path changes.
  • Research and roadmap pages: keep their status current even if the implementation does not move.
  • Contributor and governance pages: review whenever CI, inventory rules, or workflow expectations change.

Before committing documentation to the repository, verify the following constraints:

  1. Syntax correctness: All code snippets must parse and type-check cleanly. You must write raw, inline ````vox``` code blocks within the document. The vox-doc-pipeline will dynamically extract and validate all inline Vox blocks. Only use {{#include}} for legacy files, or use // vox:skip inside the block to explicitly disable dynamic validation for pseudo-code.
  2. Authority registration: New canonical pages must be reflected in contracts/documentation/canonical-map.v1.yaml; aliases must remain link-only.
  3. Status marker: Use status only when needed (current, experimental, legacy, research, roadmap, deprecated).
  4. Terminology: Use established nomenclature (Codex vs Arca, Mens vs Populi, Islands vs Components).
  5. Navigation integrity: If creating a user-facing document, update Starlight nav metadata (frontmatter title / category / sort_order) and run vox-doc-pipeline --lint-only or pnpm --dir docs-astro build as appropriate.