adr-check
Validates ADRs against references/adr-check-contract.md. Modes: Global (all ADR dirs + diff warnings), Scoped (file/dir/query — no diff noise), Diff (changed ADRs on branch). Outputs structured pass/fail report.
Step 1 — Determine mode and discover inputs
Inspect skill arg:
- No arg →
mode = global. Run dir discovery (steps 2–6).
- Arg =
.md file → mode = scoped_file, target = <path>. Skip dir discovery. Checks 2.2, 2.3, Step 4 skipped.
- Arg = directory →
mode = scoped_dir, target = <directory>. Skip CLAUDE.md discovery. Use target as sole adr_dirs entry. Run Checks 2.1, 2.1e, 2.2, 2.3. Skip Step 4.
- Any other non-empty arg →
mode = scoped_query, query = <arg>. Run dir discovery. Match ADR files via model judgment. Run Checks 2.1 and 2.1e only. Skip 2.2, 2.3, Step 4. No matches → emit advisory warning, exit PASS.
(global/scoped_query) Read project CLAUDE.md.
(global/scoped_query) Search for heading containing ADR Locations (case-insensitive).
(global/scoped_query) If found, collect bullet items as relative paths, strip inline # comments. Store as adr_dirs.
(global/scoped_query) If not found, fall back: scan repo root for docs/adrs/, decisions/, architecture/decisions/.
(global only) adr_dirs empty → output report Mode: Global, emit WARNING: No ADR directories found. Skipping validation., set Overall: PASS, stop.
Step 2 — Validate each directory
For each dir in adr_dirs, run checks below. Track failures as issues.
Check 2.1 — ADR file structure
- List files matching
NNNN-*.md (1+ digits, hyphen, any chars, .md).
- For each ADR file, verify:
a. Status present/non-empty: Line matching
**Status:** or ## Status with non-empty value. Else: [ADR-NNNN] Missing or empty Status field
b. Context non-trivial: ## Context body has ≥1 non-blank non-placeholder line (not solely whitespace, TODO, TBD, or template guidance). Else: [ADR-NNNN] ## Context section is empty or contains only placeholder text
c. Decision non-trivial: Same for ## Decision. Else: [ADR-NNNN] ## Decision section is empty or contains only placeholder text
d. Consequences present: ## Consequences section exists (content may be brief). Else: [ADR-NNNN] ## Consequences section is missing
e. Consequences quality (style): Model judgment — ≥1 genuinely adverse outcome (risk, trade-off, migration cost, complexity increase, regression, reduced flexibility, or explicit statement of what's given up). If absent, style warning (not structural): [ADR-NNNN] Consequences section contains no clearly adverse consequence or trade-off — consider adding one for credibility. Style warnings don't affect pass/fail.
Check 2.2 — Index sync (whole-dir mode only)
- If
<dir>/README.md missing: issue README.md index is missing from <dir>. Skip index checks for this dir.
- Parse README.md table: extract all ADR filenames/numbers linked in table.
- Each ADR file w/o table entry → issue:
[ADR-NNNN] ADR file exists but has no entry in README.md index
- Each table entry w/o matching file → issue:
[index entry] README.md references <filename> but file does not exist (orphaned entry)
Check 2.3 — Cross-reference integrity (whole-dir mode only)
- ADR with status
Superseded by ADR-NNNN:
a. Verify NNNN-*.md exists. Else: [ADR-MMMM] Status says "Superseded by ADR-NNNN" but ADR-NNNN does not exist
b. Verify referenced ADR contains Supersedes: ADR-MMMM. Else: [ADR-NNNN] Missing "Supersedes: ADR-MMMM" back-reference
- ADR with
Supersedes: ADR-NNNN:
a. Verify NNNN-*.md exists. Else: [ADR-MMMM] References "Supersedes: ADR-NNNN" but ADR-NNNN does not exist
b. Verify ADR-NNNN status is Superseded by ADR-MMMM. Else: [ADR-NNNN] Expected status "Superseded by ADR-MMMM" but found different status
Step 3 — Build the validation report
Separate Check 2.1e items into style_warnings (not structural, don't affect status).
Per validated target: structural issues (2.1a–2.1d) present → FAIL, else PASS.
Output report (header rows always present):
ADR Check Report
================
Mode: Global | Scoped (file) | Scoped (directory) | Scoped (query)
Target: <path, directory, or natural-language query>
ADRs: <comma-separated list of all validated ADR filenames>
Results
-------
<path/to/directory-or-file>:
Status: PASS | FAIL
Issues:
- [ADR-NNNN] <issue description>
<path/to/next-item>:
Status: PASS
Issues: none
Style Warnings (advisory only — not gate-blocking)
===================================================
- [ADR-NNNN] <style warning message>
Overall: PASS | FAIL
Global/scoped_dir → group by dir. scoped_file/scoped_query → each file own entry.
Style Warnings section omitted if empty.
Any entry FAIL → Overall: FAIL. On FAIL, append Remediation section (each issue + fix action).
Step 4 — Diff-based warnings (Global only — skip all scoped sub-modes)
Run git diff HEAD.
Scan for:
| Pattern |
Warning |
+ lines defining new ABC/interface (Python class Foo(ABC), abstractmethod, Java/TS interface, Go interface with multiple methods, TS abstract class) |
"New interface/ABC detected in <file> — consider documenting the design decision with /adr-create" |
+ lines in new file matching *Config*, *Settings*, *Configuration* (case-insensitive) |
"New configuration file <file> — consider documenting configuration decisions with /adr-create" |
+ lines in package.json (deps/devDeps), pyproject.toml ([tool.poetry.dependencies]/[project]), Cargo.toml ([dependencies]), go.mod (require) |
"New dependency added in <file> — consider documenting the technology choice with /adr-create" |
New root/top-level dir named service, module, component, pkg, lib, api, or gateway |
"New service/module boundary <dir> — consider documenting the architectural boundary with /adr-create" |
Warnings found → append to report:
Diff-Based Warnings (advisory only — not gate-blocking)
========================================================
- [WARNING] <message>
No warnings → omit section.
Step 5 — Output and exit
Print full report.
- PASS (with/without diff/style warnings): success. Gate consumers continue.
- FAIL: failure. Gate consumers block; present remediation to user.
Additional Resources
references/adr-check-contract.md — Full contract: discovery rules, checks (2.1–2.3, 2.1e), report format, pass/fail semantics, invocation modes.
1---2name: adr-check3description: This skill should be used when the user asks to 'validate ADRs', 'check ADR structure', 'run adr-check', 'check for undocumented decisions', or when lifecycle skills and gate agents need to validate ADR files. Supports Global mode (all discovered ADR directories, including diff-based warnings), Scoped mode (single file, directory, or natural-language query — no diff noise), and future Diff mode.4---56# adr-check78Validates ADRs against `references/adr-check-contract.md`. Modes: **Global** (all ADR dirs + diff warnings), **Scoped** (file/dir/query — no diff noise), **Diff** (changed ADRs on branch). Outputs structured pass/fail report.910---1112## Step 1 — Determine mode and discover inputs13141. Inspect skill arg:15 - **No arg** → `mode = global`. Run dir discovery (steps 2–6).16 - **Arg = `.md` file** → `mode = scoped_file`, `target = <path>`. Skip dir discovery. Checks 2.2, 2.3, Step 4 skipped.17 - **Arg = directory** → `mode = scoped_dir`, `target = <directory>`. Skip CLAUDE.md discovery. Use `target` as sole `adr_dirs` entry. Run Checks 2.1, 2.1e, 2.2, 2.3. Skip Step 4.18 - **Any other non-empty arg** → `mode = scoped_query`, `query = <arg>`. Run dir discovery. Match ADR files via model judgment. Run Checks 2.1 and 2.1e only. Skip 2.2, 2.3, Step 4. No matches → emit advisory warning, exit PASS.19202. *(global/scoped_query)* Read project `CLAUDE.md`.213. *(global/scoped_query)* Search for heading containing `ADR Locations` (case-insensitive).224. *(global/scoped_query)* If found, collect bullet items as relative paths, strip inline `# comments`. Store as `adr_dirs`.235. *(global/scoped_query)* If not found, fall back: scan repo root for `docs/adrs/`, `decisions/`, `architecture/decisions/`.246. *(global only)* `adr_dirs` empty → output report `Mode: Global`, emit `WARNING: No ADR directories found. Skipping validation.`, set `Overall: PASS`, stop.2526## Step 2 — Validate each directory2728For each dir in `adr_dirs`, run checks below. Track failures as `issues`.2930### Check 2.1 — ADR file structure31321. List files matching `NNNN-*.md` (1+ digits, hyphen, any chars, `.md`).332. For each ADR file, verify:34 a. **Status present/non-empty:** Line matching `**Status:**` or `## Status` with non-empty value. Else: `[ADR-NNNN] Missing or empty Status field`35 b. **Context non-trivial:** `## Context` body has ≥1 non-blank non-placeholder line (not solely whitespace, `TODO`, `TBD`, or template guidance). Else: `[ADR-NNNN] ## Context section is empty or contains only placeholder text`36 c. **Decision non-trivial:** Same for `## Decision`. Else: `[ADR-NNNN] ## Decision section is empty or contains only placeholder text`37 d. **Consequences present:** `## Consequences` section exists (content may be brief). Else: `[ADR-NNNN] ## Consequences section is missing`38 e. **Consequences quality (style):** Model judgment — ≥1 genuinely adverse outcome (risk, trade-off, migration cost, complexity increase, regression, reduced flexibility, or explicit statement of what's given up). If absent, **style warning** (not structural): `[ADR-NNNN] Consequences section contains no clearly adverse consequence or trade-off — consider adding one for credibility`. Style warnings don't affect pass/fail.3940### Check 2.2 — Index sync *(whole-dir mode only)*41421. If `<dir>/README.md` missing: issue `README.md index is missing from <dir>`. Skip index checks for this dir.432. Parse README.md table: extract all ADR filenames/numbers linked in table.443. Each ADR file w/o table entry → issue: `[ADR-NNNN] ADR file exists but has no entry in README.md index`454. Each table entry w/o matching file → issue: `[index entry] README.md references <filename> but file does not exist (orphaned entry)`4647### Check 2.3 — Cross-reference integrity *(whole-dir mode only)*48491. ADR with status `Superseded by ADR-NNNN`:50 a. Verify `NNNN-*.md` exists. Else: `[ADR-MMMM] Status says "Superseded by ADR-NNNN" but ADR-NNNN does not exist`51 b. Verify referenced ADR contains `Supersedes: ADR-MMMM`. Else: `[ADR-NNNN] Missing "Supersedes: ADR-MMMM" back-reference`522. ADR with `Supersedes: ADR-NNNN`:53 a. Verify `NNNN-*.md` exists. Else: `[ADR-MMMM] References "Supersedes: ADR-NNNN" but ADR-NNNN does not exist`54 b. Verify ADR-NNNN status is `Superseded by ADR-MMMM`. Else: `[ADR-NNNN] Expected status "Superseded by ADR-MMMM" but found different status`5556## Step 3 — Build the validation report5758Separate Check 2.1e items into `style_warnings` (not structural, don't affect status).5960Per validated target: structural issues (2.1a–2.1d) present → FAIL, else PASS.6162Output report (header rows **always present**):6364```65ADR Check Report66================6768Mode: Global | Scoped (file) | Scoped (directory) | Scoped (query)69Target: <path, directory, or natural-language query>70ADRs: <comma-separated list of all validated ADR filenames>7172Results73-------74<path/to/directory-or-file>:75 Status: PASS | FAIL76 Issues:77 - [ADR-NNNN] <issue description>7879<path/to/next-item>:80 Status: PASS81 Issues: none8283Style Warnings (advisory only — not gate-blocking)84===================================================85 - [ADR-NNNN] <style warning message>8687Overall: PASS | FAIL88```8990Global/scoped_dir → group by dir. scoped_file/scoped_query → each file own entry.9192`Style Warnings` section omitted if empty.9394Any entry FAIL → `Overall: FAIL`. On FAIL, append `Remediation` section (each issue + fix action).9596## Step 4 — Diff-based warnings *(Global only — skip all scoped sub-modes)*97981. Run `git diff HEAD`.992. Scan for:100101 | Pattern | Warning |102 |---------|---------|103 | `+` lines defining new ABC/interface (Python `class Foo(ABC)`, `abstractmethod`, Java/TS `interface`, Go `interface` with multiple methods, TS `abstract class`) | "New interface/ABC detected in `<file>` — consider documenting the design decision with `/adr-create`" |104 | `+` lines in new file matching `*Config*`, `*Settings*`, `*Configuration*` (case-insensitive) | "New configuration file `<file>` — consider documenting configuration decisions with `/adr-create`" |105 | `+` lines in `package.json` (deps/devDeps), `pyproject.toml` ([tool.poetry.dependencies]/[project]), `Cargo.toml` ([dependencies]), `go.mod` (require) | "New dependency added in `<file>` — consider documenting the technology choice with `/adr-create`" |106 | New root/top-level dir named `service`, `module`, `component`, `pkg`, `lib`, `api`, or `gateway` | "New service/module boundary `<dir>` — consider documenting the architectural boundary with `/adr-create`" |1071083. Warnings found → append to report:109 ```110 Diff-Based Warnings (advisory only — not gate-blocking)111 ========================================================112 - [WARNING] <message>113 ```114 No warnings → omit section.115116## Step 5 — Output and exit117118Print full report.119120- **PASS** (with/without diff/style warnings): success. Gate consumers continue.121- **FAIL**: failure. Gate consumers block; present remediation to user.122123## Additional Resources124125- **`references/adr-check-contract.md`** — Full contract: discovery rules, checks (2.1–2.3, 2.1e), report format, pass/fail semantics, invocation modes.