Use for the whole-estate doc audit, "run the doc-drift loop", "audit the docs against the code", "are the docs still true", "doc drift sweep", "check every doc claim", or a scheduled doc-audit cadence run. NOT for diff-scoped doc sync inside a build cycle (/kit:docs), NOT for dated records like specs, research, retros, NOT for one known-wrong doc (just fix it).
Installs into .claude/skills of the current project.
Are you the author of Doc Drift?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/dwarvesf-doc-drift)
---
name: doc-drift
description: Use for the whole-estate doc audit, "run the doc-drift loop", "audit the docs against the code", "are the docs still true", "doc drift sweep", "check every doc claim", or a scheduled doc-audit cadence run. NOT for diff-scoped doc sync inside a build cycle (/kit:docs), NOT for dated records like specs, research, retros, NOT for one known-wrong doc (just fix it).
disable-model-invocation: false
---
# Doc drift
## Scope and triggers
Enumerates every LIVING doc (README, MANUAL, AGENTS, WORKFLOW, architecture, patterns), verdicts each against the live repo with evidence, fixes drift on a branch, gates through a PR. An audit-loop instance (docs/patterns/audit-loop.md). Dated records like specs, research, retros describe their moment and never drift.
## Overview
Audit every living doc against the live repo and ship the fixes as a PR. This is the doc-drift
instance of `docs/patterns/audit-loop.md`: enumerate, verdict with evidence, apply on a branch,
gate through a PR the operator approves. `/kit:docs` syncs docs against ONE diff during a build
cycle. This skill audits the WHOLE estate on a cadence, and catches what diff-scoped sync
structurally misses: drift from merged-but-undocumented work, inventory rot, dead pointers,
stale counts. PR #306 (hand-fixing the README inventories) is the proven need.
## The four slots (per the audit-loop pattern)
| Slot | This instance |
|---|---|
| Item set | living docs only: `git ls-files README.md MANUAL.md AGENTS.md CLAUDE.md CONTRIBUTING.md ':(glob)docs/*.md' ':(glob)docs/patterns/*.md'` (the `:(glob)` magic is required: a bare `docs/*.md` pathspec matches recursively and pulls in every dated record) |
| Contract | every checkable claim matches the live repo: referenced paths exist, inventory tables match the live dirs, counts match derived counts, named verbs and flags exist, cross-doc pointers resolve |
| Evidence class | Tier 1: the repo itself via grep/ls/diff. Tier 2: a model reads the doc's described behavior against the actual command or script |
| Apply mechanics | FIX in place on an isolated branch; REMOVE only with a named successor; PR body lists every verdict; UNSURE never auto-resolved |
Dated records (docs/specs, docs/research, docs/retro, docs/handoff, docs/decisions,
docs/absorption, and docs/CHANGELOG.md's per-release entries) are OUT of the item set. They describe their moment. Flagging a 2026-05 spec
for describing 2026-05 reality is noise, not a finding.
## Process
1. **Branch first.** All edits ride an isolated branch. Auditing on master is the failure this
skill exists to prevent.
2. **Enumerate.** Run the item-set command above. Write the list down before judging anything.
The list is the queue; a resumed or scheduled run picks up where the last one stopped.
3. **Tier 1, mechanical pass, zero model cost, every file.** For each doc, extract and check
the mechanical claims:
- every backtick path or file reference resolves (`ls` it),
- every inventory table row maps to a live file (`diff` the table names against the dir
listing, both directions: rows with no file, files with no row),
- every hardcoded count matches the derived count (`ls | wc -l`),
- every named command, verb, or flag appears in the target script or its `--help`.
- every ASCII/box diagram node whose label names a file, module, or symbol resolves:
`test -e <path>` for a path, `grep -n <symbol> <path>` for a symbol. A diagram node
that names a path is a claim and gets checked like prose (source: archify's
validated-IR contract, a diagram node cites a source and a check verifies the
citation still holds). A missing target is a Tier 1 FIX, quoting the node text.
A Tier 1 failure is a finding with evidence attached, severity FIX (or REMOVE when the whole
doc's referent is gone). `bash tests/test-meta.sh` overlaps part of this pass; run it first
and treat its failures as pre-confirmed findings, do not re-derive them.
4. **Tier 2, judgment pass, model-read, only where it earns its cost.** Dispatch the shared
read-only scanner `kit:audit-scanner` (preferred: its tools roster physically cannot write,
so an unattended cadence run keeps the propose/apply split mechanical; fall back to a
general-purpose subagent only where the kit agent roster is unavailable, e.g. a frozen
plugin snapshot). Dispatch only for: files Tier 1 flagged (the drift is confirmed, judge
how deep it goes), plus the high-traffic operator surfaces (README, QUICKSTART, AGENTS)
whose prose describes behavior no grep can check. Hand it the target files, this
instance's contract and evidence class (the four-slots table above): does the described
flow still match what the command actually does? It quotes both sides for any mismatch
and returns findings; every fix is applied HERE, on the branch, never by the scanner.
Skip Tier 2 entirely for files Tier 1 cleared that only carry mechanical claims.
5. **Verdict each item** with the audit-loop grammar: OK / FIX / REMOVE / UNSURE / DANGER. A
verdict with no checkable evidence downgrades to UNSURE. UNSURE items are never auto-fixed;
list them in the PR body. DANGER (a doc that tells the operator to do something now wrong)
gets quoted, folded into the policy-carrying doc, then removed or marked superseded.
6. **Apply.** Fix in place. Prefer deriving over restating: a count becomes "every X" prose or
a derived assertion, never a fresh literal (the no-hardcoded-counts rule). Before removing
any doc, grep the estate for pointers to it and rewrite them.
7. **Verify.** Re-run the Tier 1 pass on every touched file: it must come back clean. Run
`bash tests/test-meta.sh`: green, or the run is not done.
8. **Ship.** Commit, push, open a PR whose body lists every FIX/REMOVE with its evidence and
every UNSURE for the operator. If nothing needed changing, create no branch and report
CLEAN with the enumeration list.
## Cadence
Run after any batch of merges that skipped `/kit:docs`, before a release tag, or on a schedule
(`/loop` or a cron per the audit-loop driver ladder). One pass per invocation, bounded by the
enumeration list.
## Red flags
- Editing docs without the branch: stop, branch, start over.
- "Obviously outdated" with no quoted evidence.
- Dispatching Tier 2 reviewers for every file when Tier 1 cleared most of them: the cheap-first
split exists to prevent exactly this spend.
- Writing a fresh hardcoded count while fixing a stale one.
- Auditing dated records: out of scope, always.
## Cadence
This instance has a declared cadence in the `## Cadence` table of `docs/patterns/audit-loop.md`.
Record a finished pass with `bin/audit ran doc-drift "<one line>"`, including a CLEAN one, so
`bin/audit due` stops naming it. The kit ships no scheduler: `due` is what a human or a job reads.