Architecture decision log
Every architectural decision lives here as its own record. The table below is the index: read it top to bottom, and the latest decision on a subject supersedes any earlier one.
Superseded records are never deleted and never edited into agreement. They stay, marked, so the reasoning trail survives — including the reasoning that turned out to be wrong. That is the point of keeping them.
A record in this log is a decision we have made. There is no status column: if it is on main,
it is how we do it. Changing one means a new record that supersedes it, not an edit.
🔒 Confirm the decision before you write the record
The gate is at the start, not the end.
If you are working — and especially if you are an AI agent — and you hit something that needs an architectural decision, stop and ask @mattmoran56. Get an answer, then write the record with that answer in it and open the PR. Merging is the acceptance; there is nothing to sign afterwards.
What needs asking:
- Anything hard to reverse — a database, a platform, a sync model, an auth model
- Anything cross-cutting — it constrains code nobody has written yet
- Anything contentious — two reasonable people would pick differently
- Anything that changes a decision already in this log
What does not: a library swap, a naming convention, or anything a code review settles in one comment.
:::danger Do not invent the answer An agent must never decide one of these on its own and write the record as though it were settled. Not from a plausible default, not from "the code already does it this way", not from an inference about what Matt would probably say. Ask.
If code genuinely has to exist before the decision lands, keep it small, keep it reversible, and say so in the PR — but the record does not go in until there is an answer. :::
The table
Latest first. A decision lower in the table is older; if two records address the same subject, the higher one wins.
| ADR | Decision | Date | Supersedes | Superseded by |
|---|---|---|---|---|
| 0010 | Grades stored as published, converted approximately at read time | 2026-08-18 | — | — |
| 0009 | A social feed, firewalled from the guidebook — engagement never touches guidebook data | 2026-08-18 | — | — |
| 0008 | Containers, design components, primitives — boundaries enforced by ESLint | 2026-08-17 | — | — |
| 0007 | No accounts in v1; a local device identity, external provider later | 2026-08-17 | — | — |
| 0006 | A full preview stack on every pull request | 2026-08-17 | — | — |
| 0005 | Documentation as MDX in the repo, rendered by Docusaurus | 2026-08-17 | — | — |
| 0004 | Offline-first on-device SQLite with cursor-based delta sync | 2026-08-17 | — | — |
| 0003 | Expo-managed React Native, iOS first | 2026-08-17 | — | — |
| 0002 | Cloudflare Workers + D1 for the backend | 2026-08-17 | — | — |
| 0001 | One repository, pnpm workspaces | 2026-08-17 | — | — |
Writing one
Ask first. Then copy the template and number it with the next free integer.
Keep it short — a page, not an essay. The sections that earn their place are Context (what forced a decision), Consequences (what this costs us), and Alternatives (what we did not do and why). A rejected alternative documented here does not have to be re-argued in six months.
Then add a row at the top of the table above, and add the page to apps/docs/sidebars.ts.
Superseding one
- Ask first — reversing a decision is exactly the kind of thing that needs confirming.
- Write the new record. Explain what changed: new information, a new constraint, or the original reasoning simply not holding.
- Fill in the old record's
Superseded byrow and link forward. Add aSupersedeslink on the new one. - Update the table so the new record sits above the old one, and note the supersession in both rows.
Do not edit the old record's reasoning. It was what we thought at the time, and that is the information worth keeping.
Rejected ideas
An idea we considered and declined does not get its own record — it goes in the Alternatives considered section of whichever ADR it lost to. That keeps the decision and the roads not taken in one place, which is where someone re-litigating it will look.