Codex CLIを1つだけ使っているあいだは、特に困りませんでした。
ところが、プロジェクトのコード量が多くなると、Codexの処理を待つ時間もけ増えてきました。
そこで、別のターミナルを立ち上げ並列でCodexを走らせ始めたのですが、今度は同じファイルに同時に書き込むのが心配です。
AgentチームのようなOrchestrator/Worker構成も頭にありましたが1、まずは仕組みを増やさずにどこまでやれるか試してみることにしました。
1. やったこと
リポジトリのルートに working/ ディレクトリを置きました。
各CodexはタスクをはじめるときにそこにMarkdownファイルを1枚作り、終わったら消します。
それだけです。
ファイルの中身はこんな感じです。
owner: codex-A
pid: 12345
branch: fix/monster-visual-mapping-by-id
status: active
started_at: 2026-02-23 14:10
updated_at: 2026-02-23 14:28
scope: src/scenes/ExploreScene.ts, src/mod/*
purpose: monster visual mapping by enemyIdCode language: HTTP (http)
scope に今触っているファイル範囲を書いておけば、別のCodexが作業前に確認できます2。
重なっていたら担当を分けるか、片方を待たせるか、その場で調整します。
関連ドキュメントはリポジトリの docs/AGENTS.md と working/README.md に置いてあります3。
2. なぜこの形にしたか
最初は1枚の working.md で作業状況をエージェント間で共有しようと考えました。
でも複数のCodexが同じファイルを同時に更新しようとすると、それ自体が衝突の原因になります。
ロック機構や専用スクリプトを先に作るという選択肢もありました。
ただし、取りっぱなし(ロックを解放し忘れる状態。staleとも呼ぶ)の問題は必ず出ます4。
厳密に作れば作るほど、stale対応のコードが膨らみます。
そこで、「目印として機能すれば十分」と割り切って、1時間以上更新がないファイルはstale扱いにして無視してよいというルールを最初から決めました。
3. 実際に使ってみて
衝突がゼロになったわけではありません。
これはmutexではなく、お互いの動きが見えるメモ帳に過ぎません5。
それでも「誰がどこを触っているか」が一目でわかるようになっただけで、タスクの割り当てがしやすくなりました。
4. 今後やるかもしれないこと
今は手動でファイルを作って消していますが、acquire/release をスクリプト化する余地はあります。
イベントログとして events.ndjson にappend-onlyで追記する形にすれば6、誰がいつどこを触ったかの履歴も残ります。
あとは、git worktree と組み合わせると、ブランチレベルでも物理的に競合しにくくなります7。
5. まとめ代わりに
小規模な並列Codex運用では、「厳密な排他制御を先に作る」ではなく、「見える化から始める」のが合っているのかな、と思って試してみました。
試行錯誤中ですが、まず薄い層から始めて、詰まったところで厚くしたらよいかな、と思います。
- Codex CLIにはMulti-agentsの実験的機能があり、専門化したサブエージェントを並列で起動してひとつの応答にまとめることができます。2026年2月時点では実験的機能として明示的な有効化が必要です。 – Multi-agents | OpenAI Codex
- Codex CLIはリポジトリに置かれたAGENTS.mdを作業前に自動で読み込みます。working/ディレクトリの確認ルールもここに書いておくと、Codexが毎回自分で参照するようになります。 – Custom instructions with AGENTS.md | OpenAI Codex
- AGENTS.mdはOpenAI Codexが作業前に自動で読み込む規約ファイルです。リポジトリルートに置くとプロジェクト全体の規約として機能し、サブディレクトリに置くと対象範囲を絞った指示を与えられます。 – AGENTS.md | agents.md
- Kubernetesはノードのハートビート管理にLease(リース)という仕組みを使っており、一定時間更新がなければ失効したとみなす設計になっています。staleロックへの対処としてハートビートを組み込む考え方は、この設計から参照しました。 – Leases | Kubernetes
- このような「強制排他ではなく意思表示としてのロック」をadvisory lockと呼びます。Linuxのflock(2)システムコールが代表例で、OS側は強制せず、プロセス間の合意として機能します。 – GitLab Docs: File Locking
- NDJSONはNewline Delimited JSONの略で、1行につき1つのJSONオブジェクトを書く形式です。ファイルの末尾に追記するだけでログが積み重なり、tail -fで監視しやすいです。 – ndjson/ndjson-spec: Specification | GitHub
- git worktreeはGitの公式機能で、1つのリポジトリから複数の作業ディレクトリを持てます。各worktreeが別ブランチをチェックアウトした状態で共存でき、git stashやブランチ切り替えなしに並行作業できます。 – git-worktree Documentation | Git