팀에서 Claude Code 와 Cursor 와 Copilot 을 함께 쓴다. 각각은 움직이기 전에 파일을 하나씩 읽는다 — CLAUDE.md, .cursor/rules/*.mdc, .github/copilot-instructions.md. 그 파일들은 복사된다. 다른 리포지토리로, 다른 노트북으로, 누군가의 임시 디렉터리로.
그리고 누군가 사본 하나를 수정한다.
에러는 나지 않는다. 경고도, diff 도, 실패하는 테스트도 없다. 그 기기의 에이전트만 다르게 움직인다. 여섯 주 전에 누가 지운 규칙, 팀의 절반만 아는 컨벤션 같은 것이다. 증상은 「내 기기에서는 된다」로 나타나고, 이분 탐색할 대상이 없다.
그 파일들을 찾아 어느 사본이 어긋나는지 알려주는 스크립트를 썼다.
curl -O https://raw.githubusercontent.com/untactit/agent-drift/main/agent_drift.py
python3 agent_drift.py ~/work
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
~/work/api/CLAUDE.md
~/work/web/CLAUDE.md
2dc3c616c279 2 files, 411 lines
~/work/infra/CLAUDE.md
파일 하나, 표준 라이브러리만, Python 3.8+. 읽기만 한다 — 스캔 대상 파일에 쓰지 않는다. MIT.
처음 만든 버전은 10분이 걸렸고 쓸모가 없었다. 세 번의 수정이 이 글의 전부다.
첫 버전은 이랬다. CLAUDE.md 를 전부 모으고, 해시를 내고, 다른 것을 보고한다.
내 기기에서 돌렸다. 결과는 파일 21개가 문서 하나이고 버전이 18개 였다.
당연한 결과다. 무관한 프로젝트는 무관한 지시문을 갖는다. 애초에 일치할 이유가 없다. 그것을 드리프트로 보고하는 도구는 노이즈고, 노이즈를 내는 도구는 없는 것보다 나쁘다 — 세 번째 실행쯤이면 출력을 안 읽게 된다.
두 파일이 같은 문서인지는 내용 이 정하지, 파일명이 정하지 않는다.
그래서 공백을 정규화하고, 토큰화하고, 자카드 유사도로 비교했다. 임계값 0.7.
여전히 거대한 클러스터 하나였다. 이유를 알기 위해 실제 쌍의 값을 재 봤다.
012Hki23QBMr ↔ 016ct6suZ14M : 0.000
012Hki23QBMr ↔ 016avoYh97Eu : 0.764
같은 도구용으로 쓰인 지시문 파일은 어휘를 거의 공유한다. claude, skill, agent, file, commit, never, always. 공통점이 없는 두 문서도 단어 집합으로는 크게 겹친다.
5단어 shingle 로 바꿨다. 연속하는 5단어 구문 전체를 집합으로 잡는 방식이다. 어휘는 충돌해도 어구는 잘 충돌하지 않는다. 다시 재니 무관한 쌍은 0.000 으로 떨어졌고, 실제로 갈라져 나온 문서는 0.53–0.76 에 놓였다. 필요한 것은 이 분리고, 추론이 아니라 측정에서 나왔다.
그래도 클러스터는 하나였다. 이건 고전적인 실수다.
union-find 에 「구성원 중 아무하고나 비슷하면」이라는 조건을 쓰면 A 가 B 에 붙고 B 가 C 에 붙어서, 공통점이 없는 A 와 C 가 같은 클러스터에 들어간다. 약한 연결 하나면 트리 전체가 한 덩어리가 된다.
지금은 각 클러스터가 대표 문서 를 유지한다. 가장 큰 구성원이 대표이고, 파일은 그 대표와 직접 비슷할 때만 합류한다. 스캔 순서와 무관하게 클러스터가 일관되게 유지된다.
내 기기에서의 최종 결과는 파일 15개, 그중 9개가 대표와 0.53–0.65 로 유사했다. 이쪽은 실제로 하나의 템플릿에서 갈라져 나온 것들이다. 탐지가 맞았고, 숫자도 조치할 수 있는 크기다.
- run: python3 agent_drift.py . --fail-on-drift
드리프트가 있으면 exit 1 이다. 팀 지시문의 사본 둘이 어긋난 그날 빌드가 실패한다. 여섯 달 뒤에 「에이전트가 왜 그 규칙을 안 지키냐」는 질문을 받고 알게 되는 대신이다.
후처리하고 싶다면 --json 이 전체 리포트를 준다.
Claude Code, Codex/AGENTS.md, Cursor, GitHub Copilot, Gemini, Windsurf, Cline, Aider, Continue, Zed. 패턴은 파일 상단의 상수 하나에 모여 있다. 빠진 도구가 있으면 PR 이나 이슈를 남기면 된다.
탐지는 절반이고, 그중 덜 어려운 쪽이다. 사본은 이유가 있어서 존재하며, 그 이유가 사라지기 전까지 드리프트는 다시 생긴다. 이유를 없애는 것은 검토를 마친 원본 하나가 아무도 붙여넣지 않은 채 모든 기기에 닿는 구조다.
untactit 은 그 문제를 대상으로 만들고 있고, 공개 전(pre-launch)이다. 파편화는 각자가 손대서 생긴다. untactit 은 손댈 필요를 없앤다. 이 스크립트는 제품에 의존하지 않으며 앞으로도 그렇다.