adr
Skill192 starsChanged 38 days agoMITView on GitHub
Write an Architecture Decision Record (ADR) for a feature — Context / Decision / Status / Consequences / Alternatives, filed as docs/features/<feature>/adr-<NNN>-<title>.md with a 3-digit zero-padded number. Handles the Superseded case: bidirectional linking when a new ADR replaces an old one. Use when: recording why an architectural approach was chosen, documenting a decision so it doesn't get re-litigated, marking a prior decision as superseded. Not for: feature-level technical design (use /tech-spec), task progress tracking (use /create-request), bulk backfill of historical decisions (a separate request — this skill writes one ADR at a time).
90 other projects use a version of this.
Adopted by
Most recently taken up by
- GustavoAlecio/claude-setuptheir own version, first seen Nov 8, 2026
- computerlovetech/skillstheir own version, first seen Nov 8, 2026
- rvdbreemen/OTGW-firmwaretheir own version, first seen Nov 8, 2026
- axodouble/skillstheir own version, first seen Nov 8, 2026
- RodrigoAnciaes/golem-sddtheir own version, first seen Nov 8, 2026
- n1kben/agentstheir own version, first seen Nov 8, 2026
Used with
Projects with it also use fdr, sweep and 6 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
thiagofgfSkillfdr
Use when creating, changing, reviewing, retiring, auditing, or backfilling implemented user-visible feature behavior, permissions, feature-specific rationale, tradeoffs, or relationships to architectural decisions.
Also in 3 projects that use this
drewdrewthisSkillsweep
Search for similar patterns, anti-patterns, or issues elsewhere in the codebase after a fix or feature. Use after implementing a fix to catch the same bug in other places, or proactively to audit for a known pattern.
Also in 4 projects that use this
vndeeSkillproduct-spec
Use when starting a new feature, product, or project — before any architecture or code, to define what to build and why
Also in 3 projects that use this
OpenAISkillthreat-model
Use when Codex is already in the threat-modeling phase of a security scan, the user explicitly invokes $threat-model, or the user explicitly asks to create, update, or persist a repository threat model. Do not use as the primary trigger for full PR, commit, branch, patch, or repository scans.
Also in 6 projects that use this
PydanticSkillcoverage
Fetch coverage diff from Codecov for the current branch or a specific PR. Shows uncovered lines, patch coverage, and overall coverage change.
Also in 4 projects that use this
OpenAISkillobservability
Vercel Observability expert guidance — Drains (logs, traces, speed insights, web analytics), Web Analytics, Speed Insights, runtime logs, custom events, OpenTelemetry integration, and monitoring dashboards. Use when instrumenting, debugging, or optimizing application performance and user experience on Vercel.
Also in 8 projects that use this
Other versions90 projects use a version of this.
Word for word · 1
- sd0xdev/sd0x-harness★ 192100% same
Edited · 0
None found.
Wrote their own version · 89
- CrowdDotDev/crowd.dev★ 3.4ksame name
- chattocorp/chatto★ 2.9ksame name
- Cosmian/kms★ 372same name
- linuxfoundation/insights★ 288same name
- rvdbreemen/OTGW-firmware★ 213same name
- irahardianto/awesome-agv★ 157same name
- jellydn/my-ai-tools★ 127same name
- EmeaAppGbb/spec2cloud★ 100same name
- AsiaOstrich/universal-dev-standards★ 84same name
- theagentplane/tokenops★ 84same name
79 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository102 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- agentctl-setupSkill
- architectureSkill
- askSkill
- best-practicesSkill
- bug-fixSkill
- bump-versionSkill
- check-coverageSkill
- claude-healthSkill
- code-exploreSkill
- code-investigateSkill
- codex-architectSkill
- codex-brainstormSkill
- codex-cli-reviewSkill
- codex-code-reviewSkill
- codex-explainSkill
- codex-implementSkill
- codex-review-branchSkill
- codex-review-docSkill
- codex-review-fastSkill
- codex-reviewSkill
- codex-securitySkill
- codex-setupSkill
- codex-test-genSkill
- codex-test-reviewSkill
- contract-decodeSkill
- create-prSkill
- create-requestSkill
- de-ai-flavorSkill
- debugSkill
- deep-analyzeSkill
- deep-exploreSkill
- deep-researchSkill
- dep-auditSkill
- deploy-flowSkill
- dev-security-auditSkill
- doc-refactorSkill
- doc-reviewSkill
- epic-mergeSkill
- feasibility-studySkill
- feature-devSkill
- feature-verifySkill
- fp-briefSkill
- generate-runnerSkill
- gh-stackSkill
- git-investigateSkill
- git-profileSkill
- install-hooksSkill
- install-rulesSkill
- install-scriptsSkill
- issue-analyzeSkill
- jiraSkill
- load-pr-reviewSkill
- merge-prepSkill
- necessity-auditSkill
- next-stepSkill
- obsidian-cliSkill
- op-sessionSkill
- orchestrateSkill
- plan-reviewSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
6 rules. 0 are common, 2 are distinctive, and 4 are very specific to this project.
0
Common
Most of the 74 edited versions we read keep these.
2
Distinctive
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 96
Run skills/adr/scripts/next-adr-number.js — do not hand-apply the max.
- Very specific: line 129
If not already supplied via $ARGUMENTS, ask for:
- Very specific: line 164
Remove references/template.md's two commented-out placeholder blocks (the <!-- --> slots documenting where a future …
- Very specific: line 191
If the printed type is not adr, do not write the file under that name.
- Distinctive: line 221
If the old ADR named as superseded does not exist at either location, Gate: Need Human — do not silently skip the link or guess a different …
- Distinctive: line 244
If superseding: the prior ADR file also modified (Status flip + Superseded-by link)
“Common” is measured: kept by at least 6 in 10 of the 74 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
ADR — Architecture Decision Record
Trigger
- Keywords: ADR, architecture decision record, decision record, record a decision, why did we choose, 架構決策, 決策紀錄
When NOT to Use
| Scenario | Alternative |
| Feature-wide technical design (components, data flow) | /tech-spec |
| Task progress / acceptance-criteria tracking | /create-request |
| Bulk backfill of decisions already made in the past | Separate request — this skill writes one ADR per invocation, not a batch |
Workflow
Phase 1: Resolve feature → shared feature-context resolution
Phase 2: Compute number → scan root + archived/, numeric max + 1, zero-pad to 3 digits
Phase 3: Gather content → Context / Decision / Status / Consequences / Alternatives
Phase 4: Write ADR → fill references/template.md, write to docs/features/<key>/
Phase 4b: Superseded link → (only if this ADR supersedes an existing one) edit both files
Phase 5: Report → path written, number assigned, links updatedPhase 1: Resolve Feature
Reuse the shared cascade — do not re-derive it here:
@skills/create-request/references/feature-context-resolution.md — the single copy since
doc-review-phasing r2 merged the two that had drifted apart; /tech-spec now keeps its own
command-free native-cascade reference in its own bundle instead of a second copy of this one —
canonical implementation scripts/lib/feature-resolver.js, invoked as
node scripts/resolve-feature.js [--feature <key>].
scan_error gate. scan_error !== false ⇒ the source sets are unknown, not empty —
report it and take the ⚠️ Need Human exit rather than recording a decision against a corpus you could not read — an ADR is a
time-stamped claim about what was true, and one written from an unreadable corpus is wrong forever. Gate on !== false, not
=== true: a {} payload from a shell fallback carries no such field at all, and a non-null key
is not evidence the sets are complete — scan_error rides alongside a resolved key.
The wrapper, not the CLI. resolve-feature.js is the single owner of the failure payload: it
exits 0 and emits the full shape with scan_error: true however the CLI fails — nonzero exit,
signal, partial write, or a payload that is not the agreed shape; it cannot cover node itself
being missing, since nothing running under node can — where the CLI invoked
directly can die mid-write and a || echo '{}' fallback of your own emits a payload with no
scan_error field at all. This skill briefly carried an exemption on the grounds that its
allowed-tools could not reach bash. The fix was not to widen the tool list but to make the
entrypoint reachable: resolve-feature.js runs under the Bash(node:*) this skill already grants,
so there is one failure contract and no exemptions, at no cost in permissions. (Bash(node:*) is
not universal either — /codex-code-review grants bash and no node, and keeps the shell shim. The
rule is that a skill instructs the entrypoint it is permitted to run.) This skill reads key,
confidence and docs_path only and consumes none of the four source sets, so the scan_error
gate the research skills carry does not bind it — but a {} reply still means the invocation failed
and is never an empty corpus.
The gate below checks the directory (and the confidence), not key alone. For Levels 1–3
(explicit --feature with a valid slug, branch feat/<x>, or a changed path under
docs/features/<key>/), resolveFeatureContext returns a non-null key with
confidence: "high" or "medium" even when docs/features/<key>/ does not exist on disk — it
only probes the directory to enrich the result, never to invalidate it
(scripts/lib/feature-resolver.js § probe). An explicit --feature value that fails the
case-insensitive slug pattern (/^[a-z0-9][a-z0-9._-]*$/i, e.g. --feature ../evil) is rejected
at scripts/lib/feature-resolver.js:13 before it ever reaches key. Level 3b (a changed path
under skills/<key>/, from line 140) only returns when probe() finds the directory; on a miss it falls through — to
Level 4 if docs/features/ has exactly one subdirectory (returns that directory's name as
key anyway, source: "single_dir", confidence: "low" — a guess, not a match on the actual
change), otherwise to Level 5 (key: null). the resolver prints the full result
object in the null case, e.g. {"key":null,"source":"none",...} — a bare {} means something
else entirely (no git root, or the CLI itself threw). A typo'd --feature value is the likelier
failure and does not produce a null key (Level 1 still returns it with confidence: "high"),
so gating on key alone silently creates a bogus feature directory instead of asking:
| Result | Action |
key resolved, confidence is "high" or "medium", and docs/features/<key>/ exists | Continue to Phase 2 |
key resolved but docs/features/<key>/ does not exist (check with node -e "process.exit(require('fs').existsSync(process.argv[1])?0:1)" "docs/features/<key>" — this skill's allowed-tools has no general Bash, only Bash(node:*)) | Gate: Need Human — confirm this is really a new feature directory the user wants created; do not silently write into a typo'd path |
confidence is "low" (source: "single_dir") | Gate: Need Human — this is a guess ("only one feature directory exists"), not a match on the actual change; confirm it's the right one before writing into it |
key is null (the resolver prints the full object, e.g. {"key":null,"source":"none",...}) | Gate: Need Human — ask which feature this ADR belongs to; do not guess |
Phase 2: Compute the Number
Scan both the feature's root directory and its archived/ subdirectory for existing
adr-*.md files. rules/docs-numbering.md § Ancillary docs defines the adr-<number>-<title>.md
filename pattern but says nothing about archived/ — that convention lives in
scripts/lib/doc-classifier.js (scanFeatureDocs, which skips directories named archived at any
depth when building its live doc inventory). A number retired there is still taken, so this scan
is deliberately broader than that inventory — building the live-doc list and computing the next
free number are different purposes.
Run skills/adr/scripts/next-adr-number.js — do not hand-apply the max.
Numeric max, not lexical sort: string-sorting adr-9-... after adr-10-... would collide, which
is exactly the bug that shipping this as an unexecuted prose pin would miss.
node skills/adr/scripts/next-adr-number.js docs/features/<key>(paths are repo-root relative, matching every other path in this skill). The function itself
(nextAdrNumber, exported for direct unit testing —
test/skills/adr.test.js exercises it against real temp directories, not just a prose pin):
function nextAdrNumber(featureDir) {
let max = 0;
for (const dir of [featureDir, path.join(featureDir, 'archived')]) {
let entries;
try { entries = fs.readdirSync(dir); } catch { continue; }
for (const name of entries) {
const m = name.match(/^adr-(\d+)-/i);
if (m) max = Math.max(max, parseInt(m[1], 10));
}
}
return String(max + 1).padStart(3, '0');
}The regex is case-insensitive (/i) — a hand-written ADR-006-x.md on a case-insensitive
filesystem still counts toward the max, avoiding a reissued number. The first ADR in a feature
(both directories empty or missing) produces adr-001-<title>.md.
Phase 3: Gather Content
If not already supplied via $ARGUMENTS, ask for:
- Title — short, kebab-case (becomes the filename's
<title>segment) - Context — what forces are at play, what problem prompted the decision
- Decision — what was decided, stated as a decision, not a description
- Status —
ProposedorAccepted(defaultProposed; a new ADR is never created asSuperseded— that value is only ever set on an existing ADR, by Phase 4b, on a later ADR superseding it). If the user states this ADR supersedes an existing one, ask which of the two the new ADR should carry —Acceptedis the common case, butProposedis valid too — then run Phase 4b after Phase 4 - Consequences — what becomes easier or harder as a result, including negative tradeoffs
- Alternatives considered — what else was on the table and why it lost
Phase 4: Write the ADR
Fill references/template.md and write to
docs/features/<key>/adr-<NNN>-<title>.md. The H1 must literally contain the string ADR
(e.g. # ADR-001: <Title>) — doc-taxonomy.json's heading_signals for the adr type is
["Decision Record", "ADR", "架構決策"]. For a well-formed adr-<NNN>-<title>.md filename,
classifyByPath's semantic_pattern alone already reaches medium confidence, so the two signals
are not combined to jointly lift confidence — doc-classifier.js only consults heading_signals
when scanFeatureDocs is called with its deep option (not a CLI flag; the only production
caller, scripts/lib/feature-resolver.js:29, does not pass it, so this path is currently exercised
only by direct calls and tests), and only when classifyByPath already returned the fallback type.
Even then, a correct H1 is necessary but not sufficient: classifyByHeading lowercases the
first 20 lines and returns the first taxonomy type (in array order) whose signal appears anywhere
in them — ten types precede adr (index 10 in doc-taxonomy.json): the five lifecycle types plus
review-log, fp-brief, tech-brief, checklist, and runbook. The last two matter most here,
since they are two of the four the classification guard below defends against on the filename path
— an ADR about operational tooling plausibly has "runbook", "checklist", or "SOP" in its own
Context, misclassifying it on the heading path even with a perfect H1. This claim is pinned by a
test, not left as prose alone (test/skills/adr.test.js calls classifyByHeading directly), since
it depends on doc-taxonomy.json's array order and would silently go stale on a reorder. The H1
requirement is worth keeping as a best-effort signal for the fallback case, not a guarantee.
Remove references/template.md's two commented-out placeholder blocks (the <!-- --> slots
documenting where a future Supersedes/Superseded-by line goes) — unless Phase 4b runs in the same
pass, in which case replace the relevant one with the real line instead of deleting it blank.
Classification guard — run before writing, not after. doc-taxonomy.json's type list is
checked in array order, and four types sit before adr (index 10) with patterns a free-text
<title> can actually hit: checklist and runbook carry unanchored substring patterns
(^checklist-|確認事項|checklist, ^runbook-|操作手冊|runbook — the word anywhere in the filename
matches, e.g. adr-002-runbook-automation.md), and fp-brief/tech-brief carry suffix
patterns (-fp-brief\.md$, -tech-brief\.md$) that match if the title happens to end in that
phrase, e.g. adr-003-vendor-tech-brief.md. All four classify silently as that other type instead
of adr. <title> is free text from Phase 3, so this is reachable, not theoretical.
Pass the bare filename only, never the full write path. classifyByPath has no
basename() step and is path-sensitive: run it against the full target path
(docs/features/<key>/adr-<NNN>-<title>.md) and two independent things break — the leading
docs/features/ segment defeats the ^adr- anchor entirely (falls to the taxonomy fallback
type), and if <key> itself contains a colliding word (e.g. a feature directory named
deploy-runbook) the directory name — not the title — decides the result. The guard command
below strips to the basename itself with path.basename() so it gives the same, correct answer
whether the value passed happens to be the bare filename or the full path — verified both ways:
node -e "const {basename}=require('path'); console.log(require('./scripts/lib/doc-classifier').classifyByPath(basename(process.argv[1])).type)" \
"adr-<NNN>-<title>.md"If the printed type is not adr, do not write the file under that name. Ask the user to
rephrase the title to avoid the colliding word, recompute, and re-check — up to 3 attempts. Never
silently write a misclassified ADR; this is not the same failure as an unresolved feature, so it
does not route through the Phase 1 Gate: Need Human on the first miss — it is a title-collision
retry loop, not a missing-input one. After 3 failed rephrasings, stop retrying and escalate:
Gate: Need Human — a user who keeps proposing colliding titles is the case this bounds; the
path.basename() fix above already rules out the directory-name-collision case (the feature key
itself contains the colliding word), so this cap only needs to bound retitling attempts, not an
unfixable path.
Phase 4b: Superseded Linking (only when this ADR replaces an existing one)
Bidirectional — both files change, in the same pass. Both edits target the > **Status** /
> **Created** blockquote at the top of references/template.md — never the ## Status section
further down, which is a static legend explaining the three enum values, not a per-ADR value slot:
| File | Edit |
| New ADR (just written) | Add > **Supersedes**: [adr-<OLD>](<path>) as a new blockquote line, directly below > **Created** |
| Old ADR (existing file) | Change the existing > **Status**: <value> line to > **Status**: Superseded; add > **Superseded by**: [adr-<NEW>](<path>) as a new blockquote line below it. If the old ADR predates this skill and has no > **Status**: line at all, add one rather than assuming it exists |
<path> is relative to the file doing the linking, and the old ADR may resolve to either
directory found in Phase 2's scan — get this from wherever Phase 2 actually found the old number,
don't assume root:
| Old ADR found in | New ADR's <path> | Old ADR's own <path> (self-referencing the new one) |
| feature root | ./adr-<OLD>-<old-title>.md | ./adr-<NEW>-<new-title>.md |
archived/ | ./archived/adr-<OLD>-<old-title>.md | ../adr-<NEW>-<new-title>.md |
If the old ADR named as superseded does not exist at either location, Gate: Need Human — do
not silently skip the link or guess a different file. If the old ADR is already Superseded by a
third ADR, Gate: Need Human — do not overwrite the existing link or append a second one.
Phase 5: Report
Output the path written, the assigned number, and (if Phase 4b ran) both files touched with a one-line diff summary of the added link.
Numbering & Classification — Verification
adr-001-<title>.mdis the first-ADR filename shape (AC edge case)- Number is a numeric max over
^adr-(\d+)-(case-insensitive) across root +archived/, computed byskills/adr/scripts/next-adr-number.js, never hand-applied or a string sort docs/features/<key>/adr-<NNN>-<title>.mdclassifies viadoc-classifier.js'ssemantic_pattern(^adr-|decision) at step 4 —mediumconfidence, not the step-7 fallback type — only when the title contains no word matching another type's pattern; the Phase 4 classification guard exists because titles containingrunbook,checklist, or ending in-fp-brief/-tech-briefdemonstrably do not
Output
- New ADR file at
docs/features/<feature>/adr-<NNN>-<title>.md - If superseding: the prior ADR file also modified (Status flip + Superseded-by link)
Verification Checklist
- Filename matches
adr-<NNN>-<title>.md, 3-digit zero-padded - Number computed via
skills/adr/scripts/next-adr-number.js(numeric max across root +archived/, not lexical sort, not hand-applied) - Classification guard run before writing:
classifyByPath(filename).type === 'adr' - H1 heading contains
ADR - Template fields present: Context, Decision, Status, Consequences, Alternatives considered
- If Superseded: both the new and the old ADR cross-link, in the same pass, using the path table for whichever directory Phase 2 actually found the old ADR in
- No feature resolved → Gate: Need Human, not a guess
After Creation
New to this feature's docs directory? Register it once via /tech-spec or /create-request so the
feature has a tech spec to link the ADR back to (adr is not one of doc-classifier.js's
canonical_roles, so no tooling does this automatically) — an ADR with no owning tech spec is
still valid, just harder for a reader to trace to the feature's
broader design.
References
rules/docs-numbering.md§ Ancillary docs — theadr-<number>-<title>.mdpattern this skill implementsscripts/config/doc-taxonomy.json—adrtype entry (ancillarynamespace,semantic_pattern,heading_signals); also whererunbook/checklist's unanchored patterns andfp-brief/tech-brief's suffix patterns live, the reason for the Phase 4 classification guardscripts/lib/doc-classifier.js—classifyByPath, used by the Phase 4 classification guardreferences/template.md— the ADR template this skill fillsskills/adr/scripts/next-adr-number.js— the numbering function Phase 2 runs, unit-tested directly bytest/skills/adr.test.js
Examples
Input: /adr --feature auth Title: Use JWT over session cookies
Action:
1. Resolve feature → docs/features/auth/
2. Scan root + archived/ for adr-* → none found → next number 001
3. Gather Context/Decision/Status/Consequences/Alternatives
4. Write docs/features/auth/adr-001-use-jwt-over-session-cookies.md
5. Report: adr-001 written, Status: ProposedInput: /adr --feature auth Title: Use opaque tokens (supersedes adr-001)
Action:
1. Resolve feature → docs/features/auth/
2. Scan root + archived/ → adr-001 exists → next number 002
3. Gather content, Status: Accepted (this ADR), supersedes adr-001
4. Write docs/features/auth/adr-002-use-opaque-tokens.md with "Supersedes: adr-001" line
4b. Edit adr-001-use-jwt-over-session-cookies.md: Status → Superseded, add "Superseded by: adr-002" line
5. Report: adr-002 written, adr-001 updated (Status + link)Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

