Architecture Decision Records with Agents
Agents do not remember last quarter's debate about "why we don't use an ORM in the payment path." If the decision isn't in the repo, every session re-opens it — often picking the option you rejected. ADRs are the durable "we decided X because Y" layer. Specs say what a feature must do; ADRs say which structural bets the system is allowed to make.
ADR vs spec vs CLAUDE.md
| Artifact | Answers | Lifespan | Agent use |
|---|---|---|---|
| Spec | What this feature must do / not do | Until feature evolves | Implementation acceptance |
| ADR | Which option we chose for a cross-cutting design problem | Until superseded | Avoid re-proposing rejected options |
| CLAUDE.md | How to work in this repo day-to-day | Continuous prune | Commands, never-dos, pointers to ADRs |
Rule of thumb: if you find yourself pasting the same architectural rationale into prompts twice, write an ADR and link it from CLAUDE.md ("Payment path: see docs/adr/00xx-no-orm-payments.md").
See What Not to Delegate — many ADR topics are human-owned decisions the agent may only research.
When to write an ADR
| Write an ADR when… | Skip when… |
|---|---|
| Two+ viable options with lasting consequences | Trivial library choice with no coupling |
| You rejected an option agents love (ORM, rewrite, new queue) | Purely local naming inside one file |
| Cross-cutting constraint (authn, tenancy, money, idempotency) | Feature-only behavior → use a spec |
| Migration / strangler strategy | One-line bug fix |
| Multi-agent work needs a shared north star | Temporary spike (mark spike explicitly if recorded) |
Decision tree — research vs decide vs record
Template (fill-in)
# ADR <nnnn>: <short title>
- Status: Proposed | Accepted | Superseded by ADR-<nnnn>
- Date: <YYYY-MM-DD>
- Deciders: <names>
- Agent involvement: research only | drafted | n/a
## Context
<What forces this decision? Constraints, symptoms, scale.>
## Decision
<One paragraph: we will X.>
## Consequences
### Positive
- <...>
### Negative / accepted costs
- <...>
### Follow-ons required
- <docs, migrations, CLAUDE.md never-dos>
## Options considered
### Option A — <name>
- Pros: ...
- Cons: ...
- Why rejected / accepted: ...
### Option B — <name>
- ...
## Agent instructions
- DO: <how to comply in code>
- DO NOT: <rejected approaches to stop proposing>
- See also: <paths, specs>The Agent instructions section is the load-bearing addition for agentic teams — classic ADRs omit it and agents keep offering Option B.
Example (abridged) — no ORM in payment path
# ADR 0014: No ORM in the payment path
- Status: Accepted
- Date: 2026-03-02
- Deciders: platform + billing leads
- Agent involvement: researched options; did not decide
## Context
Invoice settlement and Stripe webhook handlers must be auditable line-by-line.
Prior ORM usage hid transactional boundaries and generated N+1s under list+settle.
## Decision
Payment and settlement code under `src/domain/payments/` and `src/api/webhooks/stripe/`
uses hand-written SQL via our `db.query` helper. No Prisma/Drizzle/etc. in these trees.
## Consequences
### Positive
- Explicit transactions; easier audit
### Negative
- More boilerplate; agents will try to "clean up" with an ORM
### Follow-ons
- CLAUDE.md never-do; import lint boundary
## Options considered
### ORM everywhere
Rejected: auditability and surprise queries.
### Hybrid (ORM read, SQL write)
Rejected: still leaks into write path via convenience.
## Agent instructions
- DO: extend `db.query` helpers; add characterization tests for SQL
- DO NOT: add an ORM dependency or import ORM clients into payments/webhooks
- See also: `src/lib/db.ts`, ADR 0009 tenancyPrompt: agent drafts, human decides
Research options for: <decision question>.
Constraints: <list>. Read ARCHITECTURE.md and existing docs/adr/*.
Output:
1. Context summary (evidence from this repo, not generic blog advice)
2. 2–4 options with pros/cons FOR THIS codebase
3. Recommendation with risks — clearly labeled as recommendation only
4. A draft ADR in our template (Status: Proposed)
Do not edit application code. Do not mark Accepted.You set Status to Accepted (or reject). Never let the agent self-accept architectural ADRs. Related: Exploring Options, Constraints and Validation.
Making ADRs executable for agents
| Practice | Why |
|---|---|
Store under docs/adr/ with numeric prefixes | Stable greppable paths |
Link hot ADRs from CLAUDE.md (≤5 pointers) | Loaded every session |
| Import lint / path ownership where possible | Turns "DO NOT" into a red gate |
| Supersede, don't silently edit Accepted meaning | Agents and humans need history |
| Mention ADR in feature specs when relevant | Closes spec-code + architecture loop |
CLAUDE.md fragment:
## Architecture decisions (do not re-litigate)
- Payments SQL only: docs/adr/0014-no-orm-payments.md
- Tenancy: docs/adr/0009-tenant-context.md
If a task conflicts with an ADR, STOP and ask — do not invent a v2 path.Review checklist for new ADRs
- [ ] Decision stated in one paragraph without hedging
- [ ] Rejected options include ones agents commonly propose
- [ ] Agent instructions DO / DO NOT are concrete (paths, deps)
- [ ] Status and deciders set by a human
- [ ] CLAUDE.md pointer added if this will be hit weekly
- [ ] Enforcement noted (lint, review, test) or explicitly "honor system only"
- [ ] Related specs updated if feature work assumed the old worldFailure modes
| Symptom | Root cause | Fix |
|---|---|---|
| Agent proposes rejected ORM again | No ADR or no CLAUDE.md pointer | Write/link ADR; add never-do |
| ADR novel-length, unread | Too much essay | Compress; move narrative to wiki; keep decision + agent instructions |
| ADR edited in place to flip meaning | No supersession | New ADR; mark old Superseded |
| Agent "Accepted" an ADR in a PR | Delegated decision | Reject; human status only |
| Specs contradict ADR | Drift | Reconcile in one PR — Keeping Specs Alive |
Related
- What Not to Delegate — which decisions stay human.
- Exploring Options — research prompts before the ADR.
- Constraints and Validation — turning decisions into checks.
- CLAUDE.md and AGENTS.md — pointers and never-dos.
- Docs as Memory — ADRs as shared memory.
- Keeping Specs Alive — when feature intent vs architecture intent drift.