When the code moves on, a stale CLAUDE.md or AGENTS.md makes your agent run the dead command and edit the moved file, every session. Staleguard finds those lines, and the same lies in your READMEs, by checking them against the actual codebase.
$ brew install Arthur920/tap/staleguard
How it works
No models, no network: every check is deterministic, fast (~1.2s on 330k LOC), and tuned to under-report rather than false-alarm. Everything runs locally, and code never leaves the machine.
Scan every doc and agent rule for concrete assertions: paths, commands, env vars, flags, and code symbols.
Parse the repo in parallel into a ground-truth index: symbols and references.
Check every claim against the index. Each claim either resolves or it doesn't.
Emit a finding only when the code contradicts the doc, each with the exact doc reference and code anchor.
What it catches
npm run, make) with no matching script or targetCLAUDE.md, AGENTS.md, Cursor / Windsurf / Cline rules--diff <ref> reports only drift introduced since a refGet started
One small binary, no models to download.
Homebrew, an install script, or from source. Then run check on the full repo.
# Homebrew (macOS / Linux) $ brew install Arthur920/tap/staleguard # or with npm $ npx staleguard check # or from source $ cargo install --git https://github.com/Arthur920/Staleguard $ staleguard check # full repo
staleguard check exits non-zero on any finding. With --diff, a PR fails only on drift it introduces.
# in CI on each PR (checkout with fetch-depth: 0) $ staleguard check --diff origin/main
A Claude Code Stop hook makes the agent check its own changes before it finishes, and fix any drift it introduced. Other agents can run --format json and read the findings back.
# .claude/settings.json → hooks.Stop[].hooks[].command $ grep -q '"stop_hook_active": *true' || staleguard check --diff HEAD >&2 || exit 2 # exit 2 hands the findings back to Claude, which fixes them; # the grep lets the next stop through, so it never loops