| name | ad-drift |
| description | Read-only drift audit — compare AGENTS.md, ARCHITECTURE.md, ADR statuses, feature specs in doc/specs/, and documentation discipline against what the code actually does. Outputs a drift list, never writes files. Use when the user wants to audit, review for drift, sanity-check, or report inconsistencies between the repo's docs and its code. |
| summary | Read-only drift report comparing AGENTS.md / ARCHITECTURE.md / ADRs against the code. |
| allowed-tools | Read, Glob, Grep, Bash |
/ad-drift
Read-only. Produces a drift list comparing the repo's operational docs against what the code actually does. Writes nothing — the user decides whether to fix the spec or the code.
Step 1 — Decide what to audit
If the user names an artifact (AGENTS.md, ARCHITECTURE.md, ADRs, specs), audit only that. Otherwise audit all categories below.
Step 2 — Run the deterministic scan
The mechanical checks — artifact numbering, Status: validity, supersession-target existence, amendment-pair matching, emoji in narrative docs, checkbox UI in definition docs / specs, and AGENTS-to-GUIDELINES reciprocity — are a bundled script (ADR-0057), not prose to re-derive by hand. Run it from the repo root and read its JSON:
node .claude/skills/ad-drift/scripts/drift-scan.mjs
If this skill loaded from a different base directory (stated at the top of the skill load), substitute it — the script lives at scripts/drift-scan.mjs inside it.
The JSON carries numbering (per decision-record layer adr / specs, each with duplicates and gaps), status (adr / specs, records with a missing or out-of-enum Status), supersession (dangling superseded by targets), amendmentPairs (unpaired Amends / Amended by declarations), emoji ({path, line} in narrative docs), checkbox ({path, line} of checkbox UI in definition docs / specs, fenced examples excluded), constitutionReciprocity (an applicable flag and duplicateSections entries {section, guidelinesSection, line}), and unreadable ({path, code} — files the scan could not read, so any check over them is missing; report the gap). A reciprocity entry means that a mapped AGENTS heading exists but lacks its designated GUIDELINES.md section pointer; an absent heading is valid, and a pointer may retain a short operational subset. Tasks are not a numbering/status layer here (the audit has no task-drift category — tasks surface only under spec reciprocity, which stays judgment below). Step 3 narrates these facts; everything the scan does not compute below is judgment you perform by reading.
Step 3 — Interpret checks
AGENTS.md drift (if present)
- Stack — does the listed stack match
package.json / pyproject.toml / Cargo.toml / go.mod / equivalent?
- Setup/build/test commands — do they match
package.json#scripts, Makefile, or pyproject.toml?
- Quality gates — do referenced hook configs exist (
.husky/, .pre-commit-config.yaml, .github/workflows/)?
- Repository layout — do referenced directories exist?
- Pre-approved commands — anything in the list missing from the toolchain?
- AGENTS-to-GUIDELINES reciprocity — when
constitutionReciprocity.applicable is true, report each duplicateSections entry as a duplicate detailed-rules finding. A missing mapped heading is valid; a designated pointer within the heading is valid even with a short operational subset.
ARCHITECTURE.md drift (if present)
- Layers and boundaries — do the named directories exist? Sample 1–2 files per layer; are imports respecting the stated boundaries?
- Patterns — sample one handler / one repository / one entry point. Do they follow the documented pattern?
- No
## Active ADRs section — ARCHITECTURE.md must not duplicate the doc/adr/ directory index per ADR-0030 §2.
ADR drift (if doc/adr/ exists)
-
Numbering — numbering.adr: duplicates (two records sharing a number) is always drift. gaps is informational and expected wherever /ad-archive hard-deletes completed records (git history is their ledger); treat a gap as drift only when the project does not archive and the missing number is unexplained.
-
Status field — status.adr lists every ADR whose Status is missing or outside proposed | accepted | deprecated | superseded.
-
Superseded chains — supersession (its adr entries) lists every "superseded by ADR-NNNN" whose target record is absent.
-
Amendment pairs — a partial supersession is declared as a header-field pair: **Amends:** on the amending record, **Amended by:** on the amended one. amendmentPairs pre-computes every unpaired declaration, comparing relations, not filenames (A declares Amends: B must be answered by B declares Amended by: A) — this is why a keyword sweep for supersed|amends is not the check: it reports records that merely discuss the vocabulary or state they augment rather than supersede.
Know the limit: this check is silent in a layer that never adopted the fields (amendmentPairs is empty). Measured across three repositories, the field check returned nothing there while a keyword sweep returned between one and ten hits per layer, much of it noise. So when a layer holds records whose prose claims supersession and carries no amendment field anywhere, say so once, as an adoption suggestion — do not enumerate a sweep's hits as findings. A signal firing on a quarter of a directory stops being read.
-
State projection contradicting a live record (only if the layer has one — <layer>/PROJECTION.md, the name rule 10 fixes; check every append-only layer, not just doc/adr/). Report a record the projection calls fully binding whose own header says otherwise (deprecated, superseded by, or an Amended by: the projection omits), and a record the projection lists as retired-in-part that carries no such marker. A missing projection is not a finding — rule 10 permits one, it does not require one; flagging absence would turn a permission into an obligation the rule never granted.
Spec drift (if doc/specs/ exists)
Structural integrity only — does not deep-audit spec text against shipped code (deferred per ADR-0011 Consequences).
- Numbering —
numbering.specs: duplicates is drift, gaps informational (as for ADRs).
- Status field —
status.specs lists every spec whose Status is missing or outside draft | accepted | shipped | superseded.
- Superseded chains —
supersession (its specs entries) lists every "superseded by SPEC-NNNN" whose target is absent.
- Reciprocity — the scan does not compute this; read it. Every task under
doc/tasks/NNNN-*.md whose Spec ref field is non-empty points to a spec that exists. And every spec with Status: accepted or shipped has at least one entry in its Related → Tasks list (an accepted spec with no implementing task is a smell).
- No checkbox UI — per ADR-0030 §1, Spec is decision-record (not tracking). Functional Requirements / Non-functional Requirements / Success Criteria sections must use plain bullets, not
- [ ] checkboxes; implementation tracking lives in per-Spec tasks. checkbox (its doc/specs/ entries) pre-computes these.
- Status / task aggregate alignment — the scan does not compute this; read it. When every task that references a spec is
done, the spec's Status should be shipped. A spec with all tasks done but Status: accepted is drift between work-unit completion and feature-level claim.
Documentation discipline drift (WORKFLOW.md §2 / ADR-0008)
Audit narrative documents — README.md, AGENTS.md / CLAUDE.md, ARCHITECTURE.md, DESIGN.md, and prose pages under doc/ that are not lifecycle-managed artifacts under doc/product/, doc/specs/, doc/adr/, or doc/tasks/:
- Emoji —
emoji lists every {path, line} in the fixed narrative-doc set. Rule 3 forbids emoji anywhere (docs, code, comments, commits, skill outputs), so extend by eye to code/comments and to any non-lifecycle prose page under doc/ — the scan's fixed doc set does not reach those.
- Dates / version stamps /
DRAFT markers / changelog blocks in narrative documents — Rule 2 forbids these. Lifecycle-managed artifacts under doc/product/, doc/specs/, doc/adr/, and doc/tasks/ are exempt.
- Business context first — does the first paragraph answer why the document exists, before what and how? Rule 4.
- Scope duplication — does the document copy material that is canonically owned by another file (
AGENTS.md repeating ARCHITECTURE.md patterns; README.md re-stating ADR rationale)? Rule 5 requires linking, not copying.
- Speculation — phrases like "we might", "in the future", "could be added", or roadmaps without an ADR / task reference. Rule 1 forbids unfounded plans.
Source code (sample, not exhaustive — flag findings, not every match):
- Orphan
TODO / FIXME — Rule 7. A reference to a GitHub Issue or a doc/tasks/NNNN-*.md task file makes it not orphan.
- Commented-out code blocks — Rule 7. Removed code lives in git history.
Single-responsibility drift (ADR-0030)
Per WORKFLOW §2 rules #9–#12, definition-layer documents do not take on tracking or duplicate other layers' indices, and WORKFLOW.md stays universal:
- Definition-layer tracking UI (Rule #9) —
checkbox lists checkbox UI ({path, line}) in AGENTS.md, WORKFLOW.md, ARCHITECTURE.md, GUIDELINES.md, CONTEXT.md, doc/product/*.md, and specs, with fenced code-block examples (e.g., PR-body shape) already excluded. Definition documents must not carry per-item checkbox UI.
- Directory-as-index duplication (Rule #10) — flag sections that re-state another layer's index. Concrete patterns:
## Active ADRs inside ARCHITECTURE.md or AGENTS.md; multi-bullet ## Architectural Principles digests that paraphrase each ADR; PRD ## Related → ADRs bullet lists that enumerate the kit's ADR ledger. Not a finding: a layer's own state projection inside its own directory — rule 10 sanctions exactly one per append-only layer. It is a finding when that projection only lists records without saying what still binds, which makes it a duplicate index wearing the exception's name.
- Kit-state in
WORKFLOW.md (Rule #12) — grep ADR-[0-9]\{4\} in WORKFLOW.md. Universal philosophy must not cite kit-specific ADR numbers (downstream installs receive WORKFLOW.md without doc/adr/). Literature citations (named books / papers) and generic doc/adr/ directory references are allowed.
- Cross-references that are decoration (Rule #11) — sample inline ADR refs (
per ADR-NNNN) in narrative documents and apply the load-bearing test: if you delete the reference and the surrounding statement still stands, the reference was decoration; flag it. Judgment-call; surface as findings, not as automated reject.
Step 4 — Output
One line per finding, formatted:
[file or section]: spec says X, code says Y. Suggested resolution: change spec / change code / discuss.
Group by artifact. If a category has no drift, print one line: AGENTS.md — no drift. etc. If an audited artifact does not exist, say so explicitly rather than reporting zero findings. The Documentation discipline drift category groups its own findings under Documentation discipline — <category>: ....
If something the user says contradicts what the code shows, surface the conflict. Don't silently trust the user; don't silently trust the code.
Output contract
A drift list, no file written. Read-only operation. Empty result is reported explicitly ("no drift found across audited artifacts"), not silently. Missing artifacts are flagged, not skipped.
Next
- Address each finding with one of the three resolutions named in the format ("change spec / change code / discuss").
- For findings that require implementation:
/ad-task to scaffold the fix.
- For workflow drift (where am I, what's stuck):
/ad-next.
- For kit-version drift (state file behind current kit):
agentic update.