🪨 why use many token when few token do trick — Claude Code skill that cuts 65% of tokens by talking like caveman
CLI linter for agent context files and skills
driftlint scans agent-facing files like `CLAUDE.md`, `AGENTS.md`, skills, rules, and related config to find claims that no longer match the repo. It reports dead paths, removed commands, stale links, and other drift, then offers fixes and CI-friendly output.
Builders who maintain Claude Code, Codex, Cursor, or other agent context files and want them to stay accurate.
You can catch stale instructions before your agent follows a deleted path, command, or link.
What it does
Dead reference checks
Finds missing files, renamed scripts, and broken markdown links against the actual repo tree.
Skill and context budget checks
Flags skill descriptions and context files that can silently stop loading because they exceed known limits.
Twins sync and drift detection
Keeps `CLAUDE.md` and `AGENTS.md` mirrored, and warns when the copies diverge.
Reviewed Memory workflow
Lets agents propose memory entries, humans review them, and approved entries sync back into context files.
Diff mode and CI output
Scans only new drift from a PR and can emit JSON, SARIF, or reviewdog format.
Claude Code plugin and MCP server
Adds a `/driftlint` command and MCP tools so agents can check their own context before writing it.
How to get it
- 1Deterministic checks can't see narrative claims. --llm extracts them from your context…
npm install @anthropic-ai/sdk # optional peer dependency, only needed for --llm export ANTHROPIC_API_KEY=sk-ant-... # or `ant auth login` npx @alifurkangokce/driftlint --llm npx @alifurkangokce/driftlint --llm --llm-model claude-haiku-4-5 # budget option
- 2Run
claude mcp add driftlint -- npx -y @alifurkangokce/driftlint-mcp
- 3Run
npx @alifurkangokce/driftlint --update-baseline # record today's findings
README
driftlint
Your CLAUDE.md is lying to your agent. driftlint keeps agent context files true, two ways: a drift linter that finds the claims in CLAUDE.md, AGENTS.md, skills, subagents and cursor rules that your code no longer supports — and Reviewed Memory, the missing approval layer between what your agents learn and what your team ships into CLAUDE.md.
npx @alifurkangokce/driftlint # lint this repo
npx @alifurkangokce/driftlint twins # keep CLAUDE.md and AGENTS.md in sync

Zero config. No API key. Zero runtime dependencies. Works on any repo.
The two-file problem: Claude Code reads CLAUDE.md; Codex, Cursor, Amp and 30+ other tools read AGENTS.md. Asking for both is the most-upvoted request on the Claude Code tracker — 5,200+ reactions, marked not planned — so teams keep two copies, and the copies drift silently.
driftlint twins --checkis the CI gate for that; thetwin-driftrule catches pairs that already diverged.
Why
Coding agents trust context files completely. But code moves and context files don't: the file you renamed in March is still "the entry point" in CLAUDE.md, the deploy:prod script you deleted is still the documented release path, and the skill you wrote last month is silently invisible because your skill descriptions overflowed the system-prompt budget.
Agent knowledge decays like code documentation always has — except now the reader can't tell something is off. It just follows the instructions.
The research backs this up: an ETH Zurich evaluation measured that auto-generated context files reduce agent success while minimal human-written ones help — so the winning move is keeping the human-written file true, not generating a new one. And a 2026 study of 247k instruction lifetimes ("Why Does CLAUDE.md Keep Growing?") found context files gain ~5 instructions per commit and almost never shrink, because once a rule's rationale is lost nobody dares delete it — which is why every Reviewed Memory entry carries its evidence and provenance.
Reviewed Memory (beta)
Agents keep relearning the same repo facts, and pasting them into CLAUDE.md by hand doesn't scale to a team. Reviewed Memory closes the loop:
driftlint memory propose --text "Auth goes through the BFF." --evidence src/auth.ts:42 # the AGENT does this
driftlint memory review # the HUMAN approves/rejects, one entry at a time
driftlint memory sync # approved set → a marked block in CLAUDE.md / AGENTS.md / GEMINI.md
Why it works: the synced block lives in the files every agent CLI already reads (no hooks, no daemon), git distributes it via ordinary PRs, and driftlint scans .agent-memory/ and the block itself — so when the code moves, the memory that references it gets flagged like any other drift. Claude Code users get a /memory-propose command with the plugin. The propose → human-review → commit flow aligns with the governance channel of the memorywire vendor-neutral memory wire format.
Auto-memory audit
Claude Code also keeps its own auto memory per project (~/.claude/projects/<project>/memory/) — and those memories decay exactly like context files, except they live outside the repo where no repo-scoped linter ever looks:
driftlint memory audit # finds the memory dir for the current repo automatically
It verifies every memory against the repo it describes: dead paths and removed commands referenced in memories, broken [[wiki-links]] between memories (resolved via filenames and frontmatter name: slugs), and a MEMORY.md past the 200-line / 25KB fold — everything below it silently never loads into a session. Memories that record facts about other repos are recognized and collapsed into one info line instead of a flood.
Twins: CLAUDE.md ↔ AGENTS.md
The most-upvoted request on the Claude Code tracker — support AGENTS.md, 5,200+ 👍 — is marked not planned. So teams using Claude Code next to Codex/Amp/Cursor keep both files, and the copies drift: someone fixes the test command in CLAUDE.md, AGENTS.md goes stale, and a week later half the team's agents follow the outdated copy. driftlint attacks this twice:
driftlint # the twin-drift rule flags pairs that already diverged
driftlint twins # mirror AGENTS.md into CLAUDE.md as a marked, idempotent block
driftlint twins --check # CI mode: fail when the mirror is stale
The twin-drift rule stays quiet for intentionally different files — it fires only on evidence: near-identical files with divergent lines, command claims that exist in one file but not the other, or a stale driftlint twins mirror. Pairs bridged with an @AGENTS.md import are recognized and skipped.
What it checks
| Rule | What it catches |
|---|---|
dead-path | Referenced files/dirs that no longer exist — with "did you mean src/util.ts?" hints when the file moved |
dead-command | npm run scripts and make targets that were removed or renamed |
skill-budget | Skill descriptions overflowing the ~15k-char system-prompt budget — skills past it are silently invisible to the agent |
stale-knowledge | Context files untouched for months while the code they describe churned heavily |
foreign-context | A file whose references mostly don't resolve — probably describes another repo; findings collapse into one warning instead of a flood |
narrative-claim | (only with --llm) Narrative claims ("auth goes through the BFF") that the code contradicts — verified with your own Anthropic API credentials |
template-context | Workflow files that describe a project this repo generates — collapsed into one warning instead of a flood |
load-budget | Content that silently never reaches the model: AGENTS.md past Codex's 32 KB truncation limit, files past the ~150-instruction adherence ceiling |
missing-rationale | Directive walls (never/always/must) with no stated reason — the rules nobody dares delete |
twin-drift | CLAUDE.md and AGENTS.md that carry the same instructions but diverged — differing command claims, drifted near-copies, stale driftlint twins mirrors |
untracked-context | Context files git doesn't track — your agent follows them, your teammates' agents never see them (CLAUDE.local.md is exempt by convention) |
dead-link | Markdown links whose target file moved, or whose #anchor heading was renamed — with the closest heading offered as a fix |
silent-config | Config in a shape or place the tool ignores: a plain .md under .cursor/rules (Cursor needs .mdc), a bare .md where a <name>/SKILL.md belongs |
dead-config-ref | Hooks, MCP servers, plugin manifests and skill allowed-tools pointing at scripts that don't exist — valid JSON, missing file |
dead-command is workspace-aware: a script that exists in another monorepo package is reported as a location warning ("defined in packages/client/package.json"), not a dead command.
Config that never loads
Schema validators check that your JSON is well-formed. driftlint checks whether the thing it points at is actually there — and whether the file will be read at all:
- a hook whose script was moved (
$CLAUDE_PROJECT_DIR/.claude/hooks/guard.sh) fails the first time it fires, silently - an MCP server whose local entry file is gone never starts (remote
npx/dockerservers are left alone) - a plugin manifest listing a command that isn't there installs fine and does nothing
- a plain
.mdunder.cursor/rulesis ignored by Cursor — no error, no rule - a skill whose
description+when_to_useruns past 1,536 characters loses the tail: that's where the skill listing truncates
Skills are discovered wherever the Agent Skills standard puts them — .claude/skills/ and .cursor/skills/ alike.
Usage
npx @alifurkangokce/driftlint # scan the current repo
npx @alifurkangokce/driftlint path/to/repo # scan another repo
npx @alifurkangokce/driftlint --fix # interactively apply safe fixes (--yes: all)
npx @alifurkangokce/driftlint --json # machine-readable output (CI-friendly)
npx @alifurkangokce/driftlint --sarif # SARIF 2.1.0 for GitHub code scanning
npx @alifurkangokce/driftlint --no-fail # report but always exit 0
npx @alifurkangokce/driftlint --diff # only drift THIS change caused (vs origin/main)
--diff is what you want on pull requests: it scans the merge-base in a temporary worktree, reports only findings that are new, and attributes them to the change — "this PR renames src/auth.ts → src/authn.ts; CLAUDE.md still references the old path" — with the fix derived from the rename. Pre-existing drift stays out of your PR.
Installed globally (npm i -g @alifurkangokce/driftlint) the command is just driftlint.
Exit code is 1 when errors are found, so it drops straight into CI. Or use the action:
# .github/workflows/driftlint.yml
on: [pull_request]
permissions:
security-events: write # only needed when sarif-file is set
jobs:
driftlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 } # full history enables the staleness check
- uses: alifurkangokce/driftlint@main
with:
diff: "true" # PRs: only report drift this PR caused
sarif-file: driftlint.sarif # optional: findings become PR annotations
Or as a pre-commit hook:
repos:
- repo: https://github.com/alifurkangokce/driftlint
rev: v0.7.0
hooks:
- id: driftlint
Optional LLM pass
Deterministic checks can't see narrative claims. --llm extracts them from your context files, greps the repo for evidence, and asks Claude whether the code contradicts them:
npm install @anthropic-ai/sdk # optional peer dependency, only needed for --llm
export ANTHROPIC_API_KEY=sk-ant-... # or `ant auth login`
npx @alifurkangokce/driftlint --llm
npx @alifurkangokce/driftlint --llm --llm-model claude-haiku-4-5 # budget option
Your key, your bill (default model claude-opus-5; capped at 10 files / 8 claims per file, token usage is printed). Findings are warnings marked needs review — the verifier is conservative: missing evidence is "unverifiable", never "contradicted". Without --llm, driftlint never touches the network.
reviewdog: one-click "Apply suggestion" on PRs
- run: npx -y @alifurkangokce/driftlint --rdjsonl --no-fail | reviewdog -f=rdjsonl -reporter=github-pr-review -filter-mode=nofilter
--rdjsonl emits reviewdog RDFormat where every did-you-mean fix becomes a committable GitHub suggestion. -filter-mode=nofilter matters: drift findings live on lines the diff never touched.
MCP server: agents lint their own context
claude mcp add driftlint -- npx -y @alifurkangokce/driftlint-mcp
Two tools from @alifurkangokce/driftlint-mcp: drift_scan (full report, optional diff_range) and drift_check — an agent about to edit CLAUDE.md verifies the reference before writing it, so it never writes a dead one.
Freshness badge
Every scan computes a deterministic context-freshness score (the share of path references that resolve; collapsed template/foreign files excluded). Put it in your README:
- uses: alifurkangokce/driftlint@main
with: { badge-json: badge.json, fail: "false" }
- uses: Schneegans/dynamic-badges-action@v1.7.0
with:
auth: ${{ secrets.GIST_SECRET }}
gistID: <your-gist-id>
filename: driftlint.json
contentFile: badge.json

Adopting on a legacy repo
npx @alifurkangokce/driftlint --update-baseline # record today's findings
This writes .driftlint-baseline.json; from then on only new drift is reported, so CI stays green while you pay down the backlog.
Config
Optional .driftlintrc.json at the repo root:
{
"skillBudget": 15000,
"ignore": ["docs/archive/**"],
"templates": [".claude/skills/**"],
"rules": { "dead-command": "off", "stale-knowledge": "info" }
}
Template repos (scaffolds, methodology kits)
If your repo generates other projects, its skills legitimately reference files that will exist in the generated project — driftlint would report those as dead. Three escapes: put a driftlint-template comment in the file, list globs under "templates" in .driftlintrc.json (both skip path/command checks with one info note), or let the auto-heuristic handle it — a skill/agent/command file with ≥2 unresolved references and generator vocabulary ("scaffolds", "will create", "your project") collapses into a single template-context warning. Root CLAUDE.md/AGENTS.md are never auto-suppressed: they describe this repo.
Suppress a single false positive with a comment on the same line or the line above:
<!-- driftlint-ignore -->
This mentions `hypothetical/example.ts` on purpose.
Scanned files
Everything an agent loads from the repo, nested directories included:
| Root instructions | CLAUDE.md, CLAUDE.local.md, AGENTS.md, AGENTS.override.md, GEMINI.md — anywhere in the tree |
| Rules | .claude/rules/**/*.md, .cursor/rules/**/*.mdc, .codex/rules/**/*.rules, .clinerules (file or directory), .windsurfrules |
| Skills (Agent Skills) | .claude, .cursor, .codex, .gemini, .github and .agents — all skills/**/SKILL.md |
| Sub-agents & commands | .claude/agents/**, .cursor/agents/**, .gemini/agents/**, .github/agents/*.agent.md, .claude/commands/** |
| Copilot | .github/copilot-instructions.md, .github/instructions/**/*.instructions.md |
| Other | .opencode/{agent,command,knowledge}/**, .agent-memory/** |
Machine-readable config is checked too (hooks, .mcp.json, plugin manifests) — see Config that never loads.
User scope. Codex and Claude Code also load an instruction file from your home directory, and it counts toward the same 32 KB budget as the repo's files. --user-scope folds ~/.codex/AGENTS.md and ~/.claude/CLAUDE.md into the total. It's off by default (CI has no such file, and reading someone's home directory during a repo lint should be a choice), and only the size is read — the content never enters a finding.
Claude Code plugin
driftlint also ships as a Claude Code plugin: a /driftlint command that runs the scan and then fixes the drift it finds (with your approval).
/plugin marketplace add alifurkangokce/driftlint
/plugin install driftlint@driftlint
How driftlint compares
| driftlint | agnix | reporails | ctxlint / agents-lint | claude-mem etc. | |
|---|---|---|---|---|---|
| Referenced paths, scripts and links verified against the tree | ✅ | ❌ structural only | ❌ documented as out of scope | ✅ | ❌ |
Hard vendor limits that truncate silently (Codex's concatenated 32 KB, the 1,536-char skill listing, .cursor/rules/*.md never loading) | ✅ | partial | ✅ per-agent caps, plus a 100 KB advisory aggregate (CORE:E:0001) | ❌ | ❌ |
| Memory files | ✅ contents verified against the repo — dead refs, broken [[links]], MEMORY.md past the load fold | ❌ | ✅ structure and size rules (CORE:S:0023) | ❌ | ❌ it is the memory store |
| Reviewed Memory workflow (agent proposes → human approves → synced → re-verified) | ✅ | ❌ | ❌ | ❌ | ❌ auto-capture, no review |
| CLAUDE.md ↔ AGENTS.md drift + a CI mirror gate | ✅ mechanical diff + twins --check | ❌ | partial — cross-agent conflict rules (CORE:C:0026, CORE:C:0046) | ❌ | ❌ |
| Instruction surfaces covered | project scope, nested dirs | broad | broadest — project, user and system scope | narrow | — |
| How well the instructions are written (clarity, structure, a 0–10 score) | ❌ by design | partial | ✅ 120+ rules | ❌ | ❌ |
| Structural / spec conformance, LSP, IDE plugins | ❌ by design | ✅ 454 rules | partial | partial | ❌ |
| Runs fully offline, no account | ✅ | ✅ | ❌ sign-in unlocks fix text and exact locations | ✅ | varies |
| License | MIT | MIT | BUSL 1.1 (Apache 2.0 after 3 years) | MIT | varies |
The overlap is real and growing, so here is the honest split:
- agnix checks that your files are well-formed — schema and spec conformance, with an LSP and IDE plugins.
- reporails checks how they are written and organised — clarity, structure, size ceilings, memory and rule surfaces across project, user and system scope.
- driftlint checks whether they are still true — every path, script, link and config reference resolved against the actual tree, and a review workflow for the knowledge agents add.
The last one is the part nobody else claims: a file can be perfectly formed, well written, correctly sized, and still tell your agent to run a script someone deleted in March.
What it touches
No runtime dependencies, no install scripts, no telemetry, and no network call — except --llm, which is the one flag that sends your context files to the Anthropic API. scan writes nothing; --fix prompts per edit and only rewrites inside the scanned root. Full statement: SECURITY.md.
Roadmap
See ROADMAP.md — next up: an optional LLM pass for narrative claims, then Reviewed Memory: agents propose knowledge at session end, humans approve via PR, git distributes it, and driftlint keeps it honest.
License
MIT
Files in the repo
- .claude-plugin
- .github
- commands
- docs
- mcp
- src
- test
- .gitignore
- .pre-commit-hooks.yaml
- action.yml
- AGENTS.md
- CHANGELOG.md
- CLAUDE.md
- CONTRIBUTING.md
- LICENSE
- package-lock.json
- package.json
- README.md
- ROADMAP.md
- SECURITY.md
- tsconfig.json
Discussion (0)
Ask about usage, or say what you built with itSign in to join the discussion.
No comments yet. Be the first to say what this is good for.
More tools
The best-benchmarked open-source AI memory system. And it's free.
Orca is the ADE for working with a fleet of parallel agents. Run any coding agent with your own subscription. Available on desktop, mobile and remote runtime.

A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io
Never stop coding. Free MIT AI gateway: one endpoint, 352 providers (150+ free), 1200+ models Kimi, Claude, GPT, Gemini, GLM, DeepSeek, MiniMax. Works with Claude Code, Codex, Cursor, OpenCode, Cline & Copilot. Quota-aware auto-fallback, RTK+Caveman compression saves 15-95% tokens, MCP/A2A, Desktop/PWA. Built by 550+ contributors
Compress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.