cc-os/docs/adr-system/02-external-research.md

179 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# External Research: ADR Best Practices & Claude Code Integration
_Last updated: 2026-07-03_
Two research passes: (1) general ADR best practices independent of any AI tooling, (2) how
Claude Code / AI-coding-agent users specifically have integrated ADRs. Gathered by web-research
agents, 2026-07-03. Claims marked **[unverified]** were not independently checked against a
primary source in this pass — verify before relying on a specific tool/repo name.
---
## Part A — General ADR Best Practices
### 1. File/directory organization
Industry consensus favors **one-file-per-decision** over a monolithic running log, following
Michael Nygard's original 2011 convention: sequential numbered files (`0001-title.md`, …) in
`doc/adr/`, stored alongside code in version control ([Cognitect
Blog](https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions)). MADR refines
this with timestamped naming for sortability ([MADR docs](https://adr.github.io/madr/)).
Tradeoffs at scale:
- **Advantages**: immutable per-decision history, shallow git diffs (no merge conflicts on a
shared log file), sequential numbering creates a shared "decision language."
- **Disadvantages**: filesystem clutter past ~200 decisions, usually addressed with
subdirectory categorization (e.g. `decisions/backend/`).
Tools handle discoverability differently: **adr-tools** (bash, Nygard format) has no built-in
index, relying on naming discipline; **Log4brains** (Node.js) auto-generates a searchable
dashboard from git metadata with no enforced numbering; **Backstage** (Spotify's platform)
indexes ADRs across many repos for org-wide visibility. Across all of them, the common
discoverability mechanism is an `overview.md`/`README.md` table (title + status + date) plus
explicit `Supersedes:` / `Superseded by:` cross-links in each file.
No evidence surfaced of a monolithic single-file ADR log surviving past ~30 decisions in active
use **[unverified — multiple practitioner blogs, no single primary source]**; this is directly
relevant to cc-os's own 19-ADR, 601-line file trending toward that threshold.
### 2. Content template best practices
Three templates dominate:
- **Nygard minimal**: Status · Context · Decision · Consequences. Lowest friction, fits one
page; weaker audit trail since alternatives aren't a first-class section.
- **MADR (Markdown ADR)**: adds Decision Drivers, Considered Options (with pros/cons per
option), and RACI-style metadata (Deciders, Consulted, Informed). Two pages typical; the
de-facto default for teams >15 engineers or audit-sensitive contexts.
- **Y-Statements**: one paragraph — "In the context of `<use case>`, facing `<concern>`, we
decided for `<option>` and against `<alternatives>`, to achieve `<benefits>`, accepting
`<trade-offs>`." Writable in ~90 seconds; a lightweight complement, not a replacement, for
per-project decisions that don't warrant a full ADR.
What makes an ADR *useful later* rather than a wall of text nobody rereads:
1. **Status field** (Proposed/Accepted/Rejected/Superseded/Deprecated) — signals actionability
at a glance; accepted ADRs are treated as immutable, new insight → new ADR, not an edit.
2. **Alternatives-considered with reasoning** — the rejected options are often *more* valuable
to a future reader than the chosen one, because they prevent re-litigating a
already-evaluated path.
3. **Strong, short titles** ("Use PostgreSQL over MongoDB for user data," not "Database") —
enables index-skimming and grep.
4. **Explicit `Supersedes:` / `Superseded by:` cross-references** — prevents accidentally
applying an obsolete decision.
5. **Component/domain tagging** (`affected-components: [auth, api-gateway]`) — enables
filtering once ADR count exceeds ~50 **[unverified — inferred from MADR template fields]**.
6. **Deciders/date accountability** — prevents orphaned decisions once people leave.
Format-selection heuristic **[unverified, single secondary source]**: Nygard for <15-person
teams; MADR for 1550; MADR + tool-generated index for >50 or regulated industries;
Y-Statements for small per-project decision counts.
### 3. Lifecycle and governance
**When to write one** (Spotify engineering: "write an ADR whenever a decision of significant
impact is made; each team aligns on what 'significant' means" —
[source](https://engineering.atspotify.com/2020/04/when-should-i-write-an-architecture-decision-record)):
hard-to-reverse decisions, decisions affecting >1 team/service, decisions with real tradeoffs
and no obvious right answer, a question that's been re-litigated more than once (a sign of
undocumented institutional knowledge), non-functional requirements (security, availability,
latency). **When not to**: routine implementation choices, single-service decisions with no
cross-team impact, things already covered by standing policy.
**Immutability + supersession** (AWS Prescriptive Guidance): once Accepted, an ADR is
immutable. A conflicting new decision gets a *new* ADR in Proposed state with a
`Supersedes: ADR-NNNN` header; once accepted, the old ADR's status flips to `Superseded by
ADR-MMMM` and it stays in version control as history. "Deprecated" is a distinct state (the
decision is no longer relevant, e.g. the system was decommissioned) from "superseded" (replaced
by a newer decision).
**Review**: lightweight, PR-comment-style review (1015 min/ADR), not a formal approval board;
the author owns the final call rather than requiring full consensus (consensus causes scope
creep and decision fatigue).
**Keeping adoption high**: the #1 adoption barrier is template bloat — "a template that takes
an hour to fill out will not get used" (AWS). Practices: store ADRs in the code repo (not a
wiki), write them *during* the decision (not retroactively), markdown-only, provide a
copy-paste starting template, and periodically (e.g. quarterly) sweep for stale/undocumented
decisions.
**Sources**: [Cognitect/Nygard](https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions),
[Martin Fowler bliki](https://martinfowler.com/bliki/ArchitectureDecisionRecord.html),
[MADR](https://adr.github.io/madr/),
[AWS Prescriptive Guidance](https://docs.aws.amazon.com/prescriptive-guidance/latest/architectural-decision-records/adr-process.html),
[Spotify Engineering](https://engineering.atspotify.com/2020/04/when-should-i-write-an-architecture-decision-record),
[Log4brains](https://github.com/thomvaill/log4brains),
[Y-Statements](https://medium.com/olzzio/y-statements-10eb07b5a177).
---
## Part B — Claude Code / AI-Agent Integration
### 1. Existing plugins/skills/MCP servers for ADRs **[names unverified — not independently confirmed in this pass]**
- **adr-kit** (`github.com/rvdbreemen/adr-kit`) — drop-in Claude Code toolkit; treats ADRs as
active guardrails, not passive docs.
- **zircote/adr** (GitHub) — lifecycle management across 7 template formats (MADR, Nygard,
Y-Statement, Alexandrian, Business Case…), with compliance auditing.
- **claude-plugin-adr** (`github.com/andronics/claude-plugin-adr`) and a plain
"architecture-decision-records" skill on a Claude plugin hub — basic creation workflows.
- An open Claude Code GitHub feature request (**issue #13853**) asks for native ADR support:
auto-loading records from `~/.claude/adr/` the same way `CLAUDE.md` auto-loads.
- **mcp-adr-analysis-server** (`github.com/tosin2013/mcp-adr-analysis-server`) — an MCP server
(agent-agnostic, not Claude-Code-specific) with 15 tools for reading/creating/managing ADRs,
using Tree-sitter AST analysis and secret-masking.
### 2. Triggering ADR creation
Most real-world usage is **reactive**, driven by an explicit user command (e.g. `/record-adr`),
not autonomous. adr-kit adds a smart-detection layer on top: `/adr:review` diffs commits
against existing ADRs to flag undocumented architectural changes; `/adr:init` audits an
existing codebase for decisions already "in effect" in the code and proposes batching them as
backfilled Accepted ADRs. One practitioner write-up (`beyondautocomplete.nl`) reports the
`/record-adr` flow takes 3060 seconds per decision and asks clarifying questions when context
is thin — but complex multi-decision changes still need to be split into separate invocations
manually.
### 3. Selective retrieval (avoiding context bloat)
This is the most directly relevant finding for cc-os's third HMW. Patterns observed:
- **Ranked, task-scoped filtering**: adr-kit's `adr-context` tool returns only the 35 most
relevant *Accepted* ADRs, using weighted signals — file-path/glob match against an ADR's
declared "enforcement path" ranked highest, keyword relevance second.
- **In-flight, path-triggered nudges**: an `adr-watch`-style mechanism surfaces an ADR only
when an edit touches a path the ADR governs — i.e., deterministic path matching rather than
semantic search for the common case.
- **Knowledge-graph retrieval**: converting ADRs into graph nodes lets a query find
*structurally* related decisions ("all ADRs that depend on this infra decision"), which is a
different (and complementary) axis to keyword/semantic similarity. This is directly relevant
to cc-os since Graphify is already the chosen knowledge-layer engine (ADR-010) — an ADR
system could plausibly be *another* node type in the same graph rather than a separate
retrieval mechanism.
- **Hook-based conditional injection**: a `SessionStart`/similar hook can filter which ADRs get
injected based on what files are about to be touched, keeping the default-context footprint
near zero and only pulling in ADRs when a matching path is active — architecturally identical
to cc-os's own lazy-freshness pattern (ADR-007).
- **Status-based filtering**: only surfacing `Accepted` ADRs by default; `Proposed` and
`Superseded` stay out of default retrieval paths.
### 4. Community sentiment / pain points **[incident detail unverified — single source, not independently confirmed]**
A recurring tension: ADRs record "why we decided," but an autonomous agent often needs
enforceable "what must never happen" constraints, which prose ADRs don't provide — cited as
part of the motivation for `AGENTS.md`-style "project constitution" files that encode operable
rules rather than narrative history. A cited (but unverified in this pass) Replit incident from
2025 describes an agent running `DROP DATABASE` despite an archived freeze decision, offered as
an argument that ADRs-as-prose are not a substitute for deterministic guardrails.
Separately, one source (MemU, 2026) claims **~2% context-retention loss per agent step**,
with tool-definition overhead alone consuming a large share of context on typical MCP setups
— cited as the underlying argument for "don't dump ADRs into context, filter them." Treat these
specific numbers as **[unverified]** (single-source, not cross-checked here), but the
qualitative point — naive full-ADR-dump retrieval degrades badly as ADR count grows — matches
both this repo's own experience (the 601-line `03-architecture-decisions.md` file) and the
structured-retrieval patterns in item 3 above.
**Sources**: adr-kit, zircote/adr, claude-plugin-adr, mcp-adr-analysis-server (GitHub repos,
names as given, not independently re-verified), Claude Code issue #13853,
[beyondautocomplete.nl write-up](https://www.beyondautocomplete.nl/how-i-use-claude-code-to-keep-my-architecture-decisions-on-track/),
Graphify/GraphRAG background, [Claude Code hooks docs](https://code.claude.com/docs/en/hooks),
`agentpedia.codes` AGENTS.md article, `thebcms.com` spec-driven-development article.