Sheet 1 of 1 Revision 0.5.0 Node 24+ No config, no API key, no network MIT
58 of 66 real repositories produce zero false positives.
See the surveyAn out-of-date README confuses a person, who notices and asks. An out-of-date
CLAUDE.md hands the agent a false premise that it executes with
confidence: it runs a script that no longer exists, edits a file that moved,
follows an abandoned convention.
The cost is not confusion, it is incorrect work with no error signal.
Linters check your code. Nothing checks the document you wrote about your code.
Unlike code, these files have no compiler, no tests, no linter. They are the one part of the repo where lying has no mechanical consequence.
Struck in overprint: a claim the ground contradicts. Written beneath it: the correction, only when exactly one candidate clears 0.8 confidence.
npm/pnpm/yarn/bun run, deno task and
make, against the nearest package.json, Makefile or
deno.json. No manifest anywhere means silence.
fixable
SKILL.md names itself something other than its directory —
the folder was renamed and the frontmatter did not follow. Not a format
validator: a name in snake_case or a four-word description are real
problems and none of them are drift, so this does not report them.
fixable
--skip link/broken turns that check off everywhere--only path keeps only that family, and a prefix matches, so
--only path and --only path/missing both workchecks: in the config file makes either permanent, or demotes a check to a
warning instead of silencing itA selection that leaves no check enabled is refused.
--fix touches the mechanically verifiable fragment of a line
and nothing around itA linter that shouts too much gets uninstalled on first use. So driftwatch stays silent when it is unsure, and every discard rule in the extractor carries a comment naming the false positive it prevents. This is the measurement, over context files their authors wrote without knowing driftwatch exists.
341 context files66 repositories pinned to a commitnine languages
checked, no drift says something untrue One mark is one file, one run is one repository. Point at a run, or tab in and use the arrow keys.
A lit mark is a context file driftwatch reported anything at all about: 29 of the 341, carrying 37 findings between them, and 27 of those are true drift the maintainers had not noticed. The four figures below count only the false ones.
--fix would apply across all 66<name>,
{{path}}, $VAR, [id], EventNameHere
feat/Twenty-six rounds, every finding classified by hand, including the four rounds where a condition broke and the two where the corpus caught a regression that reading the diff would not have.
Eleven false-positive classes have been found and closed, each with a fixture and a test naming the repository and line it came from. Every fix was measured over the whole corpus before being kept, and not one of them has ever removed a true positive.
The corpus does not run in CI, because the verdict requires a person. CI can detect that a snapshot changed; it cannot rule on whether the change is an improvement, and that ruling is the measurement.
Fifty of the sixty-six repositories in the corpus report nothing at all. A tool built to stay quiet when it is unsure is quiet most of the time, so a first run has three possible endings and only one of them reports drift.
✓ 14 files · no drift · 210ms
Fourteen context files, every claim in them checked against the repository. Exit code
0.
The file count is the proof that it looked at all. --json
carries summary.claims beside it: how many individual assertions were
verified. That is the only thing that tells nothing to find apart from
nothing found. In CI, where nobody reads the output of a green run, it is the
only number worth asserting on.
✓ 0 files · no drift · 12ms
Zero files does not mean your documents are clean. It means driftwatch found none to read, and it is the one result worth checking.
Discovery runs off git ls-files, so .gitignore is
respected for free, and anything it hides is invisible to driftwatch too. A repository
with no .git falls back to a glob walk.
AGENTS.md, at any depthCLAUDE.md, CLAUDE.local.md<root>/skills/**/SKILL.md, where <root> is
.claude, .agents, .cursor,
.codex, .github or .opencode. There is no single one, and .claude/ is not the
busiest: npx skills add writes to .agents/ by
default..claude/agents/*.md.claude/commands/**/*.md.cursorrules, .cursor/rules/**/*.mdc.github/copilot-instructions.mdAnything else, name it yourself: driftwatch docs/ AGENTS.md
audits only those paths, and a sources: key in the config makes it
permanent.
AGENTS.md
✗ 3 src/util/date.ts path does not exist → src/helpers/date.ts?
✗ 5 src/cli.ts path does not exist
1 file · 2 problems (2 errors) · 59ms
1 fixable with --fix
A claim in your own repository that an agent would have believed, on the line that makes
it. Exit code 1.
file:line is clickable in a modern terminal, so the fastest
next move is to open the line and read what it claims. The arrow is a suggestion, and
--fix --dry-run prints the exact rewrite before anything is written to
disk.
It will happen: six of the corpus's twenty-six findings are false. The recovery is a comment in the document itself, next to the claim it covers.
<!-- driftwatch-ignore-next-line -->
`src/planned/feature.ts` does not exist yet, it is the plan
<!-- driftwatch-ignore path/missing -->
<!-- driftwatch-ignore-file -->
With no id it silences every check on that line; with an id, only that one. Directives apply to findings rather than to claims, so an id you misspell silences nothing and the finding still shows up.
The first run tells you whether your documents are true today. Keeping them true is the part that has to happen on every change, which is what CI is for.
With --fix the exit code describes what is left, so a
repository whose only error was autofixable exits 0. Code 2 is
reserved for driftwatch itself failing (bad config, a path that does not exist, a crash) and
never means drift.
A wrong fix is not noise, it is a document that now points confidently at the wrong file, and the next agent will believe it.
So --fix applies a correction only when there is exactly one candidate above 0.8
confidence. It replaces the claim and nothing around it. And it refuses outright to rewrite
a relative path in a document that is not at the repo root.
Terminal
$ driftwatch --fix --dry-run # what it would change
$ driftwatch --fix # change it
Try both in the field book above. It prints the real output.
.github/workflows/ci.yml
- uses: actions/checkout@v7
- uses: abr4xas/driftwatch@v0.5.0
fail-on-drift: false makes it advisory. sarif: true
writes a file for Code Scanning.
paths Paths to audit, space separated. Empty means the whole
repository.only / skip Run only these checks, or everything except
them. A prefix works: path.format pretty | json | github | sarif. Annotations are
the reason to run this in CI.sarif Write a SARIF file and expose its path as an output.
fail-on-drift Whether drift fails the job, or only annotates
it.working-directory Where to run. Defaults to the workspace
root.pretty--jsonversion is what
you branch on, and it is 1.--github--sarifstdout is the report, stderr is everything else, and the exit code does not depend on the format.