
Doc Diagnostic
- 55 installs
- 50 repo stars
- Updated June 18, 2026
- josiahsiegel/claude-plugin-marketplace
Diagnose documentation issues and route to appropriate documentation forms.
About
Documentation diagnostic plugin that analyzes existing docs and recommends proper structure. Covers Markdown style, ADR routing, and formatting standards.
- Documentation quality analysis
- Markdown style and routing guidance
Doc Diagnostic by the numbers
- 55 all-time installs (skills.sh)
- +4 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #789 of 1,879 Documentation skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill doc-diagnosticAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 55 |
|---|---|
| repo stars | ★ 50 |
| Last updated | June 18, 2026 |
| Repository | josiahsiegel/claude-plugin-marketplace ↗ |
What it does
Diagnose documentation issues and route to appropriate documentation forms.
Files
doc-diagnostic
The diagnostic and canon skill. Owns three things:
1. The alternatives catalog -- what to write when a user impulse should not be an ADR. Full catalog: references/alternatives-catalog.md. 2. The ADR canon -- templates, status lifecycle, numbering, required fields, immutability rules. (In this file.) 3. The audit procedure -- folder-level KEEP / MERGE / REWRITE / DELETE / MOVE / BACKFILL-ADR classification used by /doc-audit. Full procedure: references/audit-procedure.md.
Use this skill when routing a doc request, picking a template, naming a status, or auditing an existing doc set. The drafting / discovery / critique skills consume the canon defined here; they do not redefine it.
The four-question diagnostic (run before recommending any doc)
The canonical four-question check. The doc-expert agent and every other skill in this plugin reference this section rather than restate it. Before agreeing to produce any document, run all four. If any answer is "no" or "unclear," the doc should not be written yet.
1. Purpose -- one sentence stating what question this doc answers for a reader who already knows the system exists. 2. Audience -- a specific reader in a specific situation. ("Future maintainers" is not an audience; "an on-call engineer at 03:00 with a P1" is.) 3. Owner -- a named human accountable for keeping it true. No owner → drift within months. 4. Update trigger -- a concrete event that causes the doc to be revisited or superseded. No trigger → fossil-in-waiting.
If all four are answerable, proceed to the "is this an ADR?" diagnostic in the doc-expert agent body.
Architecturally Significant Requirement (ASR) -- canonical definition
An ADR captures a single architectural decision and its rationale. An architectural decision addresses a requirement that is architecturally significant -- an ASR with "a measurable effect on the architecture and quality of a software and/or hardware system." If the change is not architecturally significant, an ADR is the wrong tool -- route via the alternatives catalog.
Beyond architecture -- "decision records" more broadly
The same form generalizes to product, business, policy, security-program, and process decisions -- anywhere a justified, hard-to-reverse choice deserves a rationale that outlives its authors. Convention: rename docs/adr/ to docs/decisions/ and relax the ASR test to "is this decision worth recording at all?" Templates, lifecycle, numbering, immutability, and Relationships-mirror rules hold unchanged. Umbrella: github.com/joelparkerhenderson/architecture-decision-record; see also references/adr-template-catalog.md.
The alternatives catalog (when NOT to write an ADR)
When the diagnostic says "not an ADR," route via references/alternatives-catalog.md -- it maps every common impulse to the correct doc form, explains why an ADR would be wrong, and names the Diátaxis four (tutorial / how-to / reference / explanation). ADRs are not Diátaxis explanations. Load it whenever the user debates "ADR vs RFC vs design doc vs runbook vs how-to" or asks "where should I document X?"
ADR canon
Template selection
Pick the smallest template that captures the decision honestly:
| Template | Use when... | Don't use when... |
|---|---|---|
| Nygard / MADR light | Decision is simple, alternatives obvious, three to five fields suffice (Context, Decision, Consequences). | You need to compare 3+ alternatives on multiple criteria. |
| MADR (full) | Multiple options need side-by-side analysis; decision drivers matter; Confirmation/Validation field needed; traceability matters. | The decision is trivial -- full MADR pads it. |
| Y-statement | One sentence: "In the context of X, facing Y, we decided Z, to achieve W, accepting that V." Good for compact log entries or executive summaries. | The decision needs structured fields. |
| arc42 / Tyree-Akerman / Business case | The project already uses one. | Starting fresh -- heavier than most teams need. |
Pick once per project; do not mix templates within a single log unless explicitly migrating.
Canonical status lifecycle
proposed ----accepted----> accepted ----changed----> superseded
|
+--no-longer-applies--> deprecatedExplorer-compatible status values are lowercase proposed, accepted, deprecated, superseded. Do not overload status with rfc, rejected, backfilled, or explanatory strings.
- proposed -- under discussion, including ADRs serving as RFCs (add
rfc-deadline, do not inventstatus: rfc). - accepted -- in force.
- superseded -- replaced by a later ADR; the new ADR's
supersedeslist creates the edge. - deprecated -- no longer applies but no new decision replaces it, or a proposal rejected but kept for its "why not." Explain in body, not
status.
Immutability and supersession
The cardinal rule: "Don't alter existing information in an ADR." Amend or supersede.
- Once Accepted, the body is append-only: typo fixes, a
superseded bynote, dated entries under an "Amendments" heading. - A changed decision is a new ADR naming the old one in
supersedes. The old ADR may get asuperseded by: NNNNreader note but otherwise stays untouched. The new ADR'ssupersedeslist is the edge;superseded-bybody prose is not. - Teams preferring "living document" with dated inline amendments must state it up front in the log's
README.md.
Numbering, naming, ownership
- Numbering: monotonically increasing, zero-padded (
0001,0002, ...). Never reuse. The number IS the identity. - Filename: zero-padded id + present-tense imperative phrase, lowercase, hyphenated,
.md(0007-use-postgres-for-primary-store.md). - Ownership:
decidersas a YAML array (accountable); optionallyconsulted/informed(MADR RACI). "The team" is not an owner. - Date: ISO 8601. Stamp at acceptance, not first draft.
- Review cadence: a concrete trigger on the ADR ("Revisit when we exceed 10k QPS"), not "revisit annually."
Required fields
Every ADR contains:
1. Title -- NNNN. Decision (imperative verb phrase). 2. YAML frontmatter -- mandatory. A --- block with at minimum title, status, date, deciders. Add supersedes / amends / relates-to when relationships exist. Optional: tags, review-by, expires, confidence: high|medium|low, confidence-score, rfc-deadline (when status: proposed acts as an RFC). Gray-matter parsers read only the frontmatter; missing it orphans the node. 3. Body Relationships mirror -- mandatory whenever frontmatter relationships exist. MADR 4.0.0 ## More Information → ### Relationships, link-prefix vocabulary (Supersedes, Superseded by, Amends, Amended by, Related to). Body-scanning parsers read only this section; the two surfaces must agree. 4. Context -- the architecturally significant forces; a stranger three years later understands why this had to be decided now. 5. Decision -- the choice, present tense, standing alone. 6. Decision drivers (MADR) or implicit in Context (Nygard). 7. Alternatives considered -- realistic ones at the same level of abstraction, each with a one-paragraph "why not." Skip pseudo-alternatives. 8. Consequences -- Good, because... and Bad, because... plus follow-up work. 9. Confirmation / Validation (MADR full) -- how compliance is enforced. 10. Re-evaluation triggers -- concrete conditions that should cause a new ADR to supersede this one.
Storage and discoverability
- Keep ADRs in the source repository, in source control, alongside the code they govern.
- Explorer-friendly locations:
docs/adr/,docs/decisions/,docs/architecture/decisions/,**/adr/*.md. Pick one; document it in the log'sREADME.md. - Provide an index in that
README.mdlisting every ADR with status and a one-line summary. The index is navigation, not the graph; index-hub links are not edge signals. - Default to MADR 4.0.0 + frontmatter + body Relationships mirror. Frontmatter
supersedes/amends/relates-tofeed gray-matter parsers; body### Relationshipsfeeds body-scanning parsers; either alone half-renders. If the project already uses Nygard, Y-statement, arc42, or Tyree-Akerman, follow it. MADR: adr.github.io/madr/, source github.com/adr/madr. - Body lines like
Related ADRs:outside### Relationships, orRelated docs:in### Notes, are courtesy navigation -- not edges. - ID format in frontmatter lists: zero-padded four-digit strings (
"0008"). Explorer parsers extract digits with/(\d+)/and zero-pad, so8,"08","0008","ADR-0008"resolve identically -- but zero-padded strings render and sort predictably. - Cross-link from code when feasible (
// See docs/adr/0007-use-postgres-for-primary-store.md). - State the governance rule for relationship-link maintenance: if Accepted ADRs are immutable, either allow metadata-only relationship-list edits + body Relationships additions, or require a named exception.
- Offline canon check:
plugins/doc-master/scripts/validate_adrs.py. Seeplugins/doc-master/scripts/README.mdfor the full per-file check list and CLI flags. Use during/doc-auditor as a CI gate, not as a substitute for the four-question check.
Canonical mirror example
---
title: "Use Postgres for primary store"
status: accepted
date: 2026-05-20
deciders: [Jane Doe]
supersedes: ["0004"]
relates-to:
- id: "0011"
reason: "shares the tenancy model decided in 0011"
---
# 0017. Use Postgres for primary store
## More Information
### Relationships
- Supersedes [ADR-0004](0004-use-dynamodb-for-primary-store.md) -- replaced because Q3 reporting needs sub-200ms joins.
- Related to [ADR-0011](0011-tenancy.md) -- shares the tenancy model decided in 0011.Both surfaces must agree. Stray Related ADRs: lines in ### Notes, index-hub entries, or superseded-by body notes are courtesy navigation, not edges.
Repo-level cornerstones around the decision log
A decision log sits inside a broader set of community-health files: README, LICENSE, CONTRIBUTING, CODE_OF_CONDUCT (opensource.guide four-file canon), plus the extended GitHub profile (SECURITY, SUPPORT, CODEOWNERS, FUNDING, CITATION, .github/ templates). doc-master does not auto-create any of these; the four-question diagnostic still applies. Full canon in the repo-health skill -- load it when the user sets up community-health files, audits repo bootstrap docs, or picks a license / code-of-conduct / contribution guide.
ADR failure modes
The eleven canonical failure modes (drift, ADR-PRD duplication, bundled decisions, premature ADR, template thrash, decision-by-AI-without-buy-in, and the rest) with symptoms and remedies: references/failure-modes.md. Load during audits and adr-critique.
Folder-level audit procedure (used by /doc-audit)
Follow the eight-step procedure in references/audit-procedure.md: Inventory → ADR-canon test → four-question test → drift → duplication → misclassification → backfill-candidate detection (ASR test against shipped-change evidence) → numbered KEEP / MERGE / REWRITE / DELETE / MOVE / BACKFILL-ADR action list.
BACKFILL-ADR is a candidate, not a draft -- the audit surfaces it; the architect decides whether to load adr-backfill. Evidence must appear in two independent locations; reconstruction-confidence: low routes to open-questions.md. The procedure file pins the hard constraints (no body edits on Accepted ADRs, no bulk renumbering, no auto-generated Owners, no deletion without sign-off) and the post-approval flow.
Anti-padding rule
Every doc recommended must answer all four diagnostic questions (Purpose, Audience, Owner, Update trigger). If one is unanswerable, the doc should not exist yet. This applies to ADRs, RFCs, how-tos, references, explanations, tutorials, runbooks, READMEs, and CONTRIBUTING alike. Documentation is a cost as well as a benefit -- the right number is the smallest number that keeps the system understandable, operable, and decisive.
References
references/alternatives-catalog.md-- Diátaxis / RFC / runbook routingreferences/failure-modes.md-- eleven ADR failure modes with remediesreferences/audit-procedure.md-- folder-level audit procedure with hard constraintsreferences/changelog-canon.md-- Keep a Changelog 1.1 + SemVer 2.0.0references/runbook-canon.md-- runbook structure for paged incidents (not how-to)references/postmortem-canon.md-- blameless postmortem (PagerDuty + Google SRE)references/open-questions-canon.md-- standalone open-questions registerreferences/agentic-docs-canon.md--AGENTS.mdconvention for AI-agent contextreferences/adr-template-catalog.md-- template index (Nygard / MADR short / MADR long / Y-statement / Tyree-Akerman / arc42 §9)../_shared/adr-is-not.md-- canonical "ADR is NOT" checklistadr-discovery,adr-drafting,adr-critiqueskillsc4-modelskill -- canonical-C4 LikeC4 diagramsrepo-healthskill -- community-health files (README / LICENSE / CONTRIBUTING / CODE_OF_CONDUCT / SECURITY / SUPPORT / templates / REUSE-SPDX)
ADR template catalog — the canonical index
The master index of ADR template forms doc-master knows and can route between. Load this when the user asks "which ADR template should I use?", "what's a Y-statement?", "Nygard vs MADR vs Y-statement vs arc42 vs Tyree-Akerman", or "is there a one-paragraph ADR form?"
The authoritative catalog of community-curated ADR templates lives at [adr.github.io](https://adr.github.io/) — when in doubt about a template not listed here, route there first.
The forms doc-master knows
| Template | Shape | Best fit |
|---|---|---|
| Nygard (short) | Title / Status / Context / Decision / Consequences. | Simple decisions, obvious alternatives, lightweight team. The original 2011 form. |
| MADR (4.0.0) short | Context and Problem Statement / Decision / Consequences. | A modern minimalist baseline; structured but small. Upstream: adr.github.io/madr/. |
| MADR (4.0.0) long | Adds Decision Drivers, Considered Options, Decision Outcome (with positive/negative consequences), Compliance, More Information. | Decisions with 3+ realistic alternatives and traceability requirements. |
| Y-statement (Zimmermann) | Single-paragraph form (see below). | Compact log entries, executive summaries atop a longer ADR, RFC pitch lines, decision dashboards. |
| Tyree-Akerman | Heavier form with Group, Assumptions, Positions, Argument, Implications, Related Decisions, Related Requirements, Notes. | Enterprise contexts that already use this form; consistency outweighs minimalism. |
| arc42 §9 | The "Architecture Decisions" section of the arc42 template. | Projects already using arc42 for the overall architecture documentation. |
doc-master's default is MADR (currently 4.0.0) with YAML frontmatter and a body Relationships mirror; see ../SKILL.md "Storage and discoverability" and ../../adr-drafting/references/template-fields.md for the full canonical fields.
Y-statement template (inline)
A Y-statement compresses an ADR into a single paragraph. The form is fixed:
In the context of<use case / functional requirement>, facing<concern / non-functional requirement>, we decided for<chosen option>and neglected<other options>, to achieve<quality goal / criteria>, accepting<downside / consequence>, because<additional rationale>.
Each slot is mandatory. A Y-statement missing any slot is a marketing sentence, not a decision record.
Example:
In the context of the customer-facing API, facing sub-200ms p95 latency requirements, we decided for Postgres with read replicas and neglected DynamoDB, to achieve sub-150ms reporting-query latency with multi-table joins, accepting the operational overhead of self-managing replication, because the reporting workload requires SQL joins and the team has stronger Postgres operational experience than DynamoDB experience.
Y-statements are excellent as:
- The opening summary atop a longer ADR (give readers the gist before they commit to the full doc).
- Index-row summaries in the decision log's
README.md. - Executive-summary versions of an existing ADR for stakeholders.
- RFC pitch lines that compress the proposal into a single sentence.
They are insufficient when:
- The decision genuinely needs side-by-side comparison of multiple alternatives on multiple criteria.
- The Consequences need bullet lists with Good-because / Bad-because framing.
- Traceability requires structured fields (decision drivers, confirmation, re-evaluation triggers).
Source: Olaf Zimmermann's original Y-statement post on Medium, medium.com/olzzio/y-statements-10eb07b5a177. Route via adr.github.io for the up-to-date catalog entry.
Selection rules
1. If the project already uses a template — use it. Consistency outweighs minimalism. Switching templates mid-log is template thrash (a named failure mode); do not propose it lightly. 2. If the project is starting fresh — default to MADR 4.0. It has the best balance of structure, parser support, and community tooling. 3. If the team is small and the decision is simple — Nygard or MADR short. Do not pad three-field decisions with empty MADR-long sections. 4. If you need a one-paragraph summary — Y-statement atop a longer ADR. The longer ADR remains the canonical record. 5. If the project already uses arc42 or Tyree-Akerman — keep it. Translating into MADR for cosmetic reasons is template thrash.
When NOT to use any of these — beyond architecture
If the user is recording non-architectural decisions (product decisions, business decisions, policy decisions) and finds the "architectural" framing constraining: the broader pattern is just decision records, and the directory is conventionally renamed to decisions/. See ../SKILL.md "Storage and discoverability" — the Joel Parker Henderson reference repo at github.com/joelparkerhenderson/architecture-decision-record catalogs the broader pattern.
The shape is the same; only the ASR test loosens. The four-question diagnostic still applies.
AGENTS.md canon — AI-agent context file
The canonical reference for AGENTS.md. Load this when the user asks "where do I tell our AI agents about this repo?", "should I write an ADR for 'we use Claude Code'?", "we have CLAUDE.md and .cursorrules — what should we use instead?", or "what's the convention for agent instructions?"
AGENTS.md is a vendor-neutral, agent-readable file that describes a codebase to AI coding assistants: conventions, build commands, test commands, code style, deployment notes — anything an agent needs to operate effectively in the repo. It is the converged community answer to the proliferation of vendor-specific files (CLAUDE.md, .cursorrules, .github/copilot-instructions.md, .continuerc, and the rest).
Upstream: agents.md. The convention is now stewarded by the Agentic AI Foundation as a vendor-neutral spec.
The closest-AGENTS.md-wins rule
For monorepos and nested projects:
- The agent reads the nearest
AGENTS.mdwalking upward from the working directory. - Sub-project
AGENTS.mdfiles override parent files for their own scope, on a per-section basis where the agent supports it. - Repo root
AGENTS.mdprovides the defaults; subdirectory files refine them for their specific package / service / language.
This means a monorepo with packages/frontend/AGENTS.md and packages/backend/AGENTS.md can give the agent fundamentally different instructions per package (npm vs gradle, prettier vs spotless, etc.) without conflict.
Migration from vendor-specific files
If the repo currently has vendor-specific agent-context files, migrate them:
| Old file | Vendor | Migration |
|---|---|---|
CLAUDE.md / .claude/CLAUDE.md | Claude Code | Move content into AGENTS.md; symlink CLAUDE.md → AGENTS.md. |
.cursorrules / .cursor/rules | Cursor | Move content into AGENTS.md; symlink old path → AGENTS.md. |
.github/copilot-instructions.md | GitHub Copilot | Move content into AGENTS.md; symlink the old path. |
.continuerc / .continue/ | Continue | Move applicable instructions into AGENTS.md. |
.aiderrc / .aider/ | Aider | Same pattern. |
Symlinks during migration are the safe path. They preserve compatibility with tools that look for the vendor-specific name while making AGENTS.md authoritative. On Windows, where symlinks need elevated permissions or developer mode, the alternative is a tiny pointer file (e.g., a CLAUDE.md containing only "See AGENTS.md.") with the same effect.
What goes in AGENTS.md
A typical AGENTS.md covers:
- Build, test, and lint commands — the exact commands the agent should run, with no guessing.
- Code style — language version, linter / formatter config, naming conventions that the linter does not cover.
- Repository layout — where source, tests, docs, configs live.
- Dependency rules — what is allowed, what requires an ADR, vendor-pinning policy.
- Branching / PR conventions — branch naming, commit message style (Conventional Commits etc.), required reviewers.
- Forbidden actions — what the agent must not do (force-push, edit specific protected files, commit secrets, bypass CI).
- Pointers to other docs — ADR directory, runbook directory, security policy, contribution guide.
It does not typically duplicate ADRs, runbooks, or the README — it points to them.
"Should I write an ADR for 'we use Claude Code'?" — no
Picking an AI coding assistant is not an architectural decision in the ASR sense:
- It is reversible — switch to a different agent tomorrow.
- It has no measurable effect on system architecture or quality.
- It does not constrain future architectural choices.
The choice of agent is a tooling preference, like the choice of editor or terminal. It belongs in AGENTS.md (the configuration / instruction file the agent reads) or in CONTRIBUTING.md (if there are project-wide expectations about how agents are used). It does not belong in the decision log.
What may be an ADR-worthy decision in the same neighborhood:
- "All AI-generated code requires human-named reviewer sign-off before merge" — governance, often architecturally significant.
- "We forbid AI agents from modifying files under
/security/" — constraint with measurable effect on review surface and compliance. - "We license-screen all AI-suggested dependencies through workflow X" — a process commitment with measurable impact.
These produce an ADR because the policy has architectural and compliance implications. The choice of which agent is configuration.
Common failure modes
| Failure | Symptom | Remedy |
|---|---|---|
| Three competing agent-config files | CLAUDE.md + .cursorrules + AGENTS.md with overlapping, drifting content. | One source of truth (AGENTS.md); symlink the rest. Audit drift quarterly. |
AGENTS.md duplicates the README | Both files re-state the same build commands; they drift. | AGENTS.md links to the README for what the README covers; only adds agent-only notes. |
| ADR for "we use agent X" | The decision log carries a tool-choice entry that has no architectural force. | Move the content to AGENTS.md. Mark the ADR Rejected with a note. |
Secrets in AGENTS.md | API keys, internal URLs, credentials embedded as "examples." | Never. Reference the secret-management approach; never the secret. |
AGENTS.md as a manifesto | Pages of philosophy about AI; no actionable instructions. | Strip to imperatives. The agent reads this file to operate, not to read essays. |
Routing — when this is not the answer
- A decision about how the team uses agents with architectural / compliance impact → ADR.
- A decision about which agent to use →
AGENTS.md(tooling preference, not a decision). - A general "what conventions does this repo follow" doc for humans →
CONTRIBUTING.md.AGENTS.mdmay link to it. - Per-language style → linter / formatter config.
AGENTS.mdpoints at the config; it does not restate it. - Forbidden-actions policy with legal / security weight → may be both an
AGENTS.mdentry and aSECURITY.mdsection, depending on audience.
Alternatives catalog — when NOT to write an ADR
When the four-question diagnostic and the ASR check say "not an ADR," route the user to the right home. Each row below maps a common user impulse to its correct documentation form and the reason an ADR would be wrong.
This catalog is the routing reference for doc-diagnostic. Load it whenever the user is debating "ADR vs RFC vs design doc vs runbook vs how-to" or asks "where should I document X?"
The catalog
| User says... | Right home | Why not an ADR |
|---|---|---|
| "Document our coding style." | CONTRIBUTING.md or a linter config | Coding conventions are enforceable; ADRs are not enforcement |
| "Explain how the auth flow works." | Diátaxis explanation (docs/explanation/auth.md) | This is understanding, not a decision |
| "Show how to deploy to staging." | Diátaxis how-to (docs/how-to/deploy-staging.md) | This is a task; ADRs don't direct action |
| "List all the env vars / API endpoints / config keys." | Diátaxis reference | Reference is descriptive, austere, product-led; an ADR is argumentative |
| "Onboard a new engineer." | Diátaxis tutorial (docs/tutorials/getting-started.md) | Tutorials are learning-oriented; ADRs aren't lessons |
| "We're considering Postgres vs SQLite." | RFC / design doc while open; ADR if accepted | An ADR is a decided record; a proposal isn't decided yet |
| "What do we do when the queue backlog spikes?" | Runbook (docs/runbooks/queue-backlog.md) — see runbook-canon.md. A runbook is for a paged on-call engineer; it is not the same as a Diátaxis how-to (planned work, healthy system). | Runbooks are operational; ADRs are architectural rationale |
| "Why did we pick Tailwind?" | ADR | Architectural / hard to reverse — this IS an ADR |
| "We're using camelCase for JSON keys." | CONTRIBUTING.md or a style guide | Convention, not architecturally significant |
| "What's the team's branching policy?" | CONTRIBUTING.md / wiki | Process, not architecture |
| "Open question: should we shard the user table?" | An open-questions register until measured — see open-questions-canon.md (the standalone form) | ADRs record made decisions, not pending research |
| "I changed the button color on the dashboard." | PR description / changelog — see changelog-canon.md (Keep a Changelog 1.1 + SemVer 2.0) | Reversible product/UX detail |
| "We will not adopt event sourcing — and here's why." | ADR (a "rejected alternative" decision is still a decision) | Architectural, irreversible-ish, expensive to revisit |
| "Document this regex so future-me understands it." | Code comment | Tiny, local, has exactly one reader: whoever touches that line next |
| "We need to write down our deployment pipeline." | Diátaxis reference + a how-to for common operations | Description of the system + tasks, not a decision |
| "What's our SLA / latency budget for the API?" | Diátaxis reference (a quality attribute spec) — and an ADR if the choice of budget was a deliberate tradeoff | Numbers belong in reference; the why we picked them belongs in an ADR |
| "Capture the meeting notes from architecture review." | A meeting-notes doc, then distill any actual decisions into ADRs | Meeting notes are not decision records; they're transcripts |
| "Write up the outage we just had." | Postmortem — see postmortem-canon.md (PagerDuty template, Google SRE cultural framing) | Postmortems record what happened; ADRs record what was decided. A postmortem may produce an ADR. |
| "Document AI / agent context for this repo." | `AGENTS.md` at repo root — see agentic-docs-canon.md. Replaces vendor-specific files (CLAUDE.md, .cursorrules, .github/copilot-instructions.md). | Tool configuration, not an architectural decision. The choice of which agent is not ASR-significant. |
| "Track copyright / per-file licensing metadata." | REUSE 3.3 / SPDX headers + LICENSES/ directory + optional REUSE.toml. Specs: reuse.software/spec-3.3/ and spdx.org/licenses/. | Metadata convention, not a decision. The choice to adopt REUSE can be an ADR; the per-file headers are not. |
| "Standardize our commit-message format." | Conventional Commits 1.0 (conventionalcommits.org) referenced from CONTRIBUTING.md and enforced via commit-lint. | Convention enforcement, not architecture. The adoption may be an ADR if it gates release tooling. |
| "How do users report a security vulnerability?" | `SECURITY.md` at repo root (private disclosure channel, scope, response SLA) — see ../../repo-health/references/security-canon.md. Refuses single-maintainer contact lines. | Disclosure-channel policy is community-health bootstrap, not an architectural decision. The choice to add a coordinated-disclosure program may be an ADR. |
| "Where do users go for help?" | `SUPPORT.md` at repo root (issue tracker scope, discussion forum, paid support, response expectations) — see ../../repo-health/references/support-canon.md. | Support routing is community-health, not architecture. Apply the four-question check before creating it (new projects often shouldn't have one yet). |
| "How do I cite this software?" | `CITATION.cff` at repo root (Citation File Format 1.2.0; GitHub renders "Cite this repository") — see ../../repo-health/references/templates-canon.md. | Citation metadata is descriptive, not a decision. Adopting CFF as the project's citation channel may be an ADR if downstream tooling depends on it. |
| "Who owns this code?" | `CODEOWNERS` in .github/, docs/, or repo root (GitHub auto-assigns PR reviewers from path globs) — see ../../repo-health/references/templates-canon.md. | Reviewer routing is process configuration, not architecture. The policy requiring two CODEOWNERS for /security/ may be an ADR. |
| "Issue / PR templates." | *`.github/ISSUE_TEMPLATE/.yml** (GitHub Forms) and **.github/PULL_REQUEST_TEMPLATE.md** — see ../../repo-health/references/templates-canon.md`. | Form configuration, not a decision. The requirement that every PR include a changelog entry may be an ADR (or simpler: encoded in the template itself plus CI). |
| "What should our README contain?" | `README.md` at repo root following the Standard Readme structure (title → badges → short description → install → usage → API → contributing → license) — see ../../repo-health/references/readme-canon.md. | README structure is convention, not architecture. The decision to adopt Standard Readme can be implicit (just follow it) or, if the team needs accountability, recorded as an ADR. |
The Diátaxis four
The most-confused alternatives. Name them precisely:
- Tutorial — learning-oriented; a guided lesson; serves a learner. "Build your first API endpoint."
- How-to guide — task-oriented; sequence of steps; serves a competent user with a goal. "How to deploy to production."
- Reference — information-oriented; austere, neutral, product-led description. "Configuration options."
- Explanation — understanding-oriented; discursive, considers alternatives, gives the why. "About the request-routing model."
ADRs are not Diátaxis explanations. An explanation answers "can you tell me about X?" and reflects on the bigger picture. An ADR answers "what did we decide, and why this rather than the alternatives, and what does that commit us to?" An explanation may link to ADRs to surface the rationale; it should not duplicate them.
How to use this catalog
1. Run the four-question diagnostic in SKILL.md first. 2. If the request fails the diagnostic, find the closest row above by matching the user's words. 3. Name the alternative explicitly, give the path, then re-run the four-question check on the alternative. 4. If no row fits, fall back to the Diátaxis four: ask whether the user needs learning, task completion, reference lookup, or understanding.
Folder-level audit procedure (used by /doc-audit)
The canonical procedure for auditing an existing doc set. The /doc-audit command hands the audit to the doc-expert agent, which loads doc-diagnostic and follows this procedure.
This reference is the long-form spec. The short pointer in SKILL.md and the user-facing description in commands/doc-audit.md both route here.
Inputs
- Target directory — default
docs/. The user may scope to a subdirectory (e.g.,docs/adr/) or expand to additional paths (e.g.,architecture/plus root-level*.md). - Optional context — which ADRs the user already suspects of drift; the project's stance on immutability vs living-document ADRs; files to exclude (generated docs, third-party imports, license boilerplate).
The procedure
1. Inventory. Glob the target directories. Count files, group by type:
- ADR (under
adr/,decisions/, or with ADR-shaped filenames) - RFC (under
rfcs/or with explicit "Status: Open / Closed" headers) - Runbook (under
runbooks/or with operational/incident framing) - Diátaxis: how-to, reference, explanation, tutorial
- README / index files
- Loose markdown that doesn't fit any of the above
2. Test each ADR against the canon. For every ADR check:
- Status set to an ADR Explorer-compatible value (
proposed,accepted,superseded,deprecated) with no overloadedrfc,rejected, or backfill text? - Owners / Deciders named as a YAML array (humans, not "the team")?
- Relationship fields shaped for graphing:
supersedesandamendsas YAML lists,relates-toas{id, reason}objects? - Confidence is
high,medium, orlow(with optional separateconfidence-scoreif numeric scoring is used)? - Alternatives considered, at the same level of abstraction?
- Consequences listed — both Good and Bad?
- Re-evaluation triggers present and concrete (not "annually")? Optional
expiresused only when expiry is real? - Supersession graph edge present on the new ADR's
supersedeslist? Do not rely onsuperseded-by/superseded byalone. - Numbering monotonic? Filename starts with the numeric id and uses an imperative verb phrase?
- ADRs live under ADR Explorer-friendly roots (
docs/adr/,docs/decisions/,docs/architecture/decisions/,**/adr/*.md), orarchitecture/decisions/is documented as needing custom root configuration? - Each failure points to a row in
references/failure-modes.md.
3. Test each non-ADR against the four questions. Purpose / Audience / Owner / Update trigger (see SKILL.md "The four-question diagnostic"). Files that fail two or more should be flagged for deletion or rewrite.
4. Detect drift. Cross-reference ADR claims with the code. If the ADR says "we use Postgres" and the codebase has switched to SQLite, flag it. Drift is the most common failure mode in long-lived doc sets.
5. Detect duplication. Two docs that answer the same question should be merged; the duplicate becomes a redirect to the canonical.
6. Detect misclassification. A "decision" doc that's actually a how-to should be moved. A "runbook" that's actually an explanation should be moved. Cite the Diátaxis quadrant for each move (see references/alternatives-catalog.md).
7. Detect backfill candidates — run the ASR test against shipped-change evidence.
- Surface to walk. Commit history, migration files, dependency manifests, infra files, removed dependencies, removed subsystems, retired modules, retired vendors, policy unifications, and subsystem retirements. For each, ask: did the team make an architecturally significant decision that was never recorded?
- ASR test. Apply the same measurable-effect-on-architecture-or-quality test used during pre-flight discovery. No measurable signal, no row.
- Two-locator rule (false-positive guard). Evidence must appear in at least two independent locations before a backfill row is emitted. A single commit message alone is not enough. A commit plus a deleted module, or a migration plus a removed dependency in the manifest, is enough.
- No measurable signal? Do not emit a row. Log it in
open-questions.mdinstead, naming what evidence would have to surface to upgrade it.
8. Report. Produce a numbered list of recommended actions:
KEEP— passes the canon and the four-question test as-is.MERGE— overlaps with another doc; specify the merge target.REWRITE— content is salvageable but violates the canon or fails the four-question test.DELETE— fails the four-question test with no salvage path. Requires human approval.MOVE— wrong location for its content type. Specify the new path and the Diátaxis quadrant.BACKFILL-ADR— shipped-change evidence reveals a past architectural decision that was never recorded. Surface as a candidate, not a draft. Use the row schema below.
Each entry gets a one-sentence rationale. Do not bulk-delete without human approval.
BACKFILL-ADR row schema
Each BACKFILL-ADR row has exactly five fields:
| Field | Notes |
|---|---|
decision | One-line imperative phrase, as if it were the title of the ADR that should have been written (e.g., "Retire the legacy queueing vendor in favor of an in-house event bus"). |
evidence-locator | At least two independent pointers: commit SHA, migration file path, removed module path, vendor record, manifest line removed, infra-as-code resource deleted. One pointer is not enough. |
ASR-test-result | Which architectural characteristic was affected (latency / cost / availability / security / maintainability / operability / portability / …) with a measurable signal. "Felt cleaner" is not a signal; "removed 14k LOC and one vendor dependency" is. |
reconstruction-confidence | high / medium / low. High = the decision, its forces, and at least one realistic alternative can be reconstructed from evidence. Medium = the decision is clear but forces or alternatives are partial. Low = only the what is recoverable, not the why. |
suggested-status | ADR Explorer-compatible value only: accepted if the decision is still in force, deprecated if the change was later undone or superseded. Put backfill/reversal details in tags, backfilled-on, and the honesty clause — not in status. |
Backfill confidence rule
If reconstruction-confidence is low, do not emit a BACKFILL-ADR row. The decision is not reconstructible to a standard that would justify a record in the decision log. Emit an open-questions.md row instead, naming what evidence would have to surface to upgrade the confidence to medium or high. Surfacing the gap is more honest than fabricating a rationale at backfill time.
Hard constraints
- Never delete or move a file without explicit human sign-off on the action list.
- Never edit an Accepted ADR's body. Header-only metadata or human-readable supersession notes require sign-off; ADR Explorer graph edges belong in the new ADR's
supersedeslist. Body changes require a superseding ADR drafted viaadr-drafting. - Never bulk-renumber ADRs. Numbers reflect creation order; gaps and out-of-order acceptance are fine.
- Never auto-generate Owners or re-evaluation triggers for ADRs that lack them — those need human input. Flag them in the action list as
REWRITE — needs Owner / re-evaluation trigger input.
Execution after approval
After the user approves the action list, execute the actions one file at a time, summarizing each change so the user can stop the audit at any point. Batch execution is allowed only when the user explicitly approves a group of actions ("apply all MOVEs," "apply all DELETEs").
Changelog canon — Keep a Changelog 1.1 + SemVer 2.0
The canonical reference for the CHANGELOG.md file. Load this when the user asks "where do I document this user-visible change?", "do we need a changelog?", or "what version should we bump to?"
A changelog is for humans, not machines. It records what changed in each release, grouped by intent, in reverse-chronological order. It is not a commit log, not a release-notes blog post, and not a marketing summary.
Upstream specs:
- keepachangelog.com/en/1.1.0 — Keep a Changelog 1.1 (the file format).
- semver.org/spec/v2.0.0.html — Semantic Versioning 2.0.0 (the version-number contract that the changelog reports against).
File location and shape
- Single file, at the repo root:
CHANGELOG.md. - Reverse-chronological — the newest release appears at the top, immediately below the
## [Unreleased]block. - An
## [Unreleased]section is always present at the top, even when empty. It accumulates entries between releases; on release, it is renamed to the version being shipped and a fresh empty## [Unreleased]is created above it. - Every released version block carries an ISO 8601 date in the heading:
## [1.4.0] - 2026-05-21. - Released sections are never edited — fix mistakes by adding a follow-up entry in the next release, not by rewriting history.
The six categories — and only six
Keep a Changelog defines exactly six entry categories. Do not invent new ones, do not split them, do not rename them.
| Category | Use for |
|---|---|
Added | New features visible to a user of the API / CLI / UI. |
Changed | Changes in existing functionality (behavior, output, signature). |
Deprecated | Soon-to-be-removed features. Still works, but flagged for users to migrate. |
Removed | Features removed in this release. |
Fixed | Bug fixes. |
Security | Vulnerabilities addressed. Note the CVE / advisory ID if one exists. |
If an entry does not fit one of these six, it is probably not a changelog entry — it is internal refactoring, a tooling change, or a developer-process note, none of which belong here.
SemVer cross-reference
The category an entry lands in determines the version bump:
| Changelog category | SemVer bump |
|---|---|
Added | MINOR — backwards-compatible feature. |
Changed (breaking) | MAJOR — backwards-incompatible behavior change. |
Changed (non-breaking) | MINOR — typically — when behavior changes but the contract holds. |
Deprecated | MINOR — the feature still works; deprecation flags a future MAJOR removal. |
Removed | MAJOR — anything removed is a breaking change. |
Fixed | PATCH — typically — unless the fix changes a documented contract (then MINOR or MAJOR). |
Security | PATCH — typically — but escalate if the fix breaks the contract. |
The rule of thumb: MAJOR for breaking, MINOR for new, PATCH for fixes. When in doubt, ask "does an existing caller need to change anything?" If yes, MAJOR. If they can just upgrade, MINOR or PATCH.
Canonical example
# Changelog
All notable changes to this project are documented in this file.
The format is based on [Keep a Changelog 1.1](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- Retry budget on the queue consumer.
## [1.4.0] - 2026-05-21
### Added
- `--dry-run` flag on the migrate command.
### Changed
- Logging now emits structured JSON by default.
### Deprecated
- The `--legacy-output` flag. Removal scheduled for 2.0.0.
### Fixed
- Race condition in the cache warmer (#412).
## [1.3.1] - 2026-04-30
### Security
- Upgraded dependency X to address GHSA-xxxx-yyyy-zzzz.Common failure modes
| Failure | Why it breaks the changelog | Remedy |
|---|---|---|
| Commit-log-as-changelog | A diff of commit messages mixes internal refactors with user-visible changes; readers cannot scan for impact. | Curate entries on each release. The commit log is the source; not the doc. |
No ## [Unreleased] at the top | Contributors have nowhere to put in-flight entries; on release day someone re-derives the list from git log. | Always keep ## [Unreleased] at the top, even when empty. |
| Ad-hoc dates / no dates / non-ISO dates | Cannot sort, cannot reason about release cadence, breaks tooling that parses the file. | ISO 8601 (YYYY-MM-DD), heading format ## [X.Y.Z] - YYYY-MM-DD. |
| Rewriting released versions | Destroys the audit trail that downstream consumers rely on. | Add a fix-up entry in the next release. Released blocks are immutable. |
Invented categories (Refactored, Docs, Internal, Build) | Defeats the six-category contract; readers cannot filter by impact. | If it's not user-visible, it doesn't belong in the changelog at all. |
Marketing prose in entries (Massive improvements to ...) | Readers cannot tell what actually changed. | One line per entry, factual, link to the PR / issue for detail. |
| Version bump that disagrees with changelog category | Breaks the SemVer contract — downstream lockfiles trust the version number. | Either move the entry to the right category or bump the right segment. |
Routing — when this is not the answer
- A user-visible API change that requires migration steps → changelog entry + a separate migration guide (Diátaxis how-to). The changelog says what changed; the migration guide says how to adapt.
- An internal refactor that doesn't affect users → commit message + PR description, not the changelog.
- A security advisory with embargo / coordinated-disclosure framing → `SECURITY.md` advisory + a
Securityentry referencing the advisory ID. - A choice between two implementation options that was decided during the release cycle → ADR, not a changelog entry. The changelog reports the outcome; the ADR records the rationale.
ADR failure modes and concrete remedies
The eleven canonical ADR failure modes. Load this reference during folder-level audits (/doc-audit) and during adr-critique to put a name to what's wrong with a given ADR.
Each row pairs a symptom with the remedy. Most failure modes have an obvious fix; the cardinal rule (SKILL.md "Immutability and supersession") still applies — never silently edit an Accepted ADR.
| Failure mode | Symptom | Remedy |
|---|---|---|
| Drift — ADR says X, code does Y. | Status is "Accepted" but the system no longer matches. | Either supersede with a new ADR that captures reality, or fix the code. Never silently edit the ADR. |
| ADR for a non-decision | The "decision" is a coding convention, a settled industry default, or a reversible UX tweak. | Move to CONTRIBUTING.md, code comment, or PR description. Mark the ADR Rejected with a note. |
| ADR-PRD duplication | The ADR retells what the product requirements doc already says. | The ADR's job is the decision and its rationale. Strip duplication; link to the PRD. |
| ADRs nobody reads | Decisions buried in a wiki; never linked from code. | Move ADRs into the repo; link from the relevant module's top-level comment or README. |
| Missing context | ADR states the decision but not the forces that made it necessary. | Add a Context section answering "why now? why us? what constraint?" Without it, future-you cannot judge whether the decision still holds. |
| Missing re-evaluation triggers | No concrete condition for revisiting. | Add a "Re-evaluation triggers" section with measurable thresholds. |
| Hidden alternatives | "We chose X." (No mention of Y, Z.) | Add Alternatives considered. If no alternative was considered, say so — that's also information. |
| Bundled decisions | One ADR covers "database, ORM, migration tool, hosting." | Split into separate ADRs. Cross-link them. |
| Premature ADR for an in-flight proposal | "Status: Proposed" sits there for six months. | Move to an RFC. ADRs are for made decisions. |
| Stale numbering / out-of-order acceptance | ADRs accepted out of numeric order, gaps in the sequence. | That's fine — numbers reflect creation order, not acceptance order. Don't renumber. |
| Template thrash | Three different templates across the same project. | Pick one and document the pick in docs/adr/README.md. Migrate opportunistically; don't bulk-rewrite. |
| Decision-by-AI without buy-in | An agent generated an ADR; humans never confirmed. | The Owners/Deciders field must name humans. The agent drafts; humans decide. |
How to use this table during an audit
For each ADR in scope:
1. Read header (Status, Owners, Supersedes / Superseded by, Date). 2. Read body (Context, Decision, Alternatives, Consequences, Re-evaluation triggers). 3. Match symptoms against the rows above. One ADR can hit multiple failure modes. 4. Record the failure-mode name alongside the audit verdict (KEEP / MERGE / REWRITE / DELETE / MOVE). Naming the failure mode is faster than re-deriving the problem from scratch.
How to use this table during line-by-line critique
The adr-critique skill walks an ADR line by line. When a line trips a rule (marketing language, hedging, missing-why, future-proofing essay, passive-voice corporate text, implementation bleed), check whether the surrounding section also exhibits one of the failure modes above — they often co-occur. A "missing context" ADR is usually also full of hedging because the author had no constraint to argue from.
Open-questions register canon
The canonical reference for an open-questions register as a standalone documentation form. Load this when the user says "we're not ready to decide yet," "park this for later," "what should I do with the things we don't know?", or "where do unresolved architectural questions go?"
An open-questions register is a scoped, owned, dated list of unknowns that block or qualify future decisions. It is the legitimate alternative to a premature ADR — when a team feels pressure to "write something down" before the decision is actually made, the register is where that pressure should land.
Why this is not an ADR
An ADR captures a made decision and its rationale. An open question by definition has neither — it has a question and (at best) candidate answers awaiting evidence. Putting open questions in the ADR log:
- Pollutes the decision graph with non-decisions.
- Creates ADRs that sit in
status: proposedfor months. - Mixes "what did we decide" with "what are we still figuring out," which confuses every reader.
The register keeps unknowns visible without converting them into decisions they are not.
File location
- Single file, in the architecture area but outside the ADR directory the parsers walk:
- Default:
docs/architecture/open-questions.md. - Alternative:
docs/decisions/open-questions.mdif the project usesdocs/decisions/for ADRs — keep the file at the parent of the ADR directory, not inside it. - One register per system / product area. Do not maintain one register per team — too many registers means none of them are read.
The register is intentionally one level up from the ADR globs so ADR Explorer / ADR Manager / validate_adrs.py do not try to parse it as an ADR.
Distinction from adr-discovery's open-questions-register.md
doc-master has two related artifacts:
| Artifact | Scope | Owner | Lifecycle |
|---|---|---|---|
This canon (open-questions-canon.md) — the standalone register form. | Anything the team is consciously deferring or actively researching. | The project / team. | Lives indefinitely; sweeps quarterly. |
| `adr-discovery/references/open-questions-register.md` — the discovery subset. | Unknowns surfaced specifically during a single ADR's pre-flight Q&A. | The drafting architect. | Tied to the ADR; questions resolve before drafting. |
The discovery file is a focused subset; this canon is the long-lived home. Discovery questions that survive past their ADR (because the team chose to ship the ADR with the question PARKED) graduate into the standalone register here.
Required columns per row
Each row of the register answers six questions. Missing any one of these and the row is too vague to act on.
| Column | What it answers |
|---|---|
| Question | The unknown, phrased as a question. ("Should we shard the user table?" — not "Sharding.") |
| Decision needed by | A concrete date or measurable trigger. ("When DAU exceeds 50k," "by 2026-09-01," "before the Q4 migration.") |
| Blocker for | What downstream work this question is gating. Without a blocker, the question is academic. |
| Current best guess | The team's working hypothesis, with a confidence note (low, medium, high). Not a commitment. |
| Measurement plan | What evidence would resolve the question. The specific dashboard, the specific experiment, the specific call. |
| Owner | A named human (not "the team"). The person accountable for moving this row forward. |
Optional columns:
- Raised — ISO 8601 date the question was added.
- Related ADRs — IDs of ADRs this question relates to (e.g., it qualifies an existing ADR, or will produce a new one).
- Status —
OPEN,ANSWERED,PARKED(matches the discovery file's vocabulary).
Graduation rule
When the Measurement plan produces evidence, the row graduates — it does not stay open forever.
- If the resolved question is architecturally significant (an ASR — passes the ASR test in
SKILL.md): promote to an ADR. The register row gets markedANSWEREDwith the date and a link to the new ADR. - If the question turned out to not be architecturally significant (a coding convention, a settled-elsewhere policy, a reversible UX detail): close the row and route the answer to the correct alternative form via
alternatives-catalog.md. - If the team decides to ship with the question unresolved: mark the row
PARKED, cite it in the relevant ADR's Consequences section, and add a re-evaluation trigger.
The graduation rule is what keeps the register from becoming a dead list.
Canonical example
# Open Questions -- Architecture
This file tracks unknowns that block or qualify upcoming architectural decisions.
Each row is owned by a named human and has a measurement plan.
| ID | Question | Decision needed by | Blocker for | Current best guess (confidence) | Measurement plan | Owner | Status |
|-----|---------------------------------------------------------|----------------------------|------------------------------|----------------------------------------------|---------------------------------------------------------------------------------|---------|---------|
| Q12 | Should we shard the user table? | When DAU > 50k | ADR-0016 (Postgres adoption) | Yes, by tenant ID (medium) | Run a load test at 75k synthetic users on the staging Postgres; record p95. | Priya | OPEN |
| Q14 | Multi-region read replicas -- needed for EU launch? | 2026-08-15 | ADR-0019 (regional routing) | Yes (high) -- latency requirement is firm. | Confirm latency budget with product; benchmark cross-region replication. | Marcus | OPEN |
| Q07 | Will the queue handle 10x peak? | Resolved 2026-04-12 | (none) | Yes -- confirmed by load test on 2026-04-10. | Load test result: p99 < 200ms at 12x peak. Logged in test-run-2026-04-10.json. | Priya | ANSWERED|When Q07 was answered, the team did not write an ADR — the answer ("yes, the queue handles 10x") is a measurement, not a decision. Had the team chosen to oversize the queue based on that measurement, that choice would be the ADR.
Common failure modes
| Failure | Symptom | Remedy |
|---|---|---|
| Orphan questions | A question with no owner, no measurement plan, no decision-by date. | Refuse to add it. Push back to the requester until those are filled. |
Eternal OPEN rows | Rows with Decision needed by dates in the past, still marked OPEN. | Sweep quarterly. Re-date or escalate or PARK. |
| The register becomes a TODO list | Implementation tasks creep in ("upgrade Redis to 7.2"). | Implementation tasks belong in the issue tracker. The register is for open questions. |
| Resolved questions never graduate | ANSWERED accumulates; no resulting ADRs. | The graduation rule is the point. If nothing graduates, the register is bookkeeping. |
| One register per team | Five registers, none of them comprehensive, none of them read. | One register per system / product area, owned at the architecture level. |
Routing — when this is not the answer
- "We've decided X" → ADR, not the register.
- "We've decided not to decide yet, and we've identified the trigger that will force the decision" → register row with a clear
Decision needed by. - "We don't know how to do X right now and don't intend to decide soon" → `SUPPORT.md` / FAQ / Discussions if it's user-facing; issue tracker if it's implementation.
- "We've decided to ship with this question unresolved" → ADR with the question PARKED in Consequences, plus a register row tracking the PARKED state and re-evaluation trigger.
Postmortem canon — blameless incident review
The canonical reference for postmortems. Load this when the user says "we had an outage last week," "write up the incident," or "schedule a postmortem."
A postmortem records what happened, why, and what changes the team commits to after a notable incident. It is blameless by construction — the document focuses on systems, processes, signals, and decisions, never on individuals.
Two sources, distinct roles
doc-master distinguishes the template (the file you fill in) from the cultural framing (the discipline that determines whether the document is useful).
| Source | Role | Use | Licensing notes |
|---|---|---|---|
| PagerDuty Incident Response — Post-Mortem Template | The template itself. | Copy the sections, adapt the wording. | Open / copyable. Cite as "PagerDuty Incident Response open templates." |
| Google SRE Workbook, Ch. 10 — Postmortem Culture | The cultural framing. | Read the chapter; do not copy. | CC BY-NC-ND — link only, do not embody. |
doc-master writes from the PagerDuty template and links to the Google SRE chapter for the cultural framing.
Required sections (PagerDuty template)
A doc-master postmortem includes these sections, in this order:
1. Incident Summary — one paragraph: what, when, who saw it, severity. 2. Leadup — what was in flight before the incident: deploys, config changes, traffic shifts, dependency upgrades, holiday weekends. Factual, not causal. 3. Fault — the specific failure: which component, which mode, which contract was violated. 4. Impact — measurable customer effect: users affected, requests dropped, revenue lost, SLO budget consumed, regulatory implications. Use numbers. 5. Detection — how the team learned about it: alert, customer report, internal observation. Note the latency between the fault and detection. 6. Response — what the team did, in order. Who was paged. Which runbook fired. Where the response stalled. 7. Recovery — what restored service. Whether the recovery was clean (graceful rollback) or messy (manual intervention, lingering effects). 8. Timeline — UTC timestamps, single source of truth. Cross-references every other section. 9. Root Causes — Five Whys (or equivalent technique). Multiple causes are expected and named separately, not collapsed into one. 10. Action Items — what changes the team commits to, each with an owner, a due date, and a tracking ID. Avoid "improve monitoring" — name the specific dashboard, the specific alert, the specific code change. 11. Lessons Learned — what generalizes beyond this incident. What the team understands now that it did not understand before.
When to write a postmortem — predefined triggers
A postmortem is not discretionary. The team agrees the triggers in advance, in writing, and writes one for any incident that hits them:
| Trigger | Examples |
|---|---|
| Severity threshold | SEV-1 / SEV-2 / "P0" — whatever the org's convention is. |
| Customer-facing outage | Anything customers noticed, even briefly. |
| Security incident | Any incident involving credentials, data exposure, or vulnerability exploitation. |
| SLO budget exhaustion | A single incident consumed > 25% of the monthly error budget (or the team's threshold). |
| Near-miss | The system was about to break and a human caught it — these teach the most. |
| Recurring pattern | Third incident this quarter from the same subsystem — even if individually small. |
If the trigger is subjective ("was that bad enough?"), the team will under-write postmortems for the incidents that matter most — the loud ones get one, the quiet expensive ones do not. Make the triggers boolean.
Blameless framing — the discipline
The cultural rule is: focus on systems and processes, never on people.
- "The on-call engineer ran the wrong command" → bad. Reframe: "The runbook documented two commands with similar names; the more dangerous one was listed first."
- "Alice forgot to update the config" → bad. Reframe: "The config change required manual coordination between three repositories with no enforcement."
- "We should have caught this in review" → bad. Reframe: "The review checklist did not cover this class of change; we are adding a check for X."
When a postmortem names a person, ask: would changing that person fix the problem, or would the next person hit the same trap? If the latter, the trap is the problem.
For the deeper framing — psychological safety, second stories, hindsight bias, the swap test — read the Google SRE Workbook Ch. 10 referenced above. doc-master does not reproduce that chapter.
Postmortem is not an ADR
A postmortem and an ADR are different documents with different audiences:
| Dimension | Postmortem | ADR |
|---|---|---|
| Subject | A specific incident that already happened. | A specific decision the team is making (or made). |
| Audience | The team and adjacent teams; sometimes leadership. | Future maintainers and reviewers of the architecture. |
| Timing | After the incident, on a calendar deadline. | Before or at the moment of decision. |
| Updates | One per incident; never edited, only amended. | Append-only; superseded, not edited. |
| Output | Action items. | A decision and its rationale. |
A postmortem may produce an ADR — for example, "Add a circuit breaker between the payment service and the fraud service" might appear as an action item in the postmortem, and then become a separate ADR that records the architectural choice. The two documents cross-link; they do not collapse.
Common failure modes
| Failure | Symptom | Remedy |
|---|---|---|
| Single root cause | "The cause was the network." | Five Whys — incidents almost always have multiple contributing causes. Name each. |
| Action items with no owner / no date | "Improve monitoring." Nobody does it. | Every action item: owner, due date, tracking ID. Otherwise it is wishful thinking. |
| Person-blame creeping in | "X engineer should have ..." | Reframe as a systems gap. If you cannot, the postmortem facilitator pushes back. |
| Postmortem never published | Lessons stay with the immediate responders. | Publish to the team-wide channel. Adjacent teams learn more from your incidents than yours. |
| Action items never tracked | The list lives in the postmortem and dies there. | Link each action item to a tracker entry. Review at the next team retro. |
| "What we'd do differently" without commitment | Lessons learned but no behavior change. | Each lesson becomes an action item or an ADR. Otherwise it is not a lesson. |
Routing — when this is not the answer
- "What to do during the incident?" → runbook (
runbook-canon.md). The runbook is forward-looking; the postmortem is backward-looking. - "Why did we pick this architecture in the first place?" → ADR (
alternatives-catalog.md). - "What's our incident-response process in general?" → Diátaxis explanation + a runbook for each alert class. Not a postmortem.
- "What customer-visible changes did we ship?" → changelog (
changelog-canon.md), with aSecurityentry if the incident produced one.
Runbook canon — operational steps for paged incidents
The canonical reference for runbooks. Load this when the user says "we need a runbook for X," "what do we do when the queue backs up?", or "document our incident response for the database alert."
A runbook is for an on-call engineer being paged at 03:00 under stress. It assumes nothing: not that the reader knows the system, not that the reader is awake, not that the reader has time to read prose. Every step is copy-pasteable. Every step has an expected output. The reader's job is to follow, not to learn.
This is fundamentally different from a Diátaxis how-to guide, even though both are task-oriented:
| Dimension | Runbook | How-to guide |
|---|---|---|
| Reader state | Paged, under stress, possibly half-asleep. | Competent user, planned work, system healthy. |
| Assumptions | None. Reader may have never seen this system. | Reader knows the system, has goals, can debug. |
| Tone | Imperative, copy-paste, single-path. | Imperative, explanatory, with branches. |
| Time pressure | Minutes — every step counts. | None — reader can pause and read. |
| Branching | Avoided — pick the one safe path, flag exits. | Allowed — multiple valid approaches. |
| Verification | Mandatory after each step. | At the end of the procedure. |
| Reuse | One runbook per alert / paging condition. | One how-to per goal. |
One runbook per alert. If a single alert can mean three different things, you have three runbooks (or one runbook with a clearly labeled triage step that branches to three sub-runbooks).
Upstream source: PagerDuty Incident Response — open, copyable operational playbook the rest of the industry has converged on. The PagerDuty material is published under permissive terms; cite it as "PagerDuty Incident Response open templates," not as a product endorsement.
Required sections
A doc-master runbook has these sections, in this order:
1. Title — exactly the alert name / paging condition as it appears in the monitoring system. If the alert is db-replica-lag-high, the runbook title is db-replica-lag-high. No marketing prose, no rewording. The on-call engineer pastes the alert name into a search box and the right runbook comes up first.
2. Trigger — what fires this runbook:
- The exact alert ID (e.g.,
PD-INC-1042,prom-rule-name). - The dashboard URL the alert links to.
- The customer-report channel if one exists.
3. Preconditions — what must be true before running the steps:
- Required access (which IAM role, which secret, which bastion).
- Required tools installed locally.
- Anything that would silently fail otherwise.
4. Steps — numbered, each step is a single action:
- Copy-pasteable — every command runs as written.
- Expected output — what success looks like, character-by-character if possible.
- What to do if the expected output is absent — point to the next step or to the Escalation section.
- One step per cognitive unit. Do not bundle.
5. Verification — how to confirm the incident is resolved:
- The dashboard signal that should return to green.
- The customer-facing check.
- The wait time, if there is one ("metrics propagate in 60–90 seconds").
6. Rollback — what to do if the steps make it worse:
- The exact revert command for each forward step.
- Whom to call if rollback fails.
7. Escalation — who to wake up, and when:
- Named alias (not a person — bus factor).
- The threshold ("after 15 minutes with no improvement").
- The next-tier alias.
8. Known false positives — patterns the on-call should recognize as "not a real incident":
- Specific symptoms that look like the alert but are not.
- Why they look similar.
- How to confirm it's a false positive (the test, not the heuristic).
9. Last verified — ISO 8601 date the runbook was last exercised end-to-end. If it has not been exercised in six months, treat it as stale.
Common failure modes
| Failure | Symptom | Remedy |
|---|---|---|
| Runbook is actually a how-to | Branches, prose explanations, "first read this design doc." | Strip explanation. Move to docs/how-to/. Write a fresh runbook with copy-paste steps. |
| One runbook for "the database is sad" | Single document covering five different alerts. | Split into one runbook per alert. Cross-link if they share a triage step. |
| Steps lack expected output | Reader runs the command, gets unexpected output, freezes. | Every step has a "you should see ..." block. Failure mode is a separate step. |
| Escalation contact is a single person | That person is on PTO; bus factor of one. | Escalate to a shared alias (rotation, team channel), never a single human. |
| Never exercised | "Last verified" is missing or > 12 months old. | Quarterly tabletop or game-day exercise. Update or retire the runbook after each. |
| Drift | Runbook says service-foo restart; service was renamed to service-bar. | Audit alongside the service it documents. Stale runbook is worse than no runbook. |
| Hidden in a wiki | On-call cannot find it from the alert. | Link the alert directly to the runbook. Store runbooks in the repo or a flat shared folder. |
Canonical skeleton
````md
db-replica-lag-high
Trigger
- Alert ID:
prom-db-replica-lag-high - Dashboard: <link>
- Customer channel:
#cust-incidents(search forreplica lag)
Preconditions
- AWS access to the
db-prodaccount. psqlandawsclion your path.- Bastion access -- VPN profile
prod-bastion.
Steps
1. Confirm the alert is current -- open the dashboard above. Replica lag > 30s for > 5 minutes?
- Expected: red line above 30s on the
replica-lag-secondspanel. - If green, this is a stale alert. Acknowledge and stop.
2. Identify the replica:
aws rds describe-db-instances --db-instance-identifier db-replica-prod- Expected: status
available. - If
failedorincompatible-parameters, skip to Escalation.
3. ... (one step per cognitive unit, copy-paste, expected output)
Verification
- Dashboard
replica-lag-secondsreturns under 5s and stays for 10 minutes. - Customer report channel quiet for 15 minutes.
Rollback
- (Per forward step, the exact revert command and the verification it returns to green.)
Escalation
- After 15 minutes with no improvement: page
db-oncall-tier2via PagerDuty. - After 30 minutes: page
eng-leadership-oncall.
Known false positives
- A scheduled
pg_dumpat 02:00 UTC causes ~45s of replica lag for ~3 minutes. If the alert fires at exactly that window and clears within five minutes, acknowledge as expected.
Last verified
- 2026-04-12 (tabletop exercise)
````
Routing -- when this is not the answer
- "How do I deploy to staging?" → Diátaxis how-to guide, not a runbook. The user is not being paged.
- "Why does the system handle backpressure this way?" → Diátaxis explanation.
- "What was the call we made on circuit-breaker thresholds?" → ADR — the decision. The runbook executes; the ADR records why the threshold is what it is.
- "What happened during the 2026-05-12 outage?" → postmortem, not a runbook. See
postmortem-canon.md. - "What are all our alert IDs and severities?" → Diátaxis reference (an alert catalog), with each entry linking to its runbook.