You write CLAUDE.md once. Six months later there are eighteen of them on your laptop and you cannot say which one is right.
This is not a hypothetical. I scanned my own machine and found exactly that. What follows is why it happens, and why the obvious fix does not fix it.
Every agent reads instructions from a path it owns.
| Tool | Path |
|---|---|
| Claude Code | CLAUDE.md, ~/.claude/CLAUDE.md |
| Cursor | .cursor/rules/*.mdc |
| GitHub Copilot | .github/copilot-instructions.md |
| Codex / others | AGENTS.md |
You did not decide to keep four copies. You decided to use four tools. The copies came with them.
Three mechanics produce it, none of which involve anyone being sloppy.
Editing at the point of use. An agent misbehaves mid-task. You fix the instruction file that is open in front of you. That file is one of four, and the fix lands in one.
The checkout is not the unit. You have the same repo cloned twice — one for the main branch, one for a long-lived branch. Both have instruction files. They diverge the moment either is touched.
Home directory rules are invisible. ~/.claude/CLAUDE.md belongs to no repository. It is in no CI. It is where the rules you did not want to argue about in review end up.
The natural response is to stop keeping copies: write AGENTS.md once and generate the rest.
I built that. It works. It is agent-fanout — single-file Python, zero dependencies, MIT.
python3 agent_fanout.py
create CLAUDE.md
create .cursor/rules/from-agents-md.mdc
create .github/copilot-instructions.md
Generated files carry a header so nobody edits them directly, and --check in CI turns a hand-edited derivative into a red build.
That covers this repository, where CI runs. Which sounds like everything until you list what falls outside:
Prevention is policy. Detection is measurement. Policy gets bypassed in ways you cannot see unless you measure.
agent-drift scans paths rather than repos, and groups by content similarity rather than filename:
python3 agent_drift.py ~/work ~/side-projects
Scanned 47 instruction files.
DRIFT: 2 documents, 5 distinct versions between them.
claude-code:CLAUDE.md
6 copies, 3 versions
9b01aeaa204d 3 files, 406 lines
2dc3c616c279 2 files, 411 lines
Filename matching is useless here. Unrelated projects having different CLAUDE.md files is correct, and a tool that reports that as drift stops being used. Point it at your whole working directory, not one project — the interesting results cross repository boundaries.
| Scope | Question it answers | |
|---|---|---|
| agent-fanout | one repository | are the derived files current |
| agent-drift | whole machine, many paths | where did copies diverge |
Generation removes the reason copies exist. Detection catches the copies that exist for reasons you did not anticipate. Doing only one leaves you feeling covered, which is worse than knowing you are not. I walked into that myself.
Honestly, the end state is that neither script is needed — assets do not sit scattered as files on a machine, and one reviewed copy reaches every machine. That is what I am building at untactit, currently pre-launch.
The scripts do not depend on it. Take whichever part is useful.
A version of this post also appears on DEV.
Connect one workspace and see every skill, rule, and memory your team has in play — in about ten minutes.
No credit card. Works with what you already run.