CodexでPRを並列に作る前に、親Issueを制御面にしている話
この記事は、自分の個人開発で試している Codex + GitHub Issue 駆動開発の運用メモです。AIにIssueを渡すだけでは複数Issueの順序や依存関係が崩れやすくなったため、親Issueを制御面として使うようにした話を書きます。実体験と、まだ未検証の運用仮説を分けて残します。
前回の記事: AIに「いい感じに直して」と頼むのをやめて、GitHub Issueを作業の正本にした
Codexで小さなPRを複数作るようになると、最初に困ったのは「作業できるIssueが多いこと」ではなく、「どれを先に進めてよいか分からないこと」だった。
Issue単体にはGoalやScopeを書いている。それでも、複数Issueが絡むと、contract変更、docs整備、tester feedback、release gateが同じ一覧に並んで見える。
そこで最近は、親Issueをただのまとめではなく、AI作業の制御面として使っている。
この記事で扱うのは、親Issue、critical path、parallel laneの考え方です。CODEX_STATUSの詳しい表やCodexへの依頼文テンプレは続編で分けて書きます。
この記事で言いたいこと
A: IssueにGoalとScopeを書いていれば十分では?
B: 単発Issueならかなり効く。ただ、複数Issueが同時に動き始めると、それだけでは順序と依存が見えなくなった。
AIにIssueを渡すだけだと、単発作業は進む。
でも、開発が少し大きくなると、次の問題が出てきた。
- どのIssueが先に終わらないといけないのか分からない
- 並列に進めてよいIssueと、待つべきIssueが混ざる
- Codexが別々のPRを作ると、親Issue側の進捗が追いにくい
- contract変更やrelease gateのように、人間レビューが必要なものまで勢いで進みそうになる
そこで、今はGitHub Issueをただのタスクではなく、開発グラフとして扱っている。
自分の運用では、親Issueに次を置く。
- critical path
- parallel lane
- blocked / deferred / done の状態
- 担当agentやPR
- merge前に必要なgate
- 次の並列wave
Issue駆動開発というより、Issueを制御面にしたCodex並列開発に近い。
この記事の対象読者
- Codex / Claude Code / GitHub Copilot coding agent などでPRを作っている人
- GitHub Issueを使っているが、複数Issueが絡むと優先順位が崩れる人
- 小さなPRを並列に進めたいが、どこで止めるべきか迷う人
- 親Issueやlabelを、AI開発の判断材料として使いたい人
この記事で持ち帰れるもの
- 親Issueを「作業一覧」ではなく「制御面」として使う考え方
- critical path / parallel lane / blocked を分ける最小パターン
- Codexに進めさせるIssueと、人間レビューに戻すIssueの分け方
この記事の前提
| 種類 | 内容 |
|---|---|
| 実体験 | private repo で GitHub Issue を作業単位にし、Codexで複数PRを進めている |
| 発展点 | Issue単体ではなく、親Issueにcritical pathと並列レーンを持たせている |
| 実測ではないこと | 生産性が何倍になった、レビュー時間が何%減った、という定量効果はまだ測っていない |
| 未検証 | 他チーム・複数人開発・大規模OSSで同じ運用が効くか |
なぜIssue単体では足りなかったか
A: Issueを細かくすれば、並列に進めやすくなるのでは?
B: 細かくするだけだと、全部が同じ重さに見える。問題は粒度だけでなく、どれが後続を止めているかだった。
前の段階では、AIに「いい感じに直して」と頼むのをやめて、GitHub Issueを作業の正本にすることを重視していた。
Issueには最低限これを書く。
Goal Scope Done Out of scope
これは今でも有効です。
単発Issueなら、この形だけでもかなり進めやすいです。
ただ、VS Code拡張、Desktop、Obsidian Plugin、parser contract、release gateのように複数レーンが絡み始めると、Issue単体では足りなくなってきた。
複数Issueを並べると、全部が同じ重さに見えます。
でも実際には違います。
たとえば、次のようなIssueが同じ一覧に並ぶ。
- stable node id contract
- Obsidian Plugin PoC
- host adapter設計
- i18n foundation
- tester feedback
- release gate
- export品質
- map-aware diff
このとき、AIに「open issueを進めて」と渡すだけでは危ない。
先にcontractを決めないと進めてはいけないIssueもあれば、並列に進めてよいdocs/design issueもある。
小さな実例: 親Issueでphaseを制御する
抽象論だけだと分かりにくいので、private repoで実際に使っているIssueを、公開できる粒度まで匿名化するとこうなります。
| 種類 | 実例 | 何をしたか | 扱い |
|---|---|---|---|
| critical path | tester feedback後のUI gate | toolbar表示、選択位置のreveal、zoom操作のような、次のtester確認を直接ブロックするUX不具合を直した | 後続確認の前に先に閉じた |
| parallel-safe | release evidence / runbook整備 | tester配布手順、human review用decision packet、completion evidence matrixをdocsとして整理した | product code本流と衝突しにくいので並列に進めた |
| deep + review | grammar / parser contract整理 | parserとvalidationで使う分類を単一ソース化した | parallel-safeに見えてもcontractに近いため、review境界を強く意識した |
| blocked / deferred | stable node id contract | Markdown内にnode idをどう保存するかを検討した | parser / serializer / patch / validationにまたがるため、実装前にhuman review待ちにした |
この表で伝えたいのは、
critical-pathが付いたIssueだけが重要なわけではない、という点です。
release evidenceやrunbookのようなdocs/evidence系は、product codeを直接変えないので並列に進めやすい。Codexに任せるには相性が良い。
一方で、stable node id contract のような作業は、表面上は「ID保存形式を決めるだけ」に見えるが、実際には parser、serializer、validation、patch、webview protocol に影響する。こういうIssueは、勢いで実装に入るより、まずcontract boundaryを切り出してreview待ちにした方が安全だった。
また、tester feedback後のUX修正は、ユーザーが次に触る体験を直接ブロックするため、critical pathとして扱った。全部を並列にするのではなく、先に閉じるべきものを親Issue側で明示する。
自分の運用では、このようにIssueを次の3種類に分けている。
今すぐ閉じるべきcritical path 並列に進められるdocs / evidence / polish reviewなしで進めすぎてはいけないcontract変更
親Issueを制御面にする
A: 親Issueは進捗メモとして使えばよいのでは?
B: 最初はそれで十分だった。ただ、Codexに作業を渡すなら「次に何をしてよいか」を読める形にした方が安定した。
自分のprivate repoでは、親Issueに phase 全体の状態を書いています。
たとえば、親Issueにはこういう情報を置きます。
P7-01 -> P7-06
これは「P7-01からP7-06へ進める」というcritical pathを表しています。
さらに、並列レーンも持たせます。
Import/Export: P7-01, P7-03 Integrations: P7-02 Map Semantics: P7-04 Templates: P7-05 Gate: P7-06
この形にすると、Codexに渡すときも「どのIssueをやるか」だけでなく、「どのIssueは並列でよいか」「どれはgateか」を判断しやすくなる。
図にすると、流れはだいたいこうなります。
重要なのは、子Issueを全部同じ扱いにしない点です。
親Issueは「作業一覧」ではなく、どの子Issueを先に進めるか、どれを並列にしてよいか、どこで人間判断に戻すかを示す制御面として使います。
この分け方で良くなったこと
1. AIに渡す文脈が短くなる
親Issueに状態がまとまっているので、毎回長い説明をしなくてよい。
2. 並列化してよいものが見える
docs、evidence、軽微なpolishのように本流のcontractに触らないものを見つけやすい。
3. 止めるべき場所が見える
blockedやneeds-human-reviewがあると、AIが進めすぎるのを防ぎやすい。
4. PRが小さくなりやすい
Issue単位でScopeが決まるので、PRの範囲も小さくしやすい。
失敗しやすいところ
critical pathを増やしすぎる
全部をcritical pathにすると、何も並列化できなくなる。
critical pathは「重要なIssue」ではなく、「滑ると後続Issueやrelease gateが止まるIssue」として扱う。
親Issueが古くなる
親Issueは便利ですが、更新されなければ逆に危険になります。
PR本文に「親Issueの更新案」を書かせるようにしておくと、review時に反映漏れを見つけやすい。
labelだけで判断する
labelは入口であって、判断そのものではない。
Issue本文、親Issue、関連PRを読む必要がある。
まとめ
AI開発でIssueを使うだけなら、単発作業は進めやすくなる。
でも、複数Issueが絡む開発では、Issueを作業単位としてだけでなく、依存関係と並列化の制御面として扱う必要が出てきた。
今の自分の運用では、親Issueにcritical pathとparallel laneを置き、Codexにはその状態を読ませてから作業させている。
これはまだ完成された方法論ではない。
ただ、AIに「Issueを渡す」段階から、「Issue graphを読ませて並列開発する」段階へ進んできた感覚がある。
まず小さく試すなら、親Issueに次の3行だけ置くところからでよいと思う。
critical path: 先に閉じないと後続が止まるIssue parallel lane: docs/evidenceなど、並列に進めやすいIssue blocked: contractや保存形式が未確定で止めるIssue
続編
この記事では、親Issueを制御面にする考え方を書きました。
続編では、親Issueに置く状態表
CODEX_STATUSと、Codexに渡す依頼文テンプレを書きます。
未検証
- この運用でPR lead timeがどれだけ短くなるか
- review負荷が下がるか
- 複数人チームでも成立するか
- GitHub sub-issuesやProjectsとの使い分け