Register an architecture decision as a beads decision bead. Use when a hard-to-reverse choice is made, when superseding one, or when `bd lint` reports findings.
Resources
1Install
npx skillscat add srobroek/omp-plugins/adr Install via the SkillsCat registry.
Architecture decision records
Records a decision when it is made, as a beads decision bead. The bead is
the record. The file under docs/adr/ is generated from it by a pre-commit hook,
so anyone without beads installed can still read the decision in a PR.
Requires bd. Without it the hook exits 0 and the committed files stand.
When to use
- A choice is hard to reverse, constrains later work, or crosses a package,
contract, or agent boundary. - A decision is being replaced, which is a supersede rather than an edit.
bd lintreports a decision bead missing a section.- Someone asks "why is it built this way", and the answer is not written down.
Do not use for a choice a later commit can undo at no cost, or a naming preference.
Registering, while the work happens
# Create it before the choice affects anything else. --validate rejects a
# description missing a required section, so the gate runs at creation.
bd create "Adopt X for Y" --type decision --id adr-7 --force --validate \
--spec-id 042-some-spec \
-d '## Decision
Adopt X.
## Rationale
X is the only option that satisfies <driver>, verified by <evidence>.
## Alternatives Considered
Y, rejected because <cost>. Z, rejected because <cost>.'
bd update adr-7 --claim # while drafting: claimed, so others skip it
bd defer adr-7 --reason "proposed" # undecided: out of bd ready, still in bd list
bd close adr-7 --reason accepted # decided: the hook renders it on next commit--id adr-N --force keeps decisions out of the work id space. --force is
required because the id prefix differs from the database's; it is not overriding a
safety check.
Link the work without blocking it:
bd dep add <affected-bead> adr-7 --type relates-to
bd dep add <validator-bead> adr-7 --type validatesWhy a decision is not open work
Every discovery path is bd ready, so an undecided decision must stay out of it
without being closed. bd defer with no --until is indefinite and
status-based -- nothing wakes it on a timer, and bd list still shows it.
Do not build a sentinel task or a blocking epic for this. A decision bead cannot
be blocked by an epic, and an epic blocker that beads does accept is silently
ignored by bd ready.
A closed bead stays fully editable, so closing costs nothing: notes and comments
still apply afterward.
Writing the description
bd create --validate and bd lint enforce these sections:
## Decision-- the choice, stated in one unhedged sentence.## Rationale-- the driver that settled it and the evidence, written
against criteria chosen before the winner was known.## Alternatives Considered-- every option genuinely weighed, and why each
lost. A straw option added to flatter the winner makes the record worthless.
## Consequences and ## Confirmation are optional to the tool and expected by
review. State a consequence that is a cost: a record with no downside was not a
decision between real alternatives. No tool enforces that one.
Notes hold the running narrative and can be corrected wholesale while the
decision is proposed; comments are the attributed audit trail. Do not put one MADR
section per note -- notes only append, so a correction loses the boundary.
Superseding
bd supersede adr-7 --with adr-12This closes adr-7 with a reference to its replacement and records a typedsupersedes edge, which the renderer reads to mark the old file superseded.
Never hand-maintain a metadata field for this: a field and an edge disagreeing is
how a file came to claim a decision still stood after it had been replaced.
Supersede when the decision changes. Shipping a release that implements an
existing decision changes nothing about the record -- an ADR is point-in-time, and
re-superseding it per release destroys that.
The generated file
| Property | Value |
|---|---|
| Format | MADR 4.0.0 |
| Path | docs/adr/NNNN-kebab-title.md |
| Numbering | creation order among closed decisions, not the bead id |
| Source | bd export, filtered to issue_type == "decision" |
| Rendered | closed decisions only |
Never edit a file under docs/adr/. It is regenerated from its bead on the next
commit and the edit is destroyed. Edit the bead.
OMP injects this via the beads-adr-generated-guard TTSR rule (advisory,
not abort): the file is regenerated from the bead. Hand-authored ADRs stay
editable.
Installing the hook
prek install --git-dir .git--git-dir is required wherever core.hooksPath points outside the repository, as
a corporate secret scanner does. Bare prek install refuses there and suggests
unsetting core.hooksPath, which would disable the scanner; both layers coexist
with the shim in place.
The repos: fragment is at templates/pre-commit-adr.yaml. project-setup merges
it into .pre-commit-config.yaml and vendors render_adrs.py into the repository,
rewriting entry: to the vendored path.
Pre-commit rather than CI: the bead lives in the local Dolt store and is not pushed
yet, refs/dolt/data is versioned independently of git commits so CI cannot pin
the database to the commit under test, and the beads doctrine forbids bd dolt pull from any lifecycle hook. Reading the local store needs no sync authority.