Decision Records (ADRs)
How to capture architectural decisions, why they were made, and the trade-offs accepted — so future engineers and agents understand the reasoning, not just the result.
Code shows what was built. Decision records show why. Without them, the team inherits constraints with no explanation — and either blindly preserves them or inadvertently dismantles them.
An Architecture Decision Record (ADR) is a short document that captures one architectural decision: the context, the options considered, the choice made, and the trade-offs accepted. They don’t need to be long. They need to be honest.
When to write an ADR
Write an ADR when a decision is:
- Hard to reverse — switching databases, changing auth strategy, adopting a new framework
- Non-obvious — someone reading the code later wouldn’t be able to reconstruct the reasoning
- Contested — there was a real debate and the losing arguments have value
- Consequential — other decisions will depend on it, explicitly or implicitly
Don’t write ADRs for trivial choices. The signal-to-noise ratio matters.
ADRs as context for agents
When an agent is implementing a feature, it will make micro-decisions that should be consistent with your prior architectural choices. Include relevant ADRs in the design.md context for significant changes. The agent will respect constraints it knows about.
The format
# ADR-[number]: [Short title]
**Date:** YYYY-MM-DD
**Status:** Proposed | Accepted | Superseded by ADR-XXX | Deprecated
## Context
What is the situation that forces this decision? What constraints exist?
What problem are we solving? Keep this factual.
## Decision
What did we decide to do?
State it clearly and directly.
## Options considered
### Option A: [name]
- Pro: ...
- Con: ...
### Option B: [name] (chosen)
- Pro: ...
- Con: ...
### Option C: [name]
- Pro: ...
- Con: ...
## Consequences
What becomes easier? What becomes harder?
What trade-offs are we accepting?
What does this decision make impossible?
Example
# ADR-004: Use event sourcing for the Orders context
**Date:** 2025-03-12
**Status:** Accepted
## Context
The Orders context requires full audit history for compliance. We need to
reconstruct order state at any point in time for dispute resolution. The
current approach (mutable state + audit log table) requires maintaining two
separate sources of truth that drift.
## Decision
Use event sourcing for the Orders aggregate. All state changes are stored as
immutable domain events. Current state is derived by replaying events.
## Options considered
### Option A: Mutable state + audit log table
- Pro: Simple, familiar, easy to query current state
- Con: Two sources of truth that can drift; can't reconstruct intermediate states
### Option B: Event sourcing (chosen)
- Pro: Single source of truth; full history by design; audit compliance built-in
- Con: More complex query patterns; requires event versioning strategy; learning curve
### Option C: Temporal tables (database-level)
- Pro: No application-level complexity
- Con: Vendor-specific; doesn't capture domain semantics; migration risk
## Consequences
**Easier:** Audit compliance, state reconstruction, debugging production issues
**Harder:** Querying current state requires projection; schema evolution requires versioning
**Accepted trade-off:** We add complexity to the Orders context to get correctness guarantees
**Made impossible:** Direct UPDATE on order rows — all changes go through events
Where to store ADRs
docs/
decisions/
ADR-001-use-postgresql-as-primary-database.md
ADR-002-hexagonal-architecture-for-all-services.md
ADR-003-conventional-commits-enforced-in-ci.md
ADR-004-event-sourcing-for-orders-context.md
Keep them in the repository, versioned with the code. An ADR that lives in Notion or Confluence will drift from the codebase. One that lives in the repo gets read when it matters: during code review.
ADR lifecycle
| Status | Meaning |
|---|---|
| Proposed | Under discussion — not yet decided |
| Accepted | Decision made, currently in effect |
| Superseded | Replaced by a newer ADR (link to it) |
| Deprecated | Was once relevant, no longer applies |
Never delete ADRs. The history of what was tried and rejected is valuable. Mark them as superseded and link to the replacement.
Integration with OpenSpec
When a design document makes a significant architectural choice, create an ADR for it. Reference the ADR from the design document:
## Architecture decisions
The Orders context uses event sourcing for state management.
See: [ADR-004](/docs/decisions/ADR-004-event-sourcing-for-orders.md)
This way, the decision is captured at the moment it’s made — not reconstructed from memory six months later.
ADR for agent-made decisions
Agents make architectural decisions during implementation, often silently. If you notice the agent made a non-obvious structural choice, create an ADR for it explicitly — either confirming the choice or documenting why you’d do it differently.
The goal isn’t bureaucracy. It’s that the next engineer (or the next agent session) doesn’t have to reverse-engineer intent from structure alone.