# Generating your agent rules from one file does not stop them drifting

> Source: <https://dev.to/untactit/generating-your-agent-rules-from-one-file-does-not-stop-them-drifting-3gpb>
> Published: 2026-08-11 22:51:21+00:00

The obvious fix for "our agent instruction files keep diverging" is to stop maintaining copies. Write `AGENTS.md`

, generate `CLAUDE.md`

and `.cursor/rules/*.mdc`

and `.github/copilot-instructions.md`

from it, done.

I built that. It works. It also does not solve the problem, and the gap between those two statements is worth spelling out, because I only saw it after running the thing on a real machine.

```
python3 agent_fanout.py

create    CLAUDE.md
create    .cursor/rules/from-agents-md.mdc
create    .github/copilot-instructions.md
```

One source, several derived files, a header on each so nobody edits the derived copy by accident:

``` php
<!-- Generated from AGENTS.md by agent-fanout. Do not edit this file. -->
```

Add it to CI and the pull request that edits `CLAUDE.md`

directly turns the build red:

```
- run: python3 agent_fanout.py . --check
```

That covers **this repository, on the machines that run CI**. Which sounds like everything until you list what it isn't.

**Other repositories.** Your team has more than one. Each has its own `AGENTS.md`

, and they were copy-pasted from each other at some point. Generation keeps each repo internally consistent while the repos drift apart from one another.

**Global config.** Claude Code reads `~/.claude/CLAUDE.md`

in addition to the project file. Cursor has user-level rules. Those live outside any repository, are never in CI, and are exactly where people put the rule they didn't want to argue about in review.

**The window between edits.** Generation runs when someone runs it. Between that moment and the next CI run, a derived file can be edited and used. The agent reads it immediately; CI notices on push, if there is a push.

**Repos without CI.** Prototypes, scratch clones, the repo someone made last Tuesday. Those are where instructions get freely modified, and they are the ones with no gate at all.

**Machines, not repositories.** The unit that runs an agent is a laptop. A laptop has many checkouts, several of the same repo, and a home directory. Nothing that operates per-repository can see across that.

Prevention is a policy. Detection is a measurement. Policies get bypassed in ways that are invisible until you measure.

```
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
```

This one scans paths rather than repositories, and groups files by content similarity rather than by filename — two unrelated projects having different `CLAUDE.md`

files is not drift, and reporting it as drift makes the output worthless. (Getting that grouping right took three rewrites; [I wrote that part up separately](https://dev.to/untactit/i-found-18-versions-of-the-same-claudemd-on-one-laptop-bbc).)

Run it across your whole working directory, not one project. The interesting results are the ones that cross repository boundaries.

| Scope | Answers | |
|---|---|---|
`agent-fanout` |
one repository | "are the derived files current?" |
`agent-drift` |
whole machine, many paths | "where did copies diverge anyway?" |

Generation removes the *reason* copies exist. Detection catches the copies that exist for reasons you did not anticipate. Neither is redundant, and doing only the first one gives you a false sense of coverage — which is the actual failure mode I want to warn about, because it is the one I walked into.

Both are single-file Python, no dependencies, read-only where it matters, MIT:

`AGENTS.md`

once, generate the restThe honest end state is that neither script is necessary, because the assets are not files sitting on laptops at all — they live in one reviewed place and reach every machine without anyone copying anything. That is what I am building at [untactit](https://untactit.com), currently pre-launch.

The scripts stand on their own and don't depend on it. Use them, ignore the rest.
