Decisions
Architecture decision records say why the system is shaped the way it is, including the choices that constrain everything built after them.
What these are
An architecture decision record is one page describing one decision: what forced it, what was chosen, what was rejected, and what the project accepted as a consequence. They are numbered, they are never rewritten to look better in hindsight, and they are public.
They are public because of who is expected to depend on this system. A team adopting a component library for a patient-facing product may have to justify that choice to a clinical safety officer, an accessibility auditor or a procurement reviewer, none of whom were in the room. "The system does it this way" is not an answer to any of them. A dated record naming the alternative and the trade-off is.
The format
Every record has the same six headings, and the two that matter most are the two usually missing.
Consequences is where the cost is written down. A decision with only benefits listed has not been thought about; it has been advertised. Consequences include the things that got harder, the work the decision created, and the risks accepted.
Alternatives considered names the option that was rejected and why. This is what makes a record useful in two years, when somebody proposes the rejected option again. They usually have good reasons, because the reason it was rejected may have expired.
Status values
| Status | Meaning |
|---|---|
| Proposed | Written, not yet agreed |
| Accepted | In force. The system is built this way |
| Accepted, not yet implemented | Agreed and binding, but the code is not written |
| Superseded | Replaced by a later record, which is named. The page stays |
A record is normally kept even after it is reversed, because the reasoning that
produced a decision we later undid is the most useful thing in this folder. The
exception is a record whose subject no longer exists in the system at all. Two
records described the considered release phase and the roster built from it.
That phase has been removed from the vocabulary, so those records described a
mechanism that no page, no script and no catalogue row can refer to any more,
and a page kept on the site keeps teaching its vocabulary to every reader and
to every agent fetching the .md twins. A reader cannot tell a withdrawn record
from a live one by reading it, which is why the page goes rather than gaining a
banner. They were withdrawn and deleted, and
0023 names what went. Three conditions hold
whenever that happens: the record that removes the mechanism names what went,
the number is never reused, and git history is the archive.
When to write one
Write a record when a choice is expensive to reverse, constrains work that comes after it, or will look arbitrary to somebody who arrives later. Choosing a primitive library, a distribution model or a colour architecture qualifies. Choosing a variable name does not.
Write it before implementing, not after. A record written afterwards describes what happened; a record written first is a decision that can still be argued with while arguing is cheap.
The records
| # | Decision | Status |
|---|---|---|
| 0001 | Base UI, not Radix, as the primitive layer | Accepted |
| 0002 | Distribute as a shadcn registry; no CLI first | Accepted |
| 0003 | Two independent colour axes that never mix | Accepted |
| 0004 | lyra themes the documentation chrome only | Accepted |
| 0005 | No [lang] segment; bound the retrofit instead | Accepted |
| 0006 | Source, tables and measured numbers are generated | Accepted |
| 0007 | Two sibling root layouts, and no app/layout.tsx | Accepted |
| 0009 | The default export of a registry file is a zero-prop demo | Accepted |
| 0010 | Shared code ships inside every registry item | Accepted |
| 0011 | Anatomy parts are internal structure, identified by data-slot | Accepted |
| 0012 | Example data is synthetic and explicitly unsourced | Accepted |
| 0013 | A component preview is an iframe, not an inline render | Accepted |
| 0014 | The material rung names are the token names | Accepted |
| 0015 | One flat error-code scheme; errors.json is the source | Accepted |
| 0016 | The unit table ships spoken forms, not conversion factors | Accepted |
| 0017 | precision means decimal places, everywhere | Accepted |
| 0021 | A modal surface owns its own open state | Accepted |
| 0023 | Three release phases, and only a component page carries one | Accepted, outline superseded by 0024 |
| 0024 | The component page is lean | Accepted |
| 0025 | The WCAG 2.2 AA audit is author-run, not an independent review | Accepted |
The numbers are not contiguous. There is no 0008, no 0018 to 0020 and no 0022. 0008 and 0022 were withdrawn and deleted; 0018 to 0020 were never written. The gaps are in the numbering rather than in this table, and they are left as they are because renumbering a record would break every link and every citation that already names it.
Last read through against the system on 2026-09-02. Due for review every 12 months; expiry is reported by pnpm run check:freshness.
Licence and attribution
The code is MIT and the guidance prose is separately CC BY 4.0, so a team can quote this guidance inside a clinical safety case with a clear attribution path.
ADR 0001. Base UI, not Radix
The primitive layer is Base UI everywhere, chosen for its animation contract and for keeping exactly one primitive library in the tree.