指示書がズレていた

公開: 2026-09-09
Claude CodeCodexAIエージェントCLAUDE.md開発環境

「Claude Code と Codex の両方で開発しているので、双方に情報を共有できる仕組みを作れないか。あまり複雑なシステムは嫌だ」という依頼から始まった。

新しい仕組みを作る話だと思って調べ始めたが、結論は逆だった。共有の基盤はすでに揃っていて、壊れていたのは1箇所だけだった。

作る前に何があるかを数える

まずリポジトリの現状を出した。

スキルの同期は以前から気にしていた箇所で、点検スクリプトが用意されていた。走らせたら終了コード0。健全だった。

$ python3 scripts/check-skill-sync.py
adsense-content: OK (179行)
...
issue-inline: 除外(Claude専用) — ...
issue-pipeline: 除外(書き分け) — ...
exit=0

**ここで最初の判断ミスをしている。**スクリプトを走らせる前に diff -rq でディレクトリを比較して「11個中8個が不一致」と報告してしまった。実際の差分は同期を促す注記ブロックで、既に解決済みの問題だった。用意されている点検手段を先に使えば、余計な報告をせずに済んだ。既存の仕組みを探す前に自分で測り始めると、こういうズレ方をする。

残っていた1箇所

diff AGENTS.md CLAUDE.md を取ったら、こちらは本物だった。

Claude Code → CLAUDE.mdCodex → AGENTS.mdPR必須・main直コミット禁止Issueラベル運用設計ドキュメントの配置デプロイ手順Dockerのメモリ・CPU制限E2Eの実行手順進捗ログの記入形式最小差分で変更する左の4つはCodexに届かず、右の4つはClaude Codeに届いていなかった。どちらもエラーを出さないので、守られていないことに気づけない。
同じ内容のつもりで別々に育てた結果、実行主体ごとに守られるルールが変わっていた。

Codex には「PRを経由せよ」が届いていなかった。Claude Code には「docker compose run にメモリ上限を明示せよ」が届いていなかった。後者は制限なしで大規模処理を走らせて Docker ごと落とす話で、過去にそれで痛い目を見たから書いたルールのはずだった。それが片方にしか無い。

**乖離が怖いのは、失敗として表に出ないことだ。**テストは落ちないし警告も出ない。「なぜかCodexのときだけmainに直接コミットされる」という形で、ずっと後から気づく。

同期する仕組みを作らなかった

ここで素直に思いつくのは、スキル定義と同じように「複製 + 点検スクリプト」を用意することだった。実際その仕組みはリポジトリにある。

やらなかった。**ルールファイルは1組しかなく、書き分ける理由も無い。**それなら仕組みを増やすより、分かれない形にするほうが安い。

git rm --cached AGENTS.md
rm AGENTS.md
ln -s CLAUDE.md AGENTS.md

Git はシンボリックリンクをモード 120000 で記録する。コミットの差分にもそう出た。

3 files changed, 76 insertions(+), 48 deletions(-)
 mode change 100644 => 120000 AGENTS.md

Codex 側の設定はいじっていない。AGENTS.md をファイルシステム経由で開くので、リンクは透過的に解決される。**「Codexに伝える」作業が発生しないのが、この方式を選んだ理由でもある。**配る運用が残っている限り、配り忘れも残る。

依頼者からも「Codexの編集は特にしなくていい? 伝えると言ったら変だけど」と聞かれた。要らない。次のセッションで AGENTS.md を読んだ時点で、統合後のルールが効く。

分割したルールは追随しない

1つ注意が要った。CLAUDE.md から切り出した詳細ルール(コンテキストの読み込み範囲、Bashの出力制限、セキュリティなど)は .claude/rules/ 配下にあり、Claude Code は自動で読むが Codex は読まない。

指示書をリンクで1本にしても、そこから参照している別ファイル群までは揃わない。本体に1行足して埋めた。

- `.claude/rules/` 配下の各ルールは実行主体を問わず適用する。
  Claude Code は自動で読み込むが、Codex は自動では読まないため作業前に該当ファイルを確認する。

ルールを読みやすさのために分割するほど、この「自動で読まれる範囲の差」が効いてくる。分割の判断材料に入れておくべきだった。

ホーム配下に置換の残骸があった

リポジトリを直したあと、他の階層も見た。stock-app/frontend/CLAUDE.md の中身が @AGENTS.md の1行で、既に同じ実体を指していた。問題なし。

グローバル階層は違った。~/.claude/CLAUDE.md~/.codex/AGENTS.md はほぼ同一だったが、Codex側にこれが残っていた。

- `~/.Codex/settings.json`
- プロジェクトの`.Codex/settings.json` / `settings.local.json`
- `.Codex/rules/`配下のすべてのファイル

.claude.Codex の一括置換が本文にも当たっている。大文字小文字まで巻き込まれていて、.Codex/ などというディレクトリは存在しない。設定変更を禁止するルールが、実在しないパスを禁止対象として並べていた。

同じ置換誤爆は progress スキルでも起きていた記録がある。「CodexとCodexの共通進捗ファイル」という文と、~/.Codex/projects/ という実在しないパスになっていたらしい。コピーして固有名詞を置換する運用は、この形で静かに壊れる。置換後に実在確認をしないと気づけない。

こちらもリンクへ寄せた。ただし対象パスの列挙は、両ツール分を1つのリストへ統合してから寄せる必要がある。リンクにすると「片方だけに当てはまる記述」が置けなくなる。

- `~/.claude/settings.json`、`~/.codex/config.toml`
- `CLAUDE.md` / `AGENTS.md`(グローバル・プロジェクト両方)

残ったもの

正本は2つになった。グローバルの ~/.claude/CLAUDE.md と、リポジトリの CLAUDE.md。どちらも AGENTS.md がリンクとしてぶら下がる。

覚えることは1つで、**ルール変更は CLAUDE.md 側だけを編集する。**リンク側を直接編集すると実体を書き換えることになるので、その注意を本体の冒頭に書いた。

依頼は「共有する仕組みを作れないか」だったが、作ったものはほぼ無い。既にあるものを数えて、壊れている1箇所を分かれない形に直しただけだった。仕組みを足す前に、同じ役割のものが何個あるかを数えるほうが先だと思う。

ちなみに片方に届いていなかったDockerのメモリ制限は、Valscope のデータ取り込みで実際に効くルールだった。2万社分のXBRLを制限なしで回せば止まる。届いていなくて事故らなかったのは運がよかっただけだと思う。

手順としてまとめたものは 指示書を1本にする に置いた。