{"slug": "i-found-18-versions-of-the-same-claude-md-on-one-laptop", "title": "I found 18 versions of the same CLAUDE.md on one laptop", "summary": "A developer has released agent_drift, an open-source Python script that detects when copies of AI agent instruction files such as CLAUDE.md, .cursor/rules/*.mdc, and .github/copilot-instructions.md have drifted out of sync across a codebase. The tool uses 5-word shingles and a representative-based clustering algorithm to identify genuine forks of the same document, and it can be integrated into CI to fail builds when drift is detected. The developer is also building a related product called untactit, but the script is independent.", "body_md": "Your team runs Claude Code, Cursor, and Copilot. Each of them reads a file before it acts — `CLAUDE.md`\n\n, `.cursor/rules/*.mdc`\n\n, `.github/copilot-instructions.md`\n\n. Those files get copied: into another repo, onto another laptop, into someone's scratch directory.\n\nThen somebody edits a copy.\n\nNothing errors. No warning, no diff, no failing test. The agent on that machine just behaves differently — a rule someone removed six weeks ago, a convention only half the team's agents know about. It shows up as \"works on my machine\" with nothing to bisect.\n\nI wrote a script to find those files and tell you which copies disagree.\n\n```\ncurl -O https://raw.githubusercontent.com/untactit/agent-drift/main/agent_drift.py\npython3 agent_drift.py ~/work\nScanned 47 instruction files.\n\nDRIFT: 2 documents, 5 distinct versions between them.\n\n  claude-code:CLAUDE.md\n    6 copies, 3 versions\n      9b01aeaa204d  3 files, 406 lines\n        ~/work/api/CLAUDE.md\n        ~/work/web/CLAUDE.md\n      2dc3c616c279  2 files, 411 lines\n        ~/work/infra/CLAUDE.md\n```\n\nOne file, standard library only, Python 3.8+. Reads only — it never writes to the files it scans. MIT.\n\nThe naive version took me ten minutes and was useless. The three fixes are the whole story.\n\nFirst version: collect every `CLAUDE.md`\n\n, hash them, report the ones that differ.\n\nRan it on my own machine. It reported **21 files as one document with 18 versions**.\n\nOf course it did. Unrelated projects have unrelated instructions. They were never supposed to match. A tool that reports that as drift is noise, and a noisy tool is worse than no tool — you stop reading it by the third run.\n\nFiles are the same document when their **content** says so, not when their filename does.\n\nSo: normalise whitespace, tokenise, compare with Jaccard similarity, threshold 0.7.\n\nStill one giant cluster. I measured actual pairs to find out why:\n\n```\n012Hki23QBMr ↔ 016ct6suZ14M : 0.000\n012Hki23QBMr ↔ 016avoYh97Eu : 0.764\n```\n\nInstruction files written for the same tool share almost all of their vocabulary. `claude`\n\n, `skill`\n\n, `agent`\n\n, `file`\n\n, `commit`\n\n, `never`\n\n, `always`\n\n. Two documents with nothing in common still overlap heavily as word sets.\n\nSwitched to **5-word shingles** — the set of every consecutive 5-word phrase. Vocabulary can collide; phrasing rarely does. Re-measured: unrelated pairs dropped to 0.000, genuinely forked documents landed at 0.53–0.76. That separation is what you want, and it came from measuring, not from reasoning about it.\n\nStill one cluster. This one is a classic.\n\nUnion-find with \"similar to any member\" means A joins B, B joins C, and now A and C are in the same cluster despite sharing nothing. One weak link and the cluster swallows the tree.\n\nEach cluster now keeps a **representative** — its largest member — and a file joins only if it resembles that representative directly. Clusters stay coherent regardless of scan order.\n\nFinal result on my machine: 15 files, 9 of them 0.53–0.65 similar to the representative. Those really are forks of one template. Correct detection, and the number is small enough to act on.\n\n```\n- run: python3 agent_drift.py . --fail-on-drift\n```\n\nExit 1 when drift exists. The build goes red the day two copies of your team's instructions stop matching, instead of you finding out in six months when someone asks why the agent stopped following a rule.\n\n`--json`\n\ngives you the full report if you'd rather post-process it.\n\nClaude Code, Codex/`AGENTS.md`\n\n, Cursor, GitHub Copilot, Gemini, Windsurf, Cline, Aider, Continue, Zed. The patterns are one constant at the top of the file — PR or issue if yours is missing.\n\nDetection is the easy half. The copies exist for a reason, and until that reason is gone the drift comes back. What removes it is one reviewed source that reaches every machine without anyone pasting anything.\n\nThat's the problem I'm building [untactit](https://untactit.com) around — it's pre-launch. This script doesn't depend on it and never will.", "url": "https://wpnews.pro/news/i-found-18-versions-of-the-same-claude-md-on-one-laptop", "canonical_source": "https://dev.to/untactit/i-found-18-versions-of-the-same-claudemd-on-one-laptop-bbc", "published_at": "2026-08-11 22:29:37+00:00", "updated_at": "2026-08-11 23:16:46.115538+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "mlops"], "entities": ["Claude Code", "Cursor", "GitHub Copilot", "agent_drift", "untactit"], "alternates": {"html": "https://wpnews.pro/news/i-found-18-versions-of-the-same-claude-md-on-one-laptop", "markdown": "https://wpnews.pro/news/i-found-18-versions-of-the-same-claude-md-on-one-laptop.md", "text": "https://wpnews.pro/news/i-found-18-versions-of-the-same-claude-md-on-one-laptop.txt", "jsonld": "https://wpnews.pro/news/i-found-18-versions-of-the-same-claude-md-on-one-laptop.jsonld"}}