Skip to content

Documentation Standard

This is the spec every BoB doc must obey. Each doc declares one Diátaxis mode, lives in the matching docs/ category, carries a frontmatter contract (type / owner / last_reviewed), and states each fact once (link, don't duplicate). The governance tooling (R2) and CI (R3) enforce what follows; this document is the source of truth they read.

This doc is itself reference mode (look things up; don't read end-to-end). It lives in docs/reference/ and carries the frontmatter it mandates — it is its own first conformance test. It grounds out in doc-ia-audit-2026-06-22.md, which catalogues the disorder this standard exists to end.

Principles it encodes: Krug (scannable, self-evident), Rosenfeld & Morville (findability through organization / labeling / navigation), Diátaxis (one mode per doc), inverted pyramid (answer first), and the Prime Directive (one owner per fact).


1. Diátaxis: one mode per doc

Every doc serves exactly one of four user needs. Mixing modes is the single biggest failure in BoB's current docs — the 1,455-line handbook is all four at once, so no reader's need is met cleanly. Pick one mode before you write; if a doc needs two, it is two docs.

ModeServesReader is…AnswersVoice
TutorialLearninga beginner, learning by doing"Teach me, start to finish""We will… now do this." Lessons, not options.
How-toA taska practitioner with a goal"How do I X?"Imperative steps. Assumes competence.
ReferenceLooking upsomeone who knows what they need"What exactly is X?"Dry, exhaustive, scannable. Tables over prose.
ExplanationUnderstandingsomeone building a mental model"Why is it this way?"Discursive. Trade-offs, history, rationale.

Choosing the mode

Ask what the reader is doing when they open the doc:

  • Studying with no specific goal yet → tutorial (docs/tutorials/).
  • Working, with a concrete task in hand → how-to (docs/how-to/).
  • Pausing mid-task to confirm a name, flag, field, or value → reference (docs/reference/).
  • Stepping back to understand why a thing exists → explanation (docs/explanation/).

Two tests resolve almost every case:

  1. The "during vs. between" test. Tutorials and how-tos are read while doing; reference and explanation are read between doing. If your steps and your rationale fight for space, split them.
  2. The completeness test. Reference must be complete and accurate (every flag); a how-to must be sufficient for the goal (only the flags that matter). A doc that can't decide how much to include is mixing the two.

Templates that already do this well: warp-drive.md's TL;DR-first lede (how-to done right) and verification-system.md's tight reference scoping. Reuse their shape.


2. Directory taxonomy & the root-docs rule

2.1 The docs/ taxonomy

Findability comes from organization + labeling (Rosenfeld & Morville). Every doc lives in exactly one category, and the category name is the Diátaxis mode — so a doc's location declares its contract. No more flat pile at the top of docs/.

DirectoryHoldsModeExamples (target home)
docs/tutorials/Learning paths, getting-started walkthroughstutorialQuick Start, first-project setup
docs/how-to/Task recipes — "how do I X?"how-todeploy, new-machine-setup, cdfork
docs/reference/Lookup material — contracts, glossaries, tables, this standardreferencehooks reference, CLI tables, frontmatter contract
docs/explanation/Architecture, rationale, the conceptual spineexplanationprime-directive, orchestration/ (handbook + orchestrator)
docs/audits/Dated point-in-time analyses (named *-YYYY-MM-DD.md)reference (frozen)doc-ia-audit-2026-06-22
docs/research/Exploratory notes, not-yet-normative findingsexplanation (draft)model-routing research
docs/archive/Retired docs & tombstones (see §5)superseded guides

Rules:

  • Every docs/*.md lives in a category subdirectory. A bare *.md at the top of docs/ is a placement violation (the one exception is a generated docs/index.md navigation root, if present).
  • The category must match the doc's type frontmatter. type: reference in docs/how-to/ is a contradiction the auditor flags.
  • Filenames are lowercase kebab-case (^[a-z0-9]+(-[a-z0-9]+)*$), extension .md for prose — already enforced by make check-doc-naming.
  • Audit/research artifacts are dated and frozen: they record a moment, are never edited after publication, and don't carry a rolling last_reviewed expectation.

2.2 The root-docs rule

The repository root is not a documentation directory. Stray root docs (plan.md, bob-identity.md) are how BoB's IA rotted. The root *.md allowlist is closed:

FileAllowed at root?Rationale
README.md✅ RequiredRepository entry point; GitHub renders it.
CLAUDE.md✅ RequiredClaude Code reads it at the root by contract.
CHANGELOG.md✅ AllowedRelease tooling convention; tools expect it at root.
LICENSE / LICENSE.md✅ AllowedLegal convention; GitHub detects it at root.
CONTRIBUTING.md✅ AllowedGitHub surfaces it from the root in PR/issue flows.
Anything elseMove into docs/<category>/No exceptions; relocate and leave a tombstone if linked.

Why these five are exempt: each is read at the root by a tool or platform contract (GitHub, Claude Code, release automation), not by human browsing. A doc a person would seek belongs in the taxonomy. R3 enforces this allowlist in CI.


3. The frontmatter contract

Every doc under docs/ (excluding frozen audits/ and archive/ tombstones) MUST open with a YAML frontmatter block. This is the metadata the freshness, ownership, and mode-purity checks read — no frontmatter, no governance.

yaml
---
type: reference          # required — one of: tutorial | how-to | reference | explanation
owner: paulirv           # required — GitHub handle accountable for accuracy
last_reviewed: 2026-06-22 # required — ISO 8601 (YYYY-MM-DD) date last verified true
expires: 2026-12-22      # optional — ISO date after which the doc is presumed stale
---
FieldRequiredTypeContract
typeYesenumExactly one Diátaxis mode. Must match the directory (§2.1).
ownerYesstringA GitHub handle (not a team, not "team") — one accountable human.
last_reviewedYesISO dateYYYY-MM-DD. Bumped only when the content is re-verified, never as a side effect of an unrelated edit.
expiresNoISO dateIf set and past, the auditor flags the doc stale regardless of last_reviewed. Use for docs with a known shelf life (migration guides, dated plans).

Rules:

  • type is the single source of a doc's mode. The H1 title, the directory, and type must agree; disagreement is an auditor finding.
  • last_reviewed means "a human confirmed this is true on this date." Sourced via timelord, never from memory. A mechanical edit (fixing a count, repairing a link) does not reset it — only re-reading for accuracy does.
  • owner is one accountable handle. "One owner per fact" (§4) starts here: every doc has exactly one person who answers for it.
  • Frozen artifacts are exempt. docs/audits/* and docs/archive/* tombstones record a moment and don't carry a rolling review expectation; they may omit frontmatter or carry a type: reference with the publication date.

4. Writing principles

Mode and metadata get a doc filed; these principles get it read. They apply to every mode, though the emphasis shifts (reference leans hardest on scannability; explanation on the inverted pyramid's "why").

Scope: this section owns documentation prose. For prose rules that span all authored artifacts — commit messages, PR/issue bodies, comments — see the Writing Styleguide, which references these principles rather than restating them.

4.1 Inverted pyramid — answer first

Lead with the conclusion, then the detail, then the background. A reader who stops after the first paragraph should still have the answer. This is why every BoB doc opens with a TL;DR blockquote (see this doc's lede, and warp-drive.md's).

  • First screen carries the payload. Put the "what is this / what do I do" above the fold; push history, edge cases, and rationale down.
  • Never bury the lede in setup. A how-to that spends two screens on context before the first command has the pyramid upside-down.

4.2 Scannability — readers skim, they don't read

Krug's law: people scan for what they need and ignore the rest. Write for the scan.

  • Descriptive headings that say what the section answers — a reader navigating by heading alone should find their answer. Avoid cute or generic headings ("Overview").
  • Tables over prose for any enumerable set (flags, fields, modes, options). If you're writing "X does A, Y does B, Z does C," it's a table.
  • Short paragraphs (≤ 3–4 sentences) and bulleted lists for steps or sets.
  • Front-load the keyword. Start list items and table rows with the term being defined, not with filler ("You can use the --foo flag to…" → "--foo — …").
  • Bold the load-bearing phrase in a dense paragraph so the skim catches it.

4.3 Controlled vocabulary — one name per thing

Findability dies when the same concept has three names (Rosenfeld & Morville). BoB uses one canonical term per concept, everywhere:

  • One name per concept. BOB_SOURCE (not "the source repo" / "the git repo" interchangeably); "requirement" (not "ticket" / "story" / "task"); "warp-drive" (not "the loop" / "auto-dev"). Pick the canonical term; use it verbatim.
  • One casing/spelling per name. dev.json, cdprov, make check — as written, every time.
  • Define a term once, at its canonical home, and link to that definition rather than re-defining it inline (this is §4.4 applied to vocabulary).

4.4 Single source of truth — one owner per fact

The Prime Directive, applied to prose: every fact is maintained in exactly one doc; everywhere else links to it. Duplication guarantees drift — the audit found the architecture diagram copied in four places and no two component counts in the repo agreeing.

  • State each fact once, at its owning doc, then link. A count, a table, a diagram, a procedure lives in one place.
  • Link, don't paste. If you're tempted to copy a table "for convenience," link to it instead. Convenience copies are drift waiting to happen.
  • The owner is the doc whose type/topic the fact most belongs to. A make check target table belongs in the verification reference; everything else links there.
  • If two docs legitimately need the same fact, one owns it and the other transcludes or links — never two hand-maintained copies.

The R2 auditor's cross_cutting[] / duplication detector exists to enforce this mechanically. Until it ships, treat duplication as a review-blocking defect.

4.5 Issue/PR bodies — never use a bare #N as an item number

This applies to any text a command authors into a GitHub issue, PR, or comment body (not docs/ prose). GitHub autolinks every #<digits> in rendered markdown into a cross-reference to the issue/PR holding that number. In a mature repo those low numbers are unrelated closed issues, so a body that numbers its own items — "Critical #1", "High #6", "fix Medium #10" — sprouts a cluster of spurious, misleading links (the real cause of nanawallweb/nanawalld8#674; tracked here as #520).

  • Reserve #N for genuine issue/PR references only (Part of #42, fixes #51, the (#260) provenance tag).
  • For an intra-document item / finding / step number, use a non-linking form:C1 / H2 / M3 (severity+ordinal), "item 1", "finding 3", or backtick it — `#1`.
  • #N inside a fenced code block or backticks does not autolink and is safe (e.g. a terminal mockup listing real issue numbers).

Enforced by scripts/checks/check-issue-autolink.sh (wired into make check), which flags item-word + bare #N in the issue-authoring command templates and can lint a generated body file before gh issue create.


5. Deprecation & archival

Docs die. An orderly death — tombstone, archive, redirect — keeps the namespace clean and link graph intact; the current docs/ pile of six stray tombstones and orphaned artifacts is what disorderly death looks like. Never silently delete a doc that anything links to.

5.1 Decide the doc's fate

SituationAction
Content moved into another docTombstone in place (§5.2), then move the file to archive/ once links are repointed.
Doc is obsolete, nothing replaces it, but it has inbound links or historical valueArchive it (§5.3) with a tombstone redirect.
Doc is obsolete and orphaned (nothing links in, no historical value)Delete it — but only after confirming zero inbound links (link-graph check).
Doc is a dated artifact (audit, status report)Leave in audits/; it's frozen, not deprecated. Never edit; never archive.

5.2 Tombstones (redirects)

When content moves, replace the old file with a tombstone so existing links don't 404 and readers are forwarded. BoB's established tombstone shape (e.g. docs/pm-cheatsheet.md):

markdown
# <Old Title> — Moved

This document has been replaced by **[<New Title>](<relative-path-to-the-new-doc>)**.

<One line on why / what absorbed it.>
  • Keep the filename and path of the original — that's what inbound links target.
  • A tombstone is a redirect, not content. It carries no frontmatter contract and is exempt from freshness checks.
  • Tombstones live where the original lived until the next restructuring sweep, then move to archive/ (so the live namespace isn't cluttered — the audit's complaint about six tombstones in docs/).

5.3 The archive/ directory

docs/archive/ is the graveyard: retired docs and old tombstones that are kept for history but are out of the live IA.

  • Archived docs are frozen. Not edited, not reviewed, not counted in freshness or mode-purity checks.
  • Preserve the original basename so old links resolving through a tombstone still land.
  • Add a one-line banner at the top noting it's archived and what superseded it, if not already a tombstone.
  • The auditor treats archive/ and audits/ as excluded from active governance but included in the link graph (so a live doc linking into archive/ for anything other than history is flagged).

5.4 Redirect handling

  • Internal links: the tombstone is the redirect — its single link forwards the reader. Repoint inbound links to the new home opportunistically; the tombstone covers the gap until you do.
  • External / deep links (issues, external sites) can't be repointed, so the tombstone at the original path must persist — this is the reason tombstones are kept rather than deleted outright.
  • Generated nav/index (a future docs/index.md) is regenerated from the taxonomy, so it never points at a dead doc; archived docs simply drop out of it.

6. Enforcement & severity model

This standard is enforced by the doc-keeper auditor (scripts/doc-keeper/audit.js, run via make docs-check) and in CI (.github/workflows/ci.yml). Each finding carries a severity; whether it blocks (fails CI) or warns (reported, non- blocking) is set here — a single source of truth the tooling reads.

6.1 What blocks vs. warns

FindingCategoryBlocks CI?
Broken relative linkbroken-linkBlocks (severity high)
Short-form priority label (p1 vs p1-critical)label-nameBlocks (severity high)
Orphan doc (nothing links to it)orphanBlocks — via ratchet (§6.2)
Root *.md outside the allowlistroot-placementBlocks — via ratchet (§6.2)
Missing / stale required frontmatterfreshnessBlocks — via ratchet (§6.2)
Filename not lowercase-kebabfilename-violationBlocks (make check-doc-naming, now in CI)
Single-source-of-truth duplicationduplicationWarns
Diátaxis mode-mixingmode-mixingWarns
Component / registry count driftcomponent-count etc.Warns (mechanically fixable via make docs-sync)

Blocking means make docs-check exits non-zero, failing the build. Warning findings still appear in the audit report and feed the curation worklist, but never fail CI — they require human judgement (which copy is canonical, how to split a doc) that a gate can't make.

6.2 The baseline ratchet

The three governance categories (orphan, root-placement, freshness) block new violations but grandfather the existing ones, via a version-controlled baseline at scripts/doc-keeper/audit-baseline.json. This is what lets the gate go live on a repo that predates the standard without a flag-day cleanup:

  • make docs-check runs the auditor with --fail-on-categories orphan,root-placement,freshness --baseline scripts/doc-keeper/audit-baseline.json. A finding fails CI only if its signature is not already in the baseline — so a PR that adds a new orphan or a stray root doc is blocked, while the pre-existing debt is tolerated.
  • The baseline is accepted documentation debt, and the only correct direction is down. Remediation work (restructuring, archival, adding frontmatter) shrinks it; regenerate with audit.js --write-baseline scripts/doc-keeper/audit-baseline.json --fail-on-categories orphan,root-placement,freshness after a cleanup. When it reaches [], the gate is fully hot with zero suppression.
  • Never grow the baseline to silence a new finding — that defeats the ratchet. New violations are fixed, not baselined.