# Decision Records

> Write RFC and ADR documents to capture technical decisions (including rejected alternatives) — Context / Options / Decision / Consequences format. Use before a hard-to-reverse architecture decision, when designing a large feature, when technical choices spark debate, or when PR reviewers request rationale. Not for evaluating a library to adopt (use new-tech-evaluation) or prioritizing debt migrations (use tech-debt-management) — this records the resulting decision.

- Skill: `jaykim88/decision-records` (Agent Skill)
- Install (CLI): `npx skillmds@latest add jaykim88/decision-records`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jaykim88/decision-records/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- License: MIT
- Author: JayKim88 (https://skillmd.com/u/jaykim88)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/jaykim88/decision-records

---


# Decision Records (RFC / ADR)

## Purpose
Make technical decisions auditable. The "why we chose X" should not require asking the engineer who chose it — it should be retrievable from the repo.

**Universal** — RFC/ADR format is framework-agnostic; only the *types* of decisions worth recording vary slightly per stack.

## Procedure

1. **Pick the format: RFC vs ADR**
   - **RFC** (Request for Comments): proposes change BEFORE implementation, opens discussion
   - **ADR** (Architecture Decision Record): records decision AFTER it's made
   - Both can coexist; ADR often follows from accepted RFC
   - **Decision trigger — weight the process by reversibility** (Bezos's one-way vs two-way doors): a hard-to-reverse / costly-to-undo "one-way door" decision, or one 2+ engineers must weigh in on, warrants an **RFC** before commitment. A cheap-to-reverse "two-way door" needs at most a short ADR.
   - **Don't write an ADR for everything** — over-documentation rots the same way an unread debt registry does (see `tech-debt-management`). Reserve records for *significant, contested, or hard-to-reverse* decisions; trivial/local choices need only a code comment or the PR description. Keep each to ~1 page.
   - **RFC workflow**: draft → circulate → a *fixed comment period* → decision (with a deadline, or it stalls forever) → the accepted RFC becomes or produces an ADR.

2. **Use the standard ADR template (Nygard)** for simple, decided-by-conversation calls
   ```markdown
   # ADR-NNN: <decision title>

   **Status**: Proposed / Accepted / Rejected / Deprecated / Superseded by ADR-XXX
   **Date**: YYYY-MM-DD
   **Deciders**: <who made the call>

   ## Context
   What problem prompts this decision? Constraints, requirements, who's affected.

   ## Decision
   We chose X.

   ## Consequences
   - Positive: <gains>
   - Negative: <costs / risks>
   ```

   **For decisions with 3+ real alternatives, prefer MADR** (Markdown Architectural Decision Records) — adds explicit decision drivers and per-option pros/cons evaluation:
   ```markdown
   # ADR-NNN: <decision title>

   ## Status: Accepted | Date: YYYY-MM-DD

   ## Context and Problem Statement
   ## Decision Drivers
   - Driver 1, Driver 2, ...

   ## Considered Options
   - Option A: pros / cons
   - Option B: pros / cons
   - Option C: pros / cons

   ## Decision Outcome
   Chosen option: "B", because <evaluation summary>.

   ## Consequences
   ```

3. **For frontend specifically, the high-leverage ADR types** (universal across React/Vue/Svelte/Angular)
   - **State management strategy** — see `state-management-decisions`
   - **Render strategy per route family** (server-rendered vs static vs client-only) — see `render-strategy-decision`
   - **Styling system** (utility-first like Tailwind, CSS-in-JS, CSS Modules)
   - **Form approach** (server-driven vs client-validated) — see `form-ux`
   - **Auth strategy** (cookies vs JWT vs platform auth like Supabase/Auth0/Clerk)

4. **Link decisions back to code**
   - Reference ADR number in code comments: `// See ADR-007 for why we use Zustand here, not Context`
   - In commit messages: `feat(state): migrate user profile to Zustand [ADR-007]`

5. **Treat ADRs as living documents**
   - When context shifts: append a dated note rather than rewriting
   - When decision is superseded: mark Status as "Superseded by ADR-XXX" and keep the file (history matters)
   - Full status set: Proposed / Accepted / **Rejected** / **Deprecated** / Superseded — and **record rejected decisions too**: "we considered X and rejected it because Y" is what stops the team re-litigating the same debate in six months
   - Never silently delete an ADR — the history of "why we no longer do this" is itself valuable

6. **Make ADRs accessible**
   - Store in `docs/adr/` directory in the repo
   - Index file (`docs/adr/README.md`) listing all ADRs with one-line summaries
   - Numbered sequentially (ADR-001, ADR-002, ...)

7. **Write for the absent reader**
   - Assume reader has zero context
   - Avoid jargon without definition
   - State trade-offs honestly — list the cost of the chosen option, not just benefits
   - The highest-value content is *why the alternatives were rejected*, not just why the winner won — that's what prevents re-debate. Keep it short (~1 page); long ADRs don't get written or read

## Completion Criteria
- [ ] ADR follows Context / Options / Decision / Consequences format
- [ ] Process weighted to reversibility — no ADR ceremony for trivial/easily-reversible choices
- [ ] Trade-offs documented honestly (cost of chosen path stated)
- [ ] Rejected alternatives and their rationale recorded (not just the chosen option)
- [ ] Related code references the ADR number
- [ ] Indexed in `docs/adr/README.md`
- [ ] Reviewers (or future-self) can understand without external context

## Output
- **ADR file**: `docs/adr/ADR-NNN-<kebab-case-topic>.md` following Nygard (simple) or MADR (3+ alternatives) template
- **Index entry**: append one line to `docs/adr/README.md` — `- [ADR-NNN: <title>](ADR-NNN-<topic>.md) — <status> — <one-line summary>`
- **Inline code reference**: `// See ADR-NNN for rationale` at affected decision points
- **Commit format**: `docs(adr): ADR-NNN <title>` — keep ADR additions in their own commit, separate from code changes that reference them
- **Status updates**: when superseded, edit Status field and append `## Notes` subsection with date + reason (don't delete old ADRs)

## Implementation

### React + Next.js (default)
- Store ADRs in `docs/adr/` (or `docs/architecture/decisions/`)
- Number sequentially (`ADR-001`, `ADR-002`, ...)
- Link from code via comment: `// See ADR-007 for rationale`
- Tooling (optional): `adr-tools` or `log4brains` automate numbering + index generation; otherwise keep it manual
- High-leverage ADR types for this stack: Zustand vs Context vs TanStack Query; SSR vs SSG vs ISR per route; Tailwind vs CSS-in-JS

### Other stacks
- **Vue / Nuxt**: same ADR location and numbering; high-leverage types: Pinia vs provide/inject vs TanStack Query; Nitro server presets; useFetch caching strategy
- **SvelteKit**: same; high-leverage types: Svelte stores vs context vs +server load patterns; prerender vs ssr per +page.ts
- **Angular**: same; high-leverage types: signals vs RxJS vs NgRx; standalone vs NgModule; lazy-loading boundaries
- **All stacks**: ADR format itself is framework-agnostic — only the *examples* of decision types differ. The Nygard and MADR templates work for any technical decision

## Related skills
- `new-tech-evaluation` — every adoption/rejection of a library produces an ADR
- `tech-debt-management` — large debt migrations need an ADR for the chosen approach

## Reference
- **Key insight encoded**: Treat ADRs as living documents — append dated notes when context shifts rather than rewriting. For frontend, the high-leverage ADR types are state-management strategy, render strategy (SSR/SSG/ISR/CSR), and styling-system choice — these decisions reverberate for years and benefit most from explicit rationale. Weight the process by reversibility (one-way vs two-way doors) and don't over-document — an unread pile of trivial ADRs rots like a stale debt registry. The most valuable content is *why alternatives were rejected*, which is what prevents the same debate resurfacing.

