How to write an ADR
Purpose #
Recipe for adding a new Architecture Decision Record under .docs/docs/architecture/decisions/.
When you need one #
Per CLAUDE.md §7.5 and contributing/contribution-guide.md, file an ADR when a change touches:
- The Adapter contract or its types
- The Stack-pack contract or its types
- The MCP catalog shape or evaluator
- The runtime, language, monorepo tooling
- The distribution model (registry, dist-tags, provenance, signing)
- The security model
- Anything else that is genuinely architectural and will outlive a single PR
You do not need one for: bug fixes, doc updates, additive content (new skill in @aidokit/base-skills, new catalog entry that fits the existing shape — though ADR-0015 is an example of when a "data" change warranted an ADR because it expanded the security surface).
Steps #
1. Pick the next number #
ls .docs/docs/architecture/decisions/ | grep -E '^[0-9]{4}-' | sort | tail -5
The next ADR is the next monotonically-increasing four-digit number. Never reuse a number, even if there's a gap.
2. Copy the template #
cp .docs/docs/architecture/decisions/0000-template.md \
.docs/docs/architecture/decisions/00NN-short-kebab-slug.md
3. Fill in the header #
# ADR 00NN: Short title
| Field | Value |
| ------------- | ------------------------------------------- |
| Status | Proposed |
| Date | YYYY-MM-DD |
| Deciders | Project maintainers |
| Supersedes | — |
| Superseded by | — |
| Related ADRs | (list) |
Status starts as Proposed. On merge, the maintainer flips to Accepted (or Rejected with reasons).
4. Required sections #
The template enforces:
- Summary — 3–5 sentences. The decision in plain prose.
- Context — Why this needs deciding now. What constraints are at play.
- Decision — Numbered list of the actual rules / choices.
- Consequences — Positive / Negative / Neutral. Be honest about tradeoffs.
- Alternatives considered — Each alternative gets Pros, Cons, and "Reason rejected." This is the most useful section for future contributors.
- Implementation notes — Concrete code, file paths, scaffolding.
- Validation — Checklist of what proves the decision is working.
- References — Internal (other ADRs, specs, ARCHITECTURE sections) and external (RFCs, blog posts, vendor docs).
5. Cross-link #
- Add the ADR to reference/adr-index.md with a one-line summary.
- Reference it from the affected spec(s) under .docs/docs/specs/.
- Reference it from CLAUDE.md §7.5 if it's contract-relevant.
6. Open the PR #
Title: docs(adr): NNNN <short-slug>
Body: cite the change(s) the ADR enables (a follow-up PR may implement it; some ADRs are pure architecture decisions).
7. After acceptance #
- Maintainer flips status from
ProposedtoAccepted. - If the decision deprecates a previous ADR, set
Supersedeson the new ADR andSuperseded byon the old one. Do not delete the old ADR.
Worked examples #
- ADR-0008 — A single-decision ADR that codified a long-standing policy ("never auto-install prereqs") referenced by multiple specs.
- ADR-0015 — A "data" ADR for a catalog addition that expanded the security surface (Python prereq, repo content sent off-host).
- ADR-0016 — A scope-expansion ADR that added a third adapter to v1.0 with documented gaps.
- ADR-0012 — A reconciliation ADR that resolved a spec ↔ code mismatch authoritatively.
Read these to see the expected depth and tone.
Common pitfalls #
- Skipping "Alternatives considered." This is the section future contributors rely on to understand why they shouldn't propose the same idea.
- Status: Proposed forever. ADRs need closure. If a Proposed ADR sits >30 days, the maintainer either accepts, rejects, or splits it.
- Renumbering. Numbers are permanent.
- Editing an Accepted ADR after the fact. Accepted ADRs are immutable in spirit. If a decision needs revision, write a new ADR that supersedes.
- Putting transient state in an ADR. ADRs are durable design rationale. Task tracking goes in
agent-artifacts/.