An architecture decision record exists to stop a settled argument being had again. It earns its number when a decision had genuinely live alternatives, when choosing wrongly would have cost something real, and when someone reading the code a year from now would otherwise reopen it — usually by “fixing” the thing the record explains.
Most of what looks like a decision is not one. The STOP sentinel file, the
status file, dedup_bleed’s overlap and containment thresholds, Vad::turns
against Vad::chunks, using rustfmt’s defaults, the pnpm version pin in CI,
and CDLA-Permissive-2.0 sitting in the licence allowlist are all reasoned
choices with no serious rival. Each is a good paragraph in the chapter that
owns it — capture,
sessions,
what CI checks — and none is an ADR. A record whose
alternatives were never seriously live is a paragraph with a number on it, and
a directory of those is how the practice dies: nobody reads records that
mostly say nothing.
Filenames and numbering
Files are NNNN-kebab-slug.md: four digits, monotonic, never reused and never
renamed. Commit messages cite records by number, so renaming
0004-vad-chunking.md silently breaks every message that said ADR-0004. A
withdrawn record keeps its number and gains a status; the number is not
returned to the pool.
Immutability
A record is immutable once accepted. Fix a typo; do not revise an argument.
When the decision changes, write a new record and add reciprocal links: the
new one carries **Supersedes:** [ADR-NNNN](NNNN-slug.md) on its metadata line, the old one gains a matching Superseded by. Both files stay in the
tree, because the point of the record is the reasoning at the time, and that
reasoning is what a superseding record has to argue against.
rejected records are kept for the same reason, and are often the most useful
files here — the alternative someone is about to propose, already measured and
already declined.
The date is the date the decision was made. It is never touched afterwards.
Adding one
cp docs/adr/TEMPLATE.md docs/adr/0014-<slug>.mdThen give it title: and sidebar.order: frontmatter, matching the record
above it. CI fails on a record without both: no frontmatter means the content
collection rejects the file and the build stops, and no sidebar.order means
the record lands unplaced in the nav, which is nearly as good as unwritten.