skills/adr-ops/SKILL.md
Author, index, and lint Architecture Decision Records — append-only memory that recovers the WHY behind a system's shape. Triggers on: adr, architecture decision record, decision log, record this decision, supersede an adr, why was this decided, adr template, next adr number.
npx skillsauth add 0xDarkMatter/claude-mods adr-opsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
An Architecture Decision Record (ADR) captures one architectural decision: what was decided, why, what was rejected, and what it costs. ADRs are append-only project memory — they exist so a future maintainer touching a subsystem can recover the reasoning behind its shape without archaeology through git history or chat logs.
This skill encapsulates a battle-tested ADR protocol and generalizes it to any repo.
The default location is docs/adr/, but every script takes --dir so a repo can keep
records anywhere (docs/decisions/, architecture/adr/, …).
Write one when a change has any of these properties:
Write one decision per ADR. If a change bundles two separable decisions, write two.
Rule of thumb: if someone could plausibly undo this next month without re-litigating a trade-off, it is not an ADR.
<adr-dir>/ADR-NNN-slug.md (default <adr-dir> = docs/adr).NNN is zero-padded three digits, assigned sequentially: the next number is
highest existing + 1. Numbers are never reused, never reordered — a superseded
ADR keeps its number forever.slug is short kebab-case naming the subject (oauth-only-auth, per-trial-container).00_*) sorts above the numbered records and is not
part of the sequence.Do not maintain a hand-curated numbered list as the source of truth — it drifts from
the filesystem. The authoritative list is the directory itself; adr-index.sh is just a
clean parse of it. Any prose list elsewhere (README, AGENTS.md) is a convenience pointer
that may lag and must say so.
Full template in assets/ADR-template.md; full rules in
references/canonical-format.md. The shape:
---
status: accepted
date: YYYY-MM-DD
supersedes: []
superseded-by: []
touches:
- "path/one.py"
---
# ADR-NNN: Title in Title Case
## Decision (one sentence)
<BLUF — one present-tense sentence stating the standing rule; greppable, stands alone.>
## Context
## Alternatives considered
## Consequences
### Positive / ### Negative / ### Non-goals
## See also
Fixed section order: Decision → Context → Alternatives considered → Consequences →
See also. Extra sections (Migration path, Enforcement, Implementation summary) go after
Consequences. For a multi-part decision, keep the one-sentence BLUF and add a
## Decision (detail) section lower down.
| Field | Required | Rule |
|---|---|---|
| status | yes | proposed / accepted / superseded / deprecated (lowercase). |
| date | yes | Decision date, YYYY-MM-DD. |
| supersedes | yes | YAML list of ADR ids this replaces ([] if none). |
| superseded-by | yes | YAML list of ADR ids that replace this ([] until superseded). |
| touches | yes | YAML list of paths / globs / config keys this governs. Quote each. The grep discovery surface — grep touches: answers "is there an ADR about the thing I'm changing?" |
| extends | optional | ADR ids this builds on without replacing. |
| related | optional | Companion ADR ids (not parents). |
| deciders | optional | Who made the call. |
A new field is a protocol change — record it in a new ADR, don't invent per-record keys.
proposed ──► accepted ──► superseded (superseded-by: [ADR-NNN])
│
└────────► deprecated (withdrawn; nothing replaces it)
ADRs are append-only. Once accepted, you do not rewrite the Decision or Context.
Three change modes (full detail in references/lifecycle-and-supersession.md):
supersedes: [ADR-OLD];
flip the old record's frontmatter to status: superseded + superseded-by: [ADR-NEW]
in the same commit. Body stays intact (obsolete reasoning is itself a record).
Supersession is bidirectional — a one-sided link is a lint error.## Addendum — YYYY-MM-DD: <topic> at the end of the body. Never use it to
quietly reverse the decision.touches:. Preserves
meaning; never rewrites rationale.bash scripts/adr-new.sh --dir docs/adr --title "Your decision title"
(computes NNN = highest+1, derives the slug, fills frontmatter).touches: accurate; it is the discovery surface.ls docs/adr/ADR-*.md (or bash scripts/adr-index.sh).adr-new.sh --supersedes ADR-OLD --apply-supersede.python scripts/adr-lint.py --dir docs/adr.docs(adr): conventional-commit subject, e.g.
docs(adr): ADR-020 — <subject>.Adopting ADRs in a fresh repo? Run bash scripts/adr-init.sh --first-title "…" once to
bootstrap the directory + a lint-clean ADR-001. Before changing an existing subsystem, run
python scripts/adr-touching.py <path> to surface any decision already governing it.
All scripts take --dir (default docs/adr), --help, and follow semantic exit codes
(0 ok, 2 usage, 3 not-found, 5 precondition, 10 findings/domain-signal). Pair
with the git-ops skill for the commit/PR step. The three read tools form the legs of a
stool: lint = integrity, index = overview, touching = "what governs this file
before I change it".
scripts/adr-init.sh — bootstrap a repo adopting ADRs cold# Create docs/adr/, scaffold a lint-clean ADR-001, write a generated README:
bash scripts/adr-init.sh --first-title "Adopt ADRs"
# Custom dir + preview without writing:
bash scripts/adr-init.sh --dir docs/decisions --first-title "OAuth-only auth" --dry-run
Refuses to run in a directory that already holds ADR-*.md (exit 5) unless --force. The
ADR-001 it scaffolds is rendered by adr-new.sh, so it lints clean immediately. The
generated <dir>/README.md is self-labeled "generated — do not hand-edit; the directory
is the index" and says to run adr-index to regenerate. --dry-run writes nothing.
scripts/adr-new.sh — scaffold the next ADR# Next number, slug derived from the title, frontmatter pre-filled:
bash scripts/adr-new.sh --title "OAuth-only auth"
# Custom dir + explicit slug + proposed status, preview without writing:
bash scripts/adr-new.sh --dir docs/decisions --title "Per-trial container" \
--slug per-trial-container --status proposed --dry-run
# Supersede an old record and flip its frontmatter automatically:
bash scripts/adr-new.sh --title "Replace router" --supersedes ADR-002 --apply-supersede
Refuses to overwrite an existing file (exit 5). Atomic write. --dry-run prints the path
--number N forces a specific number (backfilling
or coordination) — use sparingly; sequential highest+1 is the discipline.scripts/adr-index.sh — the directory as a table (read-only)bash scripts/adr-index.sh # number | status | date | title
bash scripts/adr-index.sh --json | jq '.data[] | select(.status=="accepted")'
Prefers yq; degrades to a built-in parser when yq is absent (announced on stderr).
Pass --output FILE to write a generated Markdown index (heading + a do not hand-edit marker + the | # | Status | Date | Title | table) atomically to a file
instead of stdout — for a README pointer that you regenerate rather than hand-curate.
scripts/adr-touching.py — what governs this file? (the discovery surface)The touches: frontmatter is the grep target answering "is there an ADR about the thing
I'm changing?". This tool is that grep, done properly — match a path, glob, or config
key against every ADR's touches: list.
# Before editing src/auth.py, ask what decisions constrain it:
python scripts/adr-touching.py src/auth.py # exit 10 if an ADR governs it
python scripts/adr-touching.py 'src/**' # glob query
python scripts/adr-touching.py --json src/ | jq '.data[].number'
Matching is bidirectional and pragmatic: exact equality; fnmatch glob either direction
(touches src/** matches query src/auth.py; query src/* matches touches
src/auth.py); path-prefix containment (query src/ governs touches src/auth.py, and
vice-versa); config keys (file.yaml:key) by exact-or-prefix.
Guard contract (the load-bearing bit): exit 0 = no governing ADR found, exit
10 = at least one ADR governs the query. A pre-edit hook or CI step branches on it —
"heads up, ADR-010 governs this path; read it before changing." Exit 3 dir not found,
2 usage.
scripts/adr-lint.py — conformance validatorpython scripts/adr-lint.py --dir docs/adr # exit 0 clean, 10 if findings
python scripts/adr-lint.py --strict --json | jq '.data[] | select(.severity=="error")'
Checks required + well-typed frontmatter, the # ADR-NNN: title matching the filename,
the BLUF placement, core section order, no duplicate numbers (gaps are a warning),
and supersession bidirectionality (the high-value cross-file check). Plus:
superseded with an empty superseded-by;
deprecated with a non-empty superseded-by; an in-force (accepted/proposed) ADR
carrying a superseded-by. These complement the bidirectionality check without
double-reporting.touches (warning): a touches: entry that is a literal filesystem path
(not a glob, not a config key) which no longer resolves under --repo-root (default:
git toplevel, else cwd) — the discovery surface may have drifted. Warning-tier only;
counts toward exit 10 under --strict.--strict makes warnings count toward exit 10. Exit 4 if a file's frontmatter is
unparseable.
ADRs only stay trustworthy if the integrity contract is machine-enforced. Gate the lint
in CI; --strict turns the stale-touches drift warning into a hard signal.
# .github/workflows/adr-lint.yml
name: adr-lint
on: [pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lint ADRs
run: python skills/adr-ops/scripts/adr-lint.py --strict --dir docs/adr
# exit 10 (findings, incl. stale-touches under --strict) fails the build
Local pre-commit gate: add python scripts/adr-lint.py --strict --dir docs/adr to a
pre-commit hook so a one-sided supersession or a stale discovery surface is caught before
the commit lands. A pre-edit hook can additionally call adr-touching.py <changed-path>
and surface the governing ADR (exit 10) before a subsystem is modified.
references/canonical-format.md — the full template, field table, and body rules.references/lifecycle-and-supersession.md — status lifecycle + the three change modes.assets/ADR-template.md — copy-ready canonical template.testing
Audit any repo against the agentic-quality doctrine — score entry docs, structure, and enforcement gates, then map each finding to its fix. Triggers on: repo doctor, repo audit, agentic quality, is this repo agent-friendly, doc drift, stale AGENTS.md, monorepo structure, nested CLAUDE.md.
data-ai
Router for parallel or recurring agent work across six skills. Covers: parallel agents, fan out work, delegate to workers, run overnight, scheduled loop, land branches, mixed-model fleet, orchestrate workers, background agents at scale. Triggers on: which skill for parallel work, fan out agents, spawn workers, run this overnight, schedule a loop, land my branches, heterogeneous fleet, delegate to cheaper model, autonomous loop.
tools
Heterogeneous cross-provider fleet - GLM (z.ai), Codex (OpenAI), Grok (xAI), Anthropic Sonnet/Opus/Haiku - from one session, porting the native Workflow tool's patterns (adversarial verify, judge panels, journal resume) to OS-process workers. Triggers: fleetflow, heterogeneous/mixed-model fleet, codex worker, grok worker, cross-provider fan-out, cross-model verify.
development
Application/game-scale three.js: ES modules, GLTF pipeline (DRACO/KTX2/meshopt), AnimationMixer, physics (rapier/cannon-es), react-three-fiber, and performance at scale (InstancedMesh, LOD, draw calls). Triggers on: three.js, GLTFLoader, r3f, game loop, WebGL memory leak, boids.