Skip to content

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

ArtifactAnswersLifespanAgent use
SpecWhat this feature must do / not doUntil feature evolvesImplementation acceptance
ADRWhich option we chose for a cross-cutting design problemUntil supersededAvoid re-proposing rejected options
CLAUDE.mdHow to work in this repo day-to-dayContinuous pruneCommands, 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 consequencesTrivial 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 strategyOne-line bug fix
Multi-agent work needs a shared north starTemporary spike (mark spike explicitly if recorded)

Decision tree — research vs decide vs record

Template (fill-in)

markdown
# 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

markdown
# 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 tenancy

Prompt: agent drafts, human decides

text
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

PracticeWhy
Store under docs/adr/ with numeric prefixesStable greppable paths
Link hot ADRs from CLAUDE.md (≤5 pointers)Loaded every session
Import lint / path ownership where possibleTurns "DO NOT" into a red gate
Supersede, don't silently edit Accepted meaningAgents and humans need history
Mention ADR in feature specs when relevantCloses spec-code + architecture loop

CLAUDE.md fragment:

text
## 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

markdown
- [ ] 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 world

Failure modes

SymptomRoot causeFix
Agent proposes rejected ORM againNo ADR or no CLAUDE.md pointerWrite/link ADR; add never-do
ADR novel-length, unreadToo much essayCompress; move narrative to wiki; keep decision + agent instructions
ADR edited in place to flip meaningNo supersessionNew ADR; mark old Superseded
Agent "Accepted" an ADR in a PRDelegated decisionReject; human status only
Specs contradict ADRDriftReconcile in one PR — Keeping Specs Alive

A field manual for AI-native software engineering.