ADR-127: Docs as typed playbooks
Status: Proposed Date: 2026-05-04
Related: ADR-067 (playbooks-unified-primitive), ADR-117 (module-guidelines), ADR-116 (gyrum-knowledge-base-rag-service), ADR-126 (durable-engineering-content-in-git), ADR-128 [planned] (cross-reference graph), ADR-129 [planned] (themes + retros + verification + feature-doc synthesis), ADR-130 [planned] (multi-axis tag taxonomy)
Context
Durable engineering content lives in git (ADR-126). The substrate is settled. The shape of the content within that substrate is not.
Today, ADRs live in dark-factory/docs/decisions/, runbooks in dark-factory/docs/runbooks/, feature-docs in dark-factory/docs/features/, retros as session-log addenda, postmortems wherever the operator wrote them. Each kind is a markdown file with informal frontmatter. Some ADRs declare Status: and Date:; some do not. Some runbooks open with a context paragraph; some jump straight to commands. Cross-references are prose links that may or may not resolve. Superseded ADRs may or may not carry Superseded by:. Stale runbooks read as authoritative because nothing flags them.
The fleet's runtime work has the opposite shape. Playbooks (ADR-067) declare inputs, outputs, validators, scaffolders. gyrum-validate-playbook rejects malformed YAML. gyrum-create-playbook <kind> scaffolds the right shape so authors never start from a blank file. Module guidelines (ADR-117) apply the same primitive to per-module rules: declared schema, structural checks, scaffolders, versioned files. The RAG layer (ADR-116) indexes typed corpora because typed corpora are mechanically queryable.
Docs are the last unstructured durable artefact in the system. Authors start from a blank file or a copy-paste of a recent example. Maintainers grep for citations because no graph exists. Synthesis from merged work into a feature-doc is hand labour because the upstream signals (verification evidence, retros, theme membership) have no shape that a synthesizer can read.
The principle this ADR names is the precondition for every later phase of the docs-as-playbooks EPIC (warp#1197): r1 scaffolder, r2 validator, r3 lifecycle hooks, r4 RAG indexing, r5 feature-doc synthesis.
Decision
Docs are typed artefacts. Each kind has a declared schema, a scaffolder, a validator, lifecycle hooks, and a place in the RAG index. Cross-references are tracked. Freshness is observable.
The doc kinds in scope:
| Kind | Path | Purpose |
|---|---|---|
adr |
<repo>/docs/decisions/NNN-<slug>.md |
A decision, its context, its consequences, alternatives considered |
runbook |
<repo>/docs/runbooks/<slug>.md |
A procedure for an operator or agent to execute |
feature-doc |
<repo>/docs/features/<slug>.md |
The narrative of a shipped feature, synthesized from upstream signals |
retro |
<repo>/docs/retros/<slug>.md |
A structured retrospective on a shipped piece of work |
postmortem |
<repo>/docs/postmortems/<slug>.md |
A structured post-incident analysis |
playbook-spec |
<repo>/docs/proposals/<slug>.md |
A specification for a new playbook before it is implemented |
Each kind carries declared frontmatter:
kind(one of the six above)status(draft,active,superseded,archived)date(creation date)owner(operator or team)
tags(multi-axis taxonomy per ADR-130 [planned])freshness_window(e.g.90d,1y,permanent) describing the half-life of the contentsupersedes(list of doc ids this one replaces)supersede_by(the doc id that replaces this one, set when status flips tosuperseded)refs(canonical inbound and outbound references for the cross-reference graph)
The five enforcement layers, mirroring the playbook primitive (ADR-067) and the module guideline shape (ADR-117):
- Schema per kind (one schema file per kind, versioned, lives in devtools).
- Scaffolder (
gyrum-create-doc <kind> <slug>) that emits the right shape so authors never start from a blank file. - Validator (
gyrum-validate-doc) that runs ingyrum-review-pron PRs touchingdocs/decisions/**,docs/runbooks/**,docs/features/**. It rejects missing frontmatter, broken cross-references, em-dashes, AI-tells, freshness violations, and status invariants (asupersededdoc must carrysupersede_by; anactivedoc must not). - Lifecycle hooks (
gyrum-supersede-doc,gyrum-archive-doc,gyrum-doc-freshness) that write back-links atomically, audit archival moves, and file Warp tickets for docs past their freshness window. - RAG index (ADR-116) that consumes the typed corpus, computes inbound citation counts, and surfaces orphan docs, over-cited canonical docs, and stale docs on a fleet dashboard.
Synthesis (r5 of the EPIC) cashes in this structure: a feature-doc draft is composed from typed upstream signals (verification evidence per warp#1156, retros per warp#1133, ADRs and runbooks tagged with the theme) rather than hand-aggregated from chat memory.
Consequences
What becomes easier
- An author or agent never starts a new doc from a blank file. The scaffolder picks the next ADR number, populates the frontmatter, and opens the editor at the first content section.
- The validator catches missing frontmatter, broken cross-references, em-dashes, and AI-tells at PR time. Drift fails the gate; it does not ship.
- A superseded ADR carries a mechanical link to its replacement. Readers landing on a stale ADR are routed to the current one without grep.
- Stale runbooks file Warp tickets when their freshness window expires. The signal is queueable, not silent.
- The RAG index surfaces orphan docs (zero inbound cites, candidate for archive) and over-cited docs (top 20, signal of canonical status). Curation becomes mechanical.
- Feature-doc synthesis becomes possible because the upstream signals (retros, verification evidence, theme tags) are themselves typed artefacts. The narrative is composed from structure, not from chat memory.
What becomes harder
- Authoring a new doc requires picking a kind (a small cognitive cost compared to a blank file).
- The validator may reject docs during the in-flight migration period. An audit-tracked override flag (
--skip-doc-validation "<reason>") covers the migration window; the override lands in~/.gyrum/admin-overrides.logper thefeedback_admin_override_with_auditrule (admin override only when size is the sole blocker, audit log names why the unit cannot split). - Schema evolution requires a process. Frontmatter changes need a migration step that walks existing docs and rewrites them, or a versioned-schema scheme akin to the module-guideline
@v<n>shape. - Synthesis (r5) depends on structured upstream signals being shipped first. Verification evidence (warp#1156) and retros (warp#1133) are prerequisites; r5 is blocked on both.
What we sign up to operate
- Six per-kind schemas with versioning rules akin to module guidelines (ADR-117).
- A validator wired into
gyrum-review-prwith an audit-tracked override flag. - A scaffolder, three lifecycle CLIs, and a freshness cron.
- An incremental RAG indexer that re-indexes on PR merge with a target staleness of one hour (ADR-116).
- A migration period during which the validator runs in advisory mode (warns but does not block), then ratchets to enforce after one release cycle.
Alternatives considered
Keep docs free-form, rely on review judgement to catch drift. This is the status quo. The failure mode is observable: stale runbooks read as authoritative, superseded ADRs lose their replacement link, feature-docs are hand-written one-offs decoupled from the structured trail. Review judgement scales with attention; structure scales with mechanism. Ruled out as the steady state, even though it is the migration starting point.
Structure only ADRs, leave runbooks and feature-docs free-form. ADRs are the most cited kind, so this captures most of the cross-reference benefit. It does not capture the freshness benefit (runbooks are the kind that goes stale) or the synthesis benefit (feature-docs are the kind that benefits most from typed upstream signals). Ruled out as a partial fix that leaves the load-bearing kinds unstructured.
A separate "docs CMS" service outside git. Adds a third substrate to maintain. Breaks the ADR-126 principle that durable content lives in git. Doesn't compose with
gyrum-review-pr, doesn't show up in branch diffs, doesn't follow the operator across machines. Ruled out: more substrates do not equal better.Inline the schema in each doc body (e.g. a leading YAML block per section). Verbose, redundant per doc, and hard to evolve. The frontmatter-plus-validator shape is the same one the playbook primitive (ADR-067) and module guidelines (ADR-117) settled on; doing something different here would fragment the fleet's authoring shape. Ruled out by consistency.
Migration
The principle lands in this ADR. The implementation lands in five subsequent phases of warp#1197:
- r0 (this ADR). Names the principle. Subsequent phases cite it.
- r1 scaffolder.
gyrum-create-doc <kind> <slug>, mirroringgyrum-create-playbook. Six per-kind templates. - r2 validator.
gyrum-validate-doc, wired intogyrum-review-pr. Initially advisory; ratchets to enforce after one release cycle. Audit-tracked--skip-doc-validationoverride for the migration window. - r3 lifecycle hooks.
gyrum-supersede-doc,gyrum-archive-doc,gyrum-doc-freshness. - r4 RAG indexing. Cross-reference graph, inbound citation count, fleet dashboard surfaces (orphan, over-cited, stale, supersession).
- r5 feature-doc synthesis.
gyrum-synthesize-feature-doc <theme-slug>consumes typed upstream signals and emits a draft for operator review.
Phases r0 through r3 unblock everyday doc authoring. Phases r4 and r5 cash in the structure for synthesis and curation.
Supersedes: none Superseded by: