GitHub Issue を人間ゲート付きで自動処理する「iloop」
一定間隔で同じプロンプトを実行し続けるClaude Codeの/loop でGitHub Issue を1件ずつ拾って、設計 → 実装 → 検証 → PR まで回すスラッシュコマンド群Issue Loop(iloop)を作りました。
iOSアプリを制作しているとUIのブラッシュアップやロジックの修正など、多くの細かい課題が積み上がってきます。それをTODOリストにしながら進めていたんですが、やるべき事を人間がIssueとして列挙して、そのIssueリストをAIが自発的に消化していく仕組みにしてみようと思い立ちました。TODOと実装と進捗管理を一箇所に集約。
Issueを品質よく解決していく自動ループ。そのためには /loopの中に品質検証しながら実装していく、もう一つのループが必要になってきたわけです。
/loop 5m /iloop(時間ループ)
└─ 5分ごとに起動 → Issue を1件拾う
└─ 設計役 → 実装役 → 検証役 を指定ラウンド回す(品質ループ)
└─ 通れば PR、通らなければ blocked にして人間を呼ぶ
外側が「時間のループ」、内側が「品質のループ」。二重ループになっているのが特徴です。
ここではボクの開発環境を題材に、何のために作ったか・どういう仕組みか・GitHub とどう絡むのかなどを説明していきます。
全体像
人間・Claude Code・GitHub・Xcode の4者で、情報が下図のように流れます。
- 人間が触るのは ①⑦⑧ だけ。②〜⑥ は AI が回す
- 進捗(誰の番か)は GitHub のラベルが持つ。Claude Code 側は状態を持たない
- ⑥のPRで必ず人間に返る。ここが人間ゲート
Xcode が2箇所に出てくるのは受け入れ基準を「機械的な判定」と「人間にしかできない確認」に分けているためで、人間が検証してダメだと判断したらそのまま Issue に再持ち込みします。
| 誰が使うか | 何を見るか | |
|---|---|---|
xcodebuild(CLI) |
Claude Code | ビルドが通るか、テストが緑か、警告が増えていないか(機械的判断) |
Xcode.app(GUI) |
人間 | 見た目、アニメーション、実機での体感(主観的判断) |
IssueとプルリクエストPRで駆動する
方針決定や品質基準など人間が関与しなければいけない部分をIssueで説明して、それを見たAIが設計→実装→検証までを行い、品質基準に満たなければやり直しを行い、結果を人間へPRでフィードバックすることでキャッチボールが成立します。人間ゲートをなるべく少なくできるように工夫しています。
人間が触るのは「入口」と「出口」だけ。AI が勝手に中を回します。
| 誰の仕事か | 内容 |
|---|---|
| 人間 | 何をやるか決める(Issue を書く)/ 出来上がりを見て判断する(PR をレビューする) |
| AI | 設計→実装→検証まで。品質基準に満たなければ自己判断でやり直し |
状態は GitHub のラベルだけが持つ
iloop はローカルに状態ファイルを作りません。進捗はすべてGitHub Issue のラベルで表現します。
agent:queued → agent:working → agent:review (PR ができて人間の番)
↘ agent:blocked (AI が詰まって人間の番)
これには次の効用があります。
- どのマシンからでも、Claude アプリからでも状況が分かる
- セッションが落ちても状態が失われない
- 複数のセッションが同時に走っても、
agent:workingを見れば同時着手を防げる
Claudeで実働セッションと管理セッションを2つ立てて運用するときの状況判断がラベルでできるので、iloop は最初にラベルを確認してagent:working が1件でもあれば何もせず終了します。
セッションA(管理) 人間とAIが相談 → /iloop-issue でIssueを起票する
セッションB(実働) /loop 5m /iloop ← ひたすら Issue を処理する
内側のループ —— 設計・実装・検証を別人格でやる
iloop 本体は、自分では1行もコードを書かずに、3つのサブエージェントに投げます。
| 役 | やること | 権限 |
|---|---|---|
| designer(設計) | Issue を読み、実装計画書を書く | 書けるのは計画書だけ |
| implementer(実装) | 計画書どおりに実装し、ビルド・テストを通してコミットする | コードだけ書ける |
| verifier(検証) | 受け入れ基準を1項目ずつ、自分でコマンドを叩いて判定する | 読み取り専用 |
実装役は作業ログを検証役には渡しません。渡すのは「計画書」「受け入れ基準」「変更ファイル一覧」だけ。実装役が「直しました」と言っているのを検証役が鵜呑みにしないように、文脈を切ってコミットが実在するかの確認から始めさせます。ここが検算として機能するかどうかの分かれ目です。
検証が FAIL なら設計役に指摘事項を戻します。これをiloop内で既定ラウンド繰り返し、ループを合格で抜けられなければ(品質基準に満たなければ)Issueのラベルを agent:blocked にして人間を呼びます。無限にループを回すのではなく、問題が発散する前に人間ゲートに辿り着かせます。
受け入れ基準が全てを決める
この内側ループの品質は、Issue の受け入れ基準で決まります。検証役が判定できない基準を書くと空回りします。
| ✕ 判定できない | ○ 判定できる |
|---|---|
| 正しく動くこと |
swift test の EmptyNameTests がグリーン |
| クラッシュしないこと |
greet("") が空文字を返し、例外を投げない |
| 使いやすくなること | (機械では判定不可 → 「人間が確認すること」へ移す) |
Issueの中に「使いやすくなること」のような検査項目があった場合、検証役の合否判定からは外します。外しますがPRレビュー内の追加チェック項目として人間に届け、人間側のチェックを受けます。この線引きを上図の「②起票」時点でやってしまうのが /iloop-issue 機能で、検査項目として機械的に判定できるものと、できないものをClaudeが自動的に分別してくれます。
GitHub との絡み方
前述のように iloop は Issue と PR に別々の役割を持たせています。
Issue = 問題提起と最終結果 なぜやるか / どうなったか
PR = 実務の履歴 どう直したか / レビューのやり取り
実装後に人間がやる確認作業(差分レビュー、動作確認)は PR の文脈にあるので、やり取りは PR に書きます。Issue には、より大きな方針の変更を記載します。これがそのまま「差し戻しの深さ」の合図になっています。
| 人間がコメントを書いた場所 | AI 側の解釈 |
|---|---|
| Issue にコメント | 方針から見直す。実装のやり直しもありうる |
| PR にコメント | いまの実装を前提に、続きから直す |
「ボタンの色だけ変えて」のつもりで書いた1行のために設計をまるごとやり直す、という無駄な作業を防ぐための約束です。またAI のコメントには <!-- loop-agent --> という隠しマーカーを先頭に入れてあり、これを含むかどうかで「人間の番か、自分の番か」を判定します。これが無いとAI が自分の発言に反応して永久に回り続けてしまいます。
人間へのバトンの渡し方
PR ができたら、AI は PR にこういうコメントを残しSlackで報告してきます。
## 🔵 あなたの番です
PR #17 を作りました(ラウンド 1/3)。
### 確認してほしいこと
- [ ] スワイプ削除のアニメーションが不自然でないこと(実機)
### 確認のしかた
MyApp.xcodeproj を開いて、記録一覧画面で行を左スワイプ
### 機械で確認したこと
受け入れ基準 9/9 合格。
### 機械では判定できなかったこと
スナップショットテストの基盤が無いため、描画位置は目視が必要。
### 次にすること
- 問題なければ `/iloop-merge 17`
- この PR の中で直せること → PR にコメントしてから `/iloop`
- やり方から考え直す → Issue にコメントしてから `/iloop`
たとえば上の例では人間は「確認してほしいこと」を実施して「動きが不自然ではない」という人間的な判断を行います。不自然であればPRにコメントして差し戻し、合格であればPRをマージしてIssueは解決となります。人間とAIがそれぞれの担当範囲で「何を確認済みで、何が未確認か」の履歴として明示するのが、このPRコメントの仕事です。
コマンドは6つ
/iloop-init リポジトリに Loop を導入する(最初の1回だけ)
/iloop-issue 相談内容を、受け入れ基準付きの Issue に落としてGitHubに起票する
/iloop Issue を処理する。複数あれば人間ゲートまで連続で回す
/iloop-status いま誰の番か、次に何をすればいいかを1画面で出す
/iloop-review PR の中身を確認しながらAIと相談し、その場で PR にコメントを投稿する
/iloop-merge PR をマージし、Issue をクローズして後始末する
その他の工夫
worktree で隔離する
Issue ごとに git worktree を切って agent/issue-<番号> ブランチで作業させています。
親リポジトリは触らないので、連続処理中でも main は汚れません。
後始末を手順に書く
マージ後の後始末(worktree 削除/ローカルブランチ削除/git remote prune/ローカル main の更新)は、どれを飛ばしても次の /iloop が壊れます。たとえば main の更新を忘れると、古い main から worktree が切られて「直したはずのバグが復活した状態」で作業が始まります。手動運用なら気づきますが、無人だと気づかずに不適当な修正が進んでしまいます。
運用の流れ
前提条件
/loop 5m /iloop で実働セッションがIssueを待っている状態
作業を与える
人間が管理側AIに相談する → /iloop-issue で問題点を3本起票
iloopがIssueを拾って作業開始
設計→実装→検証のループを回す
品質ゲートの判断でPRを作って人間へ通知
Slack に「あなたの番です」が届く
人間は /iloop-status で全体像を把握
/iloop-review でPRの中身を見て、気になる点をコメント
iloopがPRコメントを拾って作業再開
再び設計→実装→検証のループを回す
品質ゲートの判断でPRを更新して人間へ通知
Slack に「あなたの番です」が届く
人間は/iloop-status で全体像を把握
実装が正しく検証されていたので /iloop-merge でマージ・後始末
iloopが次のIssueを拾って作業開始
設計→実装→検証のループを回す
・・・
人間が関与するのは Issue を書くところと PR に回答するところだけです。remote-controlを使ってモバイルのClaudeアプリから監視するのが便利です。
まとめ
-
/loopは「時間のループ」、/iloopは「品質のループ」。二重ループにして無人運転 - 状態は GitHub のラベルに持たせる。ローカルに状態を作らない
- 設計・実装・検証を別人格にして、検証役には実装役のログを渡さない
- 受け入れ基準を「機械が判定できるもの」と「人間が見るもの」に分ける
- 止まる条件を先に決め、回り続けるループは作らない
AI に丸投げするのでも、全部自分でやるのでもなく、判断だけを人間に残す。その境界線を Issue と PR という既存のGitHub道具で引けたことで回しやすいループになったと思います。
通常、人間が行うIssueやPRとは少しニュアンスが違うかもしれませんが、AIと連携するにはこのようなやり方もアリではないかと思っています。