AGENTS.md solved the format argument. Codex CLI, GitHub Copilot, Cursor, Windsurf, Amp and Devin all read the same file now. Claude Code still reads CLAUDE.md, Gemini CLI still reads GEMINI.md, and that exception list keeps getting shorter.
The format was never the expensive part.
I scanned one working laptop this morning. Nothing exotic — one developer, a few years of projects, the normal agent tooling:
| file | copies on disk | distinct contents |
|---|---|---|
AGENTS.md | 111 | 19 |
CLAUDE.md | 38 | 19 |
GEMINI.md | 2 | 2 |
SKILL.md (agent skills) | 3,073 | 887 |
Method: find ~ -maxdepth 7 -type f -name <X>, pruning node_modules, .venv*, site-packages and Library/Caches. "Distinct contents" is the count of unique md5 hashes. Vendor-installed skill bundles are included in the SKILL.md row, which is exactly the point — they are on the machine and an agent can read them.
111 files. 19 different things being said.
Nested files are a feature. A monorepo *should* scope instructions per package, and the spec says so. But 19 distinct contents across 111 copies is not scoping. That is copy, edit one copy, forget.
1. The hand copy. You write a rule you like. You paste it into the next repo. Six months later you fix a typo in one of them. Every other copy is now wrong and nothing tells you.
2. The machine boundary. Global config lives outside every repo: ~/.claude/CLAUDE.md, ~/.gemini/GEMINI.md, ~/.config/opencode/AGENTS.md. Two laptops, two versions, and the difference surfaces as "it behaves differently on my machine" three weeks later.
3. The generator. The common fix is to keep one source file and generate the rest — AGENTS.md → CLAUDE.md → .cursor/rules/*.mdc → .github/copilot-instructions.md. It works on the day you run it. It does not survive the next person who edits a generated file directly, because nothing on disk marks a file as generated, and nothing checks.
I wrote about that failure mode separately: Generating your agent rules from one file does not stop them drifting.
Worth having in one table, because the paths are the thing people get wrong:
| tool | file it reads |
|---|---|
| Claude Code | CLAUDE.md (project root, subdirectories, ~/.claude/), .claude/skills/*/SKILL.md, .claude/agents/*.md |
| Codex CLI | AGENTS.md (root + nested, nearest wins) |
| GitHub Copilot | .github/copilot-instructions.md, scoped .github/instructions/*.instructions.md |
| Cursor | .cursor/rules/*.mdc (legacy .cursorrules) |
| Windsurf | .windsurf/rules/*.md (legacy .windsurfrules) |
| Gemini CLI | GEMINI.md (~/.gemini/, workspace root, subdirectories) |
| opencode | AGENTS.md, falls back to CLAUDE.md, global at ~/.config/opencode/AGENTS.md |
agent-drift is a single-file Python script, MIT, no dependencies. It walks a tree, finds every instruction file the agents above read, groups them by content hash and prints the ones that disagree.
curl -O https://raw.githubusercontent.com/untactit/agent-drift/main/agent_drift.py
python3 agent_drift.py ~
Repo: https://github.com/untactit/agent-drift
It does not fix anything. It tells you how bad it is, which is the part most teams are missing — you cannot argue for a process change without a number.
I work on untactit. One place to hold the skills, rules and memory your agents run on, review a change once, and have it land in every target without anyone opening a file.
The distinction that matters: a person decides what gets approved. Nothing after that is touched by hand. Drift is not something we repair afterwards — it stops being produced, because nobody is editing copies any more.
It is pre-launch. The scanner above is useful without it, and that is deliberate. If you want the longer version of the argument, it is on the product page.
If you run the scan on your own machine, I would like to see the numbers. My guess is that the AGENTS.md row is worse than mine on any team of more than three people.
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.