# Claude Code × Codex 併用スターターキット

同一リポジトリを2体のAIコーディングエージェントに触らせるための最小構成です。
AIディア（https://aidia.pengi-n.co.jp）が2026-08-16から実運用しているものを、
顧客名・実案件・認証情報を除いて配布用に整理しました。

そのままコピーして使えます。ライセンスは自由（帰属表示も不要）。

---

## 0. 使う順番

**この順番を変えないでください。1番を飛ばすと、2番と3番をやっても壊れます。**

1. 書いてよいディレクトリを分ける（§1）
2. 実行時間をずらす（§2）
3. 共有する処理だけロックを取る（§3）
4. 落ちた回をログに残す（§4）

---

## 1. territory 規約（まずこれを決める）

`AGENTS.md` なり `CLAUDE.md` なりに書くだけでなく、**片方の権限を実際に外してください。**
書いてあるだけの規約は守られません。

```markdown
## territory（相手の領域を書き換えない）

- エージェントA（公開担当）: content/ templates/ assets/ cron/
- エージェントB（生成担当）: automation/ content_queue/<B>/review_required/
                              automation/workspace/runs/<run_id>/

## 権限

- エージェントB には公開・デプロイ・外部送信の権限を与えない
- B は検証に通った成果物を review_required/ へ置くところまで
- 採否は A が一次ソースを再確認したうえで決める

## 共有

- 共有するのは公開処理とレビューキュー移送だけ
- 生成処理はロックを取らない（取ると遅いほうが速いほうを止める）
```

**なぜ領域から始めるのか**: 領域を分けた時点で、生成処理は互いのファイルを見に行かなくなります。
AIディアでは17日間の運用で、生成処理の衝突は0回でした。
衝突したのは公開処理という共有工程だけで、1回です。

---

## 2. 実行時間の決め方

**測ってから決めてください。** 目安ではなく実測です。

```
占有率 = （A の所要時間の中央値 + B の所要時間の中央値） ÷ ジョブ間隔
```

AIディアの実測（2026-08-16〜09-01・27ラン）:

| | 所要中央値 | 所要最長 |
|---|---:|---:|
| A（公開担当・毎朝07:03） | 32.3分 | 59.2分 |
| B（生成担当・毎日12:03） | 11.3分 | 57.3分 |

合計43.6分 ÷ 間隔5時間 = **占有率 約15%**。この水準ならロックはほぼ発動しません。
**占有率が50%を超えるなら、ロックの発動が常態化します。** その場合はロックを直すのではなく、
ジョブ間隔かジョブ内容を見直してください。

---

## 3. 排他ロック（Windows / msvcrt 版）

要点は `LK_NBLCK` です。**ブロッキングしないロックを使い、取れなければ即座に諦めます。**

```python
import os
from contextlib import contextmanager
from pathlib import Path
from typing import Iterator

AUTOMATION = Path(__file__).resolve().parent


@contextmanager
def named_lock(name: str) -> Iterator[None]:
    """取れなければ即座に例外。待たない。"""
    import msvcrt

    lock_path = AUTOMATION / "locks" / name
    lock_path.parent.mkdir(parents=True, exist_ok=True)
    handle = lock_path.open("a+b")
    try:
        handle.seek(0, os.SEEK_END)
        if handle.tell() == 0:
            handle.write(b"0")
            handle.flush()
        handle.seek(0)
        try:
            msvcrt.locking(handle.fileno(), msvcrt.LK_NBLCK, 1)
        except OSError as exc:
            raise RuntimeError("別の編集ジョブが実行中です") from exc
        yield
    finally:
        try:
            handle.seek(0)
            msvcrt.locking(handle.fileno(), msvcrt.LK_UNLCK, 1)
        except OSError:
            pass
        handle.close()


@contextmanager
def editorial_lock() -> Iterator[None]:
    with named_lock("editorial.lock"):
        yield
```

### Linux / macOS 版

`msvcrt` は Windows 専用です。差し替えてください。

```python
import fcntl

# 上記 named_lock の msvcrt 部分だけを置き換える
try:
    fcntl.flock(handle.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
except OSError as exc:
    raise RuntimeError("別の編集ジョブが実行中です") from exc
# 解放は fcntl.flock(handle.fileno(), fcntl.LOCK_UN)
```

---

## 4. 呼び出し側（終了コード75で落とす）

```python
import sys

EXIT_LOCKED = 75  # 別ジョブ実行中。異常ではない


def main() -> int:
    try:
        with editorial_lock():
            print("[lock] 取得")
            return run_publish()
    except RuntimeError:
        print("[skip] 別ジョブが実行中のため今回はスキップします")
        return EXIT_LOCKED


if __name__ == "__main__":
    raise SystemExit(main())
```

**なぜ待たずに落とすのか**: 待つ設計にすると、公開処理が長引いた日に2体が同時に生き残ります。
生成の途中で相手の成果物が入れ替わる可能性が出ます。
1日1回の定期実行なら、1回落としても翌日に戻ります。
**取りこぼし1回より、壊れた成果物を公開するほうが高くつきます。**

終了コード75を「失敗」ではなく「スキップ」として集計してください。
混ぜると、あとから「ロックの取り合いが何回起きたか」が数えられなくなります。

---

## 5. 実行ログに最低限残すもの

これだけ残しておけば、あとから運用の実態を数字で振り返れます。
AIディアの実測記事は、このログだけで書けています。

```json
{
  "schema_version": 1,
  "agent": "codex",
  "run_id": "codex-20260831-120307",
  "started_at": "2026-08-31T12:03:17+09:00",
  "finished_at": "2026-08-31T12:14:25+09:00",
  "status": "succeeded",
  "exit_code": 0,
  "promoted_to_review": [{"path": "...", "id": "...", "title": "..."}],
  "rejected": [{"target_kw": "...", "reason": "..."}]
}
```

集計してわかること:
- **完走率** … 落ちて困る工程をどちらに寄せるかの根拠
- **所要時間の中央値** … 実行時間をずらす幅の根拠
- **採用率** … 生成側の速さが意味を持っているかの検算
- **終了コード75の回数** … ジョブ時間の設計が妥当かの検算

---

## 6. 併用しないほうがよい場合

次の3つが揃っているなら、併用しても下書きが増えるだけで終わります。

- 1人・1リポジトリで、手元だけで使っている
- 定期実行にしていない
- 生成物をレビューする人がいない

AIディアでも生成側の採用率は57%（8本採用／6本却下）でした。
**レビューする側の工数を先に確保してから併用してください。**

---

作成: 株式会社PENGIN / AIディア編集部
出典: https://aidia.pengi-n.co.jp/articles/claude-code-vs-codex/
実測期間: 2026-08-16 〜 2026-09-01（27ラン）
