Authoring Architecture Decision Records
Creates, lists, and supersedes Architecture Decision Records with the adr CLI, following the house ADR template. Use when recording an architectural decision, writing an ADR, documenting a technical choice, superseding a prior decision, numbering a new decision record, bootstrapping an ADR log under docs/adr.
npx tessl install pantheon-ai/adr-creatornpx skills add github:pantheon-org/tekhne --skill documentation--adr-creatorMindset
An ADR is a dated, immutable record of one decision and the forces that shaped it, not living documentation. Its value is archaeological: a reader six months from now must understand why a choice was made without asking anyone. Once accepted, an ADR is never edited to change its meaning. When the decision changes, you write a new ADR and mark the old one superseded, preserving the chain of reasoning.
Two rules make an ADR log trustworthy over time. First, numbering is append-only and gap-tolerant: the next number is always max(existing) + 1, never a count of files, so deleting or archiving a record never reuses an identifier. Second, status is the only mutable field: an accepted decision’s Context and Decision text are frozen; only its Status flips to Superseded when a later ADR replaces it. The adr CLI enforces both rules, which is why you should reach for it rather than hand-writing files that drift from the template.
Treat the template’s section order as a contract. Downstream tooling and reviewers scan for ## Context, ## Decision, and ## Consequences in that order. Reordering or renaming them breaks that expectation even when the prose is good.
Prerequisites
This skill drives the pantheon-adr CLI and is distributed by it
(pantheon-adr skill install). Every step below invokes that binary, so it must
be on PATH. Confirm before proceeding:
pantheon-adr --version
If it is not found, the skill was installed without its companion CLI. Install
the pantheon-adr CLI (its release binary, or cargo install) and retry; there
is no self-contained fallback for these commands.
When to Use
- The user asks to record, write, or draft an architectural or technical decision.
- A significant, hard-to-reverse choice was just made (framework, data store, protocol, boundary) and needs a durable rationale.
- An earlier decision is being replaced and the old record must be marked superseded while keeping its history.
- A repository needs an ADR log bootstrapped under
docs/adr. - A decision already exists in an existing planning or review document (a design doc, a review, a retrospective) and needs to be captured as an ADR after the fact, rather than authored fresh — see Deriving an ADR from an Existing Document.
When Not to Use
- The change is routine and reversible (a dependency bump, a rename, a config tweak). Use a commit message, not an ADR.
- The user wants prose design documentation or a runbook. ADRs capture a single decision, not a system overview.
- A decision is still being debated with no chosen option. Reach a decision first, or record it with status
Proposedonly if the team parks proposals as ADRs.
Principles
- One ADR records exactly one decision. If you are tempted to write “and also”, split it into two records.
- Numbers are assigned by the tool from the highest existing record, never guessed or hand-typed.
- Accepted ADRs are immutable except for their Status line. Supersede, do not rewrite.
- The Context must state the forces at play so the decision reads as inevitable, not arbitrary.
- Alternatives Considered is mandatory evidence of due diligence, even when the answer was obvious.
Procedure
- Locate the ADR directory. Default is
docs/adr; a repository may override it with theADR_DIRenvironment variable or a--dirflag. Confirm which applies before creating records. Verify:pantheon-adr list --dir <path>runs without error. - Create the record. Run
pantheon-adr new "<Title>". The tool computes the next number, slugs the title intoNNNN-kebab-title.md, and stamps today’s date with statusProposed. Verify: the printed path matches the number you expected frompantheon-adr list. - Fill the template in place. Replace the placeholder prose under Context, Decision, and Consequences. Keep every heading; delete only the placeholder bullet text. Stop if: you cannot articulate at least one entry under each of Positive, Negative, and Neutral consequences; that gap means the decision is not yet understood.
- Record alternatives honestly. For each option not chosen, give its pros, cons, and the specific reason it was rejected. An empty Alternatives section fails review.
- Set the final status. Change
ProposedtoAcceptedonce the decision is ratified. Do not touch any other field after acceptance. - Supersede when the decision changes. Run
pantheon-adr supersede <old-number> "<New Title>". This flips the old record’s Status toSuperseded by ADR-NNNNand creates a new Accepted record that references the old one. Verify:pantheon-adr listshows the old record as superseded and the new record directly after it.
Deriving an ADR from an existing document
Sometimes step 3 isn’t a blank page: the decision was already made and
written down in a design doc, review, or planning note, and the task is to
capture it as an ADR rather than author it from scratch. The steps above
still apply — the record is still created with pantheon-adr new and still
goes through the same statuses — but recognizing that a document actually
contains a binding decision, and linking the new ADR back to it for
provenance, takes more care than filling in a decision you just made
yourself. See Deriving an ADR from an Existing Document
for how to spot the decision and record the source link.
Quick Commands
# Create the next-numbered ADR from the house template.
pantheon-adr new "Adopt OpenTelemetry for tracing"
Expected result: prints Created docs/adr/0001-adopt-opentelemetry-for-tracing.md (number varies with existing records).
# List every ADR with its number, status, and title.
pantheon-adr list
Expected result: one line per record, e.g. ADR-0001 Accepted Adopt OpenTelemetry for tracing.
# Supersede an earlier decision, marking it and linking the replacement.
pantheon-adr supersede 1 "Adopt Grafana Tempo for tracing"
Expected result: prints the superseded path and the new Created path; the old record’s Status becomes Superseded by ADR-0002.
# Work against a non-default ADR directory.
pantheon-adr new "Split the monolith" --dir architecture/decisions
Expected result: the record is created under architecture/decisions.
# Find planning documents with a decision that has no ADR pointing back at it.
scripts/check-undocumented-decisions.sh
Expected result: exit 0 with a confirmation line when everything is covered, or exit 2 with a
list of undocumented files when it finds decision-shaped documents that no ADR’s Source: line
references. See Deriving an ADR from an Existing Document.
Anti-Patterns
NEVER hand-number a new ADR
- WHY: Guessing the next number races with other records and reuses identifiers after deletions, corrupting cross-references. The tool derives the number from the highest existing record, which is gap-tolerant.
- BAD: creating
docs/adr/0003-...mdby hand because “there are three files” when the highest existing number is 0005. - GOOD:
pantheon-adr new "...", which assignsmax(existing) + 1. - Consequence: two decisions share ADR-0003 and every link to “ADR-0003” becomes ambiguous.
NEVER edit an accepted ADR to change its decision
- WHY: ADRs are an audit trail. Rewriting the Decision text erases the record that a different choice was once correct and severs the reasoning chain reviewers rely on.
- BAD: opening
0002-...mdand replacing “We will use REST” with “We will use gRPC”. - GOOD:
pantheon-adr supersede 2 "Adopt gRPC for internal services", leaving ADR-0002 intact and marked superseded. - Consequence: history lies; a future reader cannot tell the decision ever changed or why.
NEVER leave the Alternatives Considered section empty
- WHY: The section is the evidence that the decision was weighed against real options. An empty section reads as an unexamined default and fails review.
- BAD:
## Alternatives Consideredfollowed by- N/A. - GOOD: each rejected option with its pros, cons, and the concrete reason it lost.
- Consequence: reviewers cannot judge whether the decision was sound, so they either block it or rubber-stamp it.
NEVER rename or reorder the template headings
- WHY: Tooling and reviewers scan for the exact headings
## Context,## Decision,## Consequencesin order. Renaming## Consequencesto## Trade-offsor moving it breaks that contract. - BAD: replacing
## Decisionwith## What We Chose. - GOOD: keep the heading text verbatim; put your prose beneath it.
- Consequence: automated ADR indexes and diff reviews silently skip your record’s key sections.
NEVER record multiple unrelated decisions in one ADR
- WHY: A record that decides two things cannot be superseded independently. When one half changes you must either fork the record or supersede a still-valid decision.
- BAD: one ADR titled “Database and CI runner choices”.
- GOOD: two records,
... Choose PostgreSQLand... Adopt self-hosted runners. - Consequence: the log tangles; superseding the database choice wrongly retires the CI decision too.
NEVER commit an ADR while its status is still Proposed as if it were final
- WHY:
Proposedsignals an open question. Merging it as the decision of record makes readers act on a choice the team never ratified. - BAD: merging
**Status:** Proposedand treating it as accepted in downstream work. - GOOD: flip the Status to
Accepted(orRejected) once the team decides, then merge. - Consequence: teams build on a decision that was never actually agreed.
References
- ADR Lifecycle — status transitions, superseding chains, and why accepted records are immutable
- CLI Usage — every adr command, its flags, the ADR_DIR variable, and exit behaviour
- Deriving an ADR from an Existing Document — recognizing a binding decision already written down in a design doc, review, or planning note, and linking the new ADR back to it for provenance
- Documenting Architecture Decisions — Michael Nygard’s original essay grounding the ADR practice
- MADR templates — widely used Markdown ADR template variants for comparison
No audit data available.
No eval scenarios available.
ADR Lifecycle
An Architecture Decision Record moves through a small, well-defined set of states. Understanding the transitions keeps the log honest and prevents the two most common failures: editing history and orphaning superseded records.
Status values
| Status | Meaning | Mutable after? |
|---|---|---|
Proposed |
The decision is drafted but not yet ratified by the team. | Yes, until accepted or rejected. |
Accepted |
The decision is in force. Context and Decision text are now frozen. | Only the Status line. |
Rejected |
The proposal was considered and declined. Kept for the record. | No. |
Deprecated |
The decision no longer applies but was not replaced by a specific ADR. | Only the Status line. |
Superseded |
A later ADR replaces this one. The Status names the replacement. | No, beyond the initial supersede. |
Transitions
Proposed ──accept──▶ Accepted ──supersede──▶ Superseded by ADR-NNNN
│ │
└──reject──▶ Rejected└──deprecate──▶ Deprecated
- Accept: flip
ProposedtoAcceptedonce the team ratifies the choice. Change nothing else. - Reject: flip
ProposedtoRejected. Keep the record so the rejected option is not proposed again without context. - Deprecate: use when a decision stops applying but no single ADR replaces it (for example, the subsystem was removed).
- Supersede: the primary transition for a changed decision. It is a two-part, linked operation and should be done with the CLI.
Superseding chains
Superseding never edits the meaning of the old record. It performs two changes atomically:
- The old ADR’s Status becomes
Superseded by ADR-NNNN, pointing forward to its replacement. - A new Accepted ADR is created that references the old one in its Technical Story and Context, pointing backward.
The result is a doubly-linked chain a reader can follow in either direction:
ADR-0002 (Superseded by ADR-0007) ──▶ ADR-0007 (Accepted, Supersedes ADR-0002)
A record may be superseded only once. If ADR-0007 is itself later replaced, it
gains Superseded by ADR-0012; ADR-0002 is left untouched. Never re-point an
old record at a newer replacement, as that hides an intermediate decision.
Why immutability matters
The audit value of an ADR log comes entirely from the guarantee that accepted
text does not change. A reader diffing the log across two release tags must see
new records and Status flips, never silent edits to old rationale. This is why
the tool refuses to rewrite decision text and offers only supersede.
adr CLI Usage
The adr binary creates and manages Architecture Decision Records from the
house template, and installs this companion skill into agent directories. It is
offline and deterministic: every command is a pure function of the ADR
directory’s contents plus the current date.
Directory resolution
Commands resolve the ADR directory in this order of precedence:
- An explicit
--dir <path>flag. - The
ADR_DIRenvironment variable. - The default,
docs/adr(relative to the current working directory).
Set ADR_DIR once per repository to avoid passing --dir on every call:
export ADR_DIR=architecture/decisions
Commands
pantheon-adr new <title>
Creates the next-numbered ADR. The number is max(existing NNNN-*.md) + 1,
starting at 0001. The title is slugged into the file name and rendered into
the heading. The record is stamped with today’s date and status Proposed.
pantheon-adr new "Adopt OpenTelemetry for tracing"
# Created docs/adr/0001-adopt-opentelemetry-for-tracing.md
pantheon-adr list
Prints every record, sorted by number, as ADR-NNNN <status> <title>. Files
that do not match the NNNN-*.md pattern (such as README.md) are ignored.
pantheon-adr list
# ADR-0001 Accepted Adopt OpenTelemetry for tracing
# ADR-0002 Proposed Split the ingestion service
pantheon-adr supersede <number> <new-title>
Marks ADR <number> as Superseded by ADR-NNNN and creates a new Accepted
record titled <new-title> that references the old one. Errors if <number>
does not exist.
pantheon-adr supersede 1 "Adopt Grafana Tempo for tracing"
# Superseded docs/adr/0001-adopt-opentelemetry-for-tracing.md
# Created docs/adr/0003-adopt-grafana-tempo-for-tracing.md
pantheon-adr skill install
Installs this adr-creator skill into agent skills directories. The skill is
embedded in the binary, so no repository checkout is needed.
| Flag | Effect |
|---|---|
--agent <name> |
Target a specific agent by slug (repeatable). |
--all |
Install into every agent in the universal list. |
--local |
Install into project-local directories instead of global. |
--mode copy|symlink |
Copy (default) or symlink the skill files. |
--dry-run |
Report what would happen without writing. |
--list-agents |
List targetable agents and exit. |
pantheon-adr skill install --all --dry-run
Exit behaviour
Every command exits 0 on success and 1 on error, printing Error: <message>
to standard error. This makes the tool safe to chain in scripts and CI.
pantheon-adr new "Record the decision" && git add docs/adr && git commit -m "docs(adr): record decision"
Deriving an ADR from an Existing Document
Most ADRs get written forwards: a decision is made, then pantheon-adr new
creates a fresh record for it. Sometimes the order is reversed — a decision
was already made and written down, just not as an ADR. It is sitting inside
a design doc, a review, a retrospective, a planning note, or an analysis
document that existed for some other purpose. This reference covers that
extraction case: how to recognize a binding decision buried in existing
prose, and how to turn it into a proper ADR without losing the link back to
where it came from.
Everything else about ADRs — immutability once accepted, the supersede
workflow, status transitions — is unchanged. See
ADR Lifecycle for those rules; this document only covers
the extraction step that happens before pantheon-adr new runs.
When this applies
- A design doc, spike write-up, or planning note already states a choice (“we will use X”, “the recommended approach is Y”) but no ADR exists yet.
- A retrospective or incident review reaches a conclusion that changes how the team will build something going forward.
- Someone asks you to “write up that decision from the doc” rather than handing you a decision to record from scratch.
If the source document only observes or analyzes without landing on a choice, there is nothing to extract yet — see Recognizing a binding decision below before creating anything.
Recognizing a binding decision in existing prose
Not every sentence that sounds decisive is a decision worth an ADR, and not every decision announces itself with a heading. Look for a choice that meets both of these:
- It is settled, not proposed. The document states what will happen or what was chosen, not a menu of options still being weighed. “We should probably consider Postgres” is not yet a decision; “we will use Postgres for the audit log” is.
- It is binding on future work. The choice constrains architecture, a convention, a process, or a hard-to-reverse technical direction — not a one-off, easily-reversed implementation detail.
A quick scan of section headings and phrasing narrows down where to look:
| Signal in the source document | Likely a decision? |
|---|---|
| A section literally titled “Decision”, “Recommendation”, “Recommended Approach”, or “Proposed Approach” | Yes — read it first |
| “We will…”, “Adopt Option A”, “Going forward, …” | Yes |
| An “Open Questions” or “Options” section, later resolved elsewhere in the doc or in a follow-up | Yes, once resolved — don’t extract while still open |
| A “Summary” or “Findings” section with no stated direction | No — this is observational, not a decision |
| An inline aside or comment (“worth noting that…”) | No — too ephemeral for an ADR |
When in doubt, ask: if this document disappeared tomorrow, would future contributors need to know this choice was made and why? If yes, it earns an ADR.
Workflow
- Confirm no ADR already covers this decision. Run
pantheon-adr listand skim titles. Extracting a decision that already has a record produces a duplicate; supersede instead if the decision has since changed (see ADR Lifecycle). - Create the record exactly as you would for a fresh decision. Run
pantheon-adr new "<Title>". The tool still derives the next number and stamps today’s date — the fact that the decision was made earlier does not change how the record is created. Verify: the printed path matches the number expected frompantheon-adr list. - Fill Context, Decision, and Consequences from the source document, not from memory. Pull the forces, constraints, and reasoning out of the original prose and rewrite them so the ADR stands alone — a reader should not need the source document to understand the decision. Do not just copy-paste a paragraph verbatim if it assumes context the ADR doesn’t have.
- Backfill Alternatives Considered if the source document doesn’t have it. Planning notes and reviews often settle on an approach without formally listing what else was considered. If the source document names other options anywhere (even in passing, or in an “Options” section that was later resolved), pull them into this section with the reason each was rejected. An empty section here is not acceptable just because the source document didn’t have one — see the CLI skill’s own Anti-Patterns on this.
- Link back to the source document for provenance, using the convention below.
Linking back to the source document
pantheon-adr does not currently have a structured field dedicated to “this
ADR was extracted from document X” — checked in the CLI’s own template
renderer, which only defines **Technical Story:** (a link/ticket line) and
a ## References section with generic link bullets. Until the tool grows a
purpose-built field, use this convention so provenance is still visible and
consistent between ADRs:
- Add a
- Source: <path-or-link>bullet under Context, right after the opening paragraph, naming the document the decision was extracted from (a relative repo path, a doc link, or a review/ticket URL). - Also add the same link under References if the document is durable
and worth pointing readers to directly (the
## Referencessection already invites “[Link to relevant docs]” — a source document counts).
Example ## Context opening:
## Context
- Source: docs/design/ingestion-pipeline-review.md
What is the issue we're facing in a given context?
...
This is a documentation convention, not something the CLI validates or enforces — nothing breaks if it’s omitted, but omitting it silently loses the provenance chain between the decision and the document that motivated it, so treat it as expected practice for any ADR created this way.
Anti-patterns specific to extraction
NEVER extract a decision that is still framed as an open question in
the source document.
WHY: An ADR states what was decided. Recording an unresolved option
as if it were settled misrepresents the actual state of the decision and
will need correcting (or superseding) as soon as the team actually decides.
BAD: Turning a planning doc’s “Option A looks promising” into an ADR
titled “Adopt Option A” before anyone signed off on it.
GOOD: Wait until the source document (or a follow-up) states the choice
was made, then extract it — or create the ADR with status Proposed only if
the team already treats proposals as ADRs (see the main SKILL’s
When Not to Use).
NEVER skip the source link because the decision “is obvious from
context”.
WHY: The person reading the ADR in six months has neither the source
document open nor the memory of which review it came from. Without the
link, they cannot verify the reasoning or find related detail the ADR
necessarily left out.
GOOD: Always add the Source: line under Context, even for a decision
that feels self-explanatory today.
Optional: spotting decisions with no ADR yet
If a team accumulates design docs, reviews, or planning notes as a matter of
course, it can be worth periodically checking whether any of them contain a
decision (per the signals above) that never got an ADR.
scripts/check-undocumented-decisions.sh automates this: it scans a
planning-document directory (.context by default) for the same
decision-shaped headings and phrasing listed above, cross-references them
against every existing ADR’s Source: line, and reports any document that
looks decided but isn’t linked from an ADR yet (exit 2), or confirms
everything is covered (exit 0). Pass --source-dir if planning documents
live somewhere other than .context, or --adr-dir to match a non-default
pantheon-adr new --dir. Like the Source: convention itself, this is a
documentation-side check, not something pantheon-adr runs internally —
wire it into CI or a pre-commit hook if you want it enforced rather than
run on demand.