fully local · offline · deterministic

Staleguard

Keep your agent instructions true

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

Deterministic, from docs to verdict

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.

01Read docs

Extract claims

Scan every doc and agent rule for concrete assertions: paths, commands, env vars, flags, and code symbols.

02Read code

Index with tree-sitter

Parse the repo in parallel into a ground-truth index: symbols and references.

03Compare

Resolve each claim

Check every claim against the index. Each claim either resolves or it doesn't.

04Report

Only provable misses

Emit a finding only when the code contradicts the doc, each with the exact doc reference and code anchor.

What it catches

What a stale doc looks like

// REFERENCES

Broken references

  • file/dir paths quoted in docs that don't exist
  • commands (npm run, make) with no matching script or target
  • env vars & flags documented but never read
  • qualified code refs that resolve to no symbol
// AGENTS

Agent instructions

  • CLAUDE.md, AGENTS.md, Cursor / Windsurf / Cline rules
  • slash commands and skills that point at missing files
// DRIFT

Only new drift

  • --diff <ref> reports only drift introduced since a ref
  • caught whether the doc or the code changed

Get started

Install, run, gate CI, wire into agents

One small binary, no models to download.

Homebrew, an install script, or from source. Then run check on the full repo.

shell
# 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.

.github/workflows
# 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.

agent
# .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