Skip to content

How to record a decision with an ADR

Record an architectural decision with a durable tradeoff, sequential identifier, and index entry.

Use this when: You’ve made (or are formally proposing) an architectural decision with a concrete tradeoff and need it durably recorded in the repository’s decision-record surface. Prerequisites: governance-extras pack installed and a decision that is architectural in scope, made, and has a real tradeoff — see Prerequisites below. Result: A confirmed ADR file in the resolved decision-record destination with its row added to that destination’s index, ready for sign-off and acceptance.

You made an architectural call — a database choice, a process commitment, a structural rule the team will live with — and the next person to ask “why did we do it this way?” deserves an answer in writing. The new-adr skill first resolves the portable decision-record destination, then drafts an Architecture Decision Record there from the bundled template with that destination’s next sequential number. It pushes back on hand-wavy sections before you commit.

Use the new-adr skill to write an ADR for choosing PostgreSQL for the order service.

This guide is task-oriented; for the why of ADRs (immutable history vs. living docs), read docs/CONVENTIONS.md § ADR. For where ADRs sit in the wider doc system, see the core pack as a system.

The two skills look adjacent and confuse readers regularly. The split is about time, not topic:

PropertyADR (new-adr)RFC (new-rfc)
Direction in timeBackward-looking recordForward-looking proposal
State of the decisionMade (or about to be made)Under debate; may be rejected
After acceptanceBody frozen at acceptance; Status: header still mutableBody frozen at acceptance (status field mutable); spawns ADRs, specs, convention edits
Change mechanismNew ADR that supersedes the old; status of the old flips, body staysNormal revision until accepted, frozen thereafter

If the call is already made (or you’re recording one made in a meeting yesterday), it’s an ADR. If you want a debate, it’s an RFC — and the accepted RFC then produces one or more ADRs as follow-on. See how to propose a change (RFC) for the inverse view.

  • A repository destination that Core can resolve for decision-record, including an explicit policy-permitted destination supplied as resolver evidence. Existing custom locations win; docs/adr/ is a fallback offer and is never created silently. Without compatible Core, the skill returns a zero-write handoff even when you confirm its evidence.
  • A decision that genuinely warrants an ADR — the entry-point prose below covers the test.

Bring the upstream material that informed the decision: a shaped intent from docs/product/intents/, a decision brief, a research survey or brief, or an architecture concept or reference architecture. Cite that artifact in the ADR; the citation is what makes the decision traceable later.

Three conditions, all must hold:

  1. The decision is about architecture or shared infrastructure, not one feature’s internals. (“We use Postgres for the primary store” is an ADR; “the saved-filters chip uses URL state, not local storage” is a spec.)
  2. The decision has been made (or is being formally proposed for acceptance). ADRs are not the venue for open-ended discussion — that debate belongs in an RFC.
  3. There is a concrete tradeoff. At least one viable alternative was considered. If only one option exists (“we use UTF-8”), you don’t need an ADR.

If any of these fails, push back rather than writing an ADR that future readers will discount. The skill checks them at invocation time.

Two worked invocations that genuinely differ:

use the new-adr skill to record our choice of Postgres over DynamoDB
for the user-activity store

(technology choice — the alternatives section will weigh DynamoDB, SQLite, and a managed warehouse against the team’s Postgres familiarity.)

use the new-adr skill to record our decision to use trunk-based
development with short-lived feature branches

(process choice — the alternatives section will weigh GitFlow and release-branch models against the team’s deploy cadence.)

Natural phrasings (let's ADR this, write an ADR for X, record this decision) match the skill’s description and often trigger it, but description matching isn’t guaranteed. Lead with use the new-adr skill to … whenever you want the discipline to fire reliably.

Step 2 — Confirm the three preconditions

Section titled “Step 2 — Confirm the three preconditions”

Before the skill scaffolds anything, it asks (explicitly or implicitly) about architecture-not-feature, decided-not-debated, and real-tradeoff. If you can’t answer cleanly, the skill pushes back. Two common redirects:

  • “This is still being debated.” → open an RFC instead. The accepted RFC then produces the ADR as follow-on.
  • “This is about a single feature’s internals.” → write a spec (new-spec), not an ADR.

Step 3 — Resolve the destination, then find its next ordinal

Section titled “Step 3 — Resolve the destination, then find its next ordinal”

Before it reads an ADR directory or chooses identity, the skill asks compatible Core for semantic-surface-resolution.v1 with role decision-record. The resolver honors an explicit permitted destination, repository policy or configuration, established repository convention, and established external destination—in that order—then stops for ambiguity or offers selection/creation on absence. Mandatory policy rejects a conflicting explicit path. One example does not establish a convention, and no terminal result creates a directory, index, or configuration.

Only after a confined repository destination resolves does the skill run its bundled scripts/next-ordinal.py helper against that directory. It prints the next 4-digit ordinal—0001 if the destination has no ADRs, max-plus-one otherwise. Numbers are sequential within the resolved destination and never reused. The helper parses the full digit prefix, so transitions like 00990100 work correctly without manual zero-padding. External destinations remain external; without an authorized write adapter, the skill returns a portable handoff instead of probing or writing them.

The skill then picks a short kebab-case filename from your description (0007-primary-store-postgres-over-dynamodb.md, not 0007-decision-about-the-database.md). It does not create the file yet: it drafts the ADR, shows you a preview, and waits for your confirmation before writing anything (see Preview and confirm below). The H1 title inside names the problem and the chosen solution together (keeping the ADR-NNNN ordinal), so the decision reads clearly from the index. The skill keeps it short — the title identifies the decision rather than encoding the whole rationale (that lives in the Decision section); a title that compresses the whole argument into a clause makes the index hard to scan.

Status starts as Proposed. Today’s date. Decision-makers are the people who own the call, identified however your team does — a name, a GitHub handle, or an email (don’t assume GitHub handles unless your conventions require them); add Consulted (whose input was sought, two-way) and Informed (who is kept up to date, one-way) when the decision was run past others, and delete those two lines otherwise. Supersedes: is none for a greenfield ADR; otherwise the ADR number being replaced (see Variations). Keep Consulted and Related pointer-like — short lists of handles and ADR/RFC/spec references, not prose; if a relationship needs explaining, that explanation goes in Context or References, not the frontmatter.

If your request arrives tangled — rationale, history, and several sub-decisions in one breath — the skill first reflects back a short decision frame (the decision in a sentence, the problem it resolves, the alternatives, the winning driver, what you’re giving up) to isolate the call before drafting; when the decision is already crisp it skips the frame and drafts straight away. It then walks you through Context, Decision, Consequences, and Alternatives, and offers several optional fields — included when they earn their place, dropped otherwise:

  • Decision summary — a first-screen TL;DR (Decision / Because / Applies to / Tradeoff accepted / Revisit if) placed before Context. The skill offers it once the ADR is long enough that the decision isn’t visible on the first screen — a multi-line title, a paragraph of metadata, or a long Context push it down — and skips it on a short ADR, where the five restated lines would be pure redundancy. Every line restates the body, so it never carries new reasoning; when it’s present, its Revisit if: restates the Consequences line verbatim.
  • Revisit if — a named trigger in Consequences for when the decision should be reconsidered (a new constraint, a failed confirmation, a scale threshold). This is its canonical home, so it survives deletion of the optional summary; the skill recommends it for any decision likely to age, and writes the explicit Revisit if: stable — no foreseeable trigger for one that genuinely won’t, rather than dropping the line.
  • Decision drivers — the criteria the choice was judged against, so each alternative is rejected against a stated criterion rather than an ad-hoc reason.
  • Confirmation — how conformance with the decision will be verified, structured as Mode / Signal / Owner (with Mode one of reviewer-checked | lint/CI | architecture fitness test | periodic audit | none). Where you’d plausibly expect a conformance mechanism, the skill prefers an explicit Mode: none with a one-line reason over silently deleting the section — a non-checkable residual stays visible — and drops the section only for trivial decisions where no one would expect a check.

None of these is mandatory. The skill pushes back on hand-wavy required sections rather than accepting them:

  • Context with no listed constraints → the skill asks what’s actually constraining the choice. “We need a database” isn’t context; “~10M records, query by user_id and time range, team of two who know Postgres” is.
  • Decision without a single declarative sentence at the top → the skill asks you to write one. (“We will use Postgres as the primary data store for user activity.”)
  • Consequences with only positives → the skill asks what you’re giving up. Honest negatives are what save the next person from re-litigating the choice.
  • Alternatives without rejection reasons → the skill asks why each was rejected. One sentence each is enough; the point is to show future readers you considered the option they’re about to suggest.

The skill adds a row to the resolved destination’s sibling index so the new ADR appears in its established table. For the catalogue fallback only, that index is docs/adr/README.md.

Step 7 — Get sign-off, then mark Accepted (or Rejected)

Section titled “Step 7 — Get sign-off, then mark Accepted (or Rejected)”

The skill leaves status as Proposed and tells you to flip it to Accepted once the decision-makers have signed off — usually in the same PR, sometimes in a follow-up commit. If the proposal is declined, mark it Rejected and keep the file: a recorded rejection stops the same option being re-proposed later. Once Accepted, the body is frozen. See the immutability mechanic below.

new-adr never writes silently. Before it creates the ADR file or touches the index, it shows you a preview — the proposed identifier (ADR-NNNN), the status (Proposed), the target path (absolute and repo-relative), the index path it will update, and the drafted content — and waits for your explicit confirmation. Nothing lands on disk until you approve. After it writes, it hands back a short completion receipt: the identifier, the file path, the index path, the status, the files changed, the owner (the decision-maker), and the next step — get sign-off, then flip to Accepted.

ADRs differ from wiki-style docs in one load-bearing way: once accepted, the body is never edited. This is what makes ADRs a durable record rather than a moving target.

The status field can move: ProposedAccepted or Rejected, and an Accepted ADR later to Deprecated (the decision no longer applies and nothing replaces it) or Superseded by ADR-NNNN (a specific later ADR replaces it). The body text stays put. If the decision is reversed or revised, you write a new ADR that supersedes the old one, with explicit cross-references in both directions, and update the old ADR’s Status: header — header only, body untouched. The old text remains visible as historical record; the new ADR carries the current reasoning.

This is the difference between an ADR and documentation. Documentation should match present truth; ADRs preserve why we got here.

Recording a decision made just now (the common case)

Section titled “Recording a decision made just now (the common case)”

You’re capturing the call before the details fade. The decision is fresh in everyone’s head; the skill’s pushback on hand-wavy sections costs the least here. Invoke right after the meeting where the choice landed.

A maintainer joins, asks “why are we doing it this way?” and there’s no good answer in writing. Open an ADR now anyway — backfilling is fine. Reconstruct Context from memory and Git history; list the Decision-makers as the people who actually decided (not you, unless you were in the room); note in References that the ADR is being backfilled. The content matters more than the freshness.

A previously-accepted ADR no longer reflects the team’s call. You do not edit the old ADR’s body. Instead:

  1. Run new-adr for the new decision. In Context, name the prior ADR you’re superseding and what changed since it was written.
  2. Set the new ADR’s frontmatter Supersedes: to the old ADR’s number.
  3. After the new ADR is Accepted, update the old ADR’s frontmatter Status: from Accepted to Superseded by ADR-<NNNN> — with the actual four-digit number of the new ADR substituted in. Leave the old body alone — it’s history.

If the reversal is contested or non-obvious, the reversal should go through an RFC first; the accepted RFC then produces this superseding ADR as follow-on. See docs/CONVENTIONS.md § RFC for the trigger conditions.

The RFC carried the debate; its accepted outcome lists “one or more ADRs to record the architectural decisions” as follow-on artifacts. Run new-adr per architectural decision named, cite the RFC in Related:, and let the RFC carry the prior-art and alternatives weight — the ADR’s Alternatives considered can be terse when the RFC already exhausted them.

  • The decision is still being debated. Use new-rfc — RFCs carry the debate; ADRs record the outcome. The accepted RFC then produces the ADR.
  • The decision is about a single feature’s internals. Use new-spec — feature-internal choices live in docs/specs/<feature>/spec.md under Boundaries or Testing Strategy.
  • The decision is trivial or has only one sensible option. (“We use UTF-8.”) No ADR needed. Don’t manufacture decisions to document.
  • Documenting how something works today. That’s the repository’s resolved current-architecture surface, not its decision-record surface. ADRs are why we made the call; current architecture is what the implemented system looks like now.

You have a confirmed ADR in the resolved decision-record destination and a row in its index. Seek acceptance for the record, then create a superseding ADR if the durable decision changes.