Toolnotes

Notes on access-control bugs and AI-agent instruction drift, from the people who built entitlement-guard and baton to catch them.

View the Project on GitHub Ayinla10/toolnotes

Your AGENTS.md is already stale — here’s how to catch it without another LLM call

Multi-agent setups — Claude Code, Codex, or any workflow built around CLAUDE.md/AGENTS.md-style convention files — share a habit: they keep a “here’s the state of the world” file that every new agent session is supposed to read before acting, and every finishing session is supposed to update. In practice, the update step is the one that slips. Real commits land, the memory file doesn’t get touched, and the next agent session starts from a picture of the repo that’s already wrong.

This isn’t a hypothetical. It’s independently documented as the same failure mode by people who aren’t us: dev.to has “Your AGENTS.md Is Already Stale — And Your Agent Trusts It Completely,” and nuvikatech.com has “The Clone That Didn’t Get the Memo: Worktree CLAUDE.md Drift” — both 2026, both describing a stale instruction file that an agent trusted anyway, because nothing told it not to. The framing that stuck with us: a stale entry is worse than a missing one, because it resolves ambiguity in the wrong direction with full confidence.

Two ways to catch it

Once you accept the file rots, you need something checking it against reality. There are two structurally different ways to build that checker.

LLM-driven. ClaudeForge ships a claude-md-drift-audit skill that runs as a forked Claude Code subagent (context: fork, agent: Explore): it walks recent git history, greps the CLAUDE.md files in the tree, and has the model synthesize a punch list of stale references. It’s genuinely useful, and it’s only available inside a Claude Code session — every audit is a live agent invocation, which means it costs tokens per run and can’t be dropped into a generic CI job as a standalone binary with an exit code.

Deterministic. We built baton as the other kind: a plain CLI, regex- and git-log-based, no API calls, no tokens, no network dependency beyond git itself. It reads the state file’s own ## Last Updated claim, looks at every commit since that date, and reports:

It exits 1 on drift, so it works as a CI gate the same way a linter does — same behavior on a laptop, in CI, or in an air-gapped environment, since there’s no model call to route through.

Which one to use

They’re not really competing for the same moment. If you’re already inside a Claude Code session and want a model’s read on what’s stale, claude-md-drift-audit is a reasonable ad hoc check. If you want a gate that runs identically in CI on every PR, with zero marginal cost per run and no dependency on which agent harness happens to be active, that’s what baton is for:

git clone https://github.com/Ayinla10/baton && cd baton
npm install && npm run build && npm link
baton check --fail-on-drift

Free, MIT-licensed, and it was built to solve our own problem first — we run a multi-agent setup with a shared state file, and this is the tool that stopped us from feeding stale context back into every new session.