ここ数ヶ月、Claude Codeにレビューを任せながら、少しずつ信頼できる範囲を広げてきました。最初はdiffを読ませて指摘を出すだけ。問題なさそうなら、CIとエビデンスを確認した上でApproveまで任せる。ガードレールを1つずつ作りながら「ここまでは任せて大丈夫」のラインを引いてきた形です。
前回の記事では、承認自動化やスキル設計で「画面に張り付かなくていい仕組み」を整えました。レビュー自動化のガードレールと合わせて、自動化の土壌がある程度できた。次に試しているのは、その土壌の上で仕事の収集から実行まで自律的に回せないかという実験です。
1日動かしてみた結果、PR8本作成、レビュー対応3件、他者PRレビュー1件。誤解のないように書いておくと、自分が8本分のコードを書いたわけではありません。「仕事を自分でやる」のではなく「仕事の仕組みを作って回す」側に立った結果です。
この記事では、Slack→Notion→Claude Codeのサブエージェントという自動パイプラインの設計と、試してみて分かった失敗・課題をまとめます。
全体像: AIタスクキューのアーキテクチャ
まず構成図を示します。
登場するコンポーネントは3つです。
- Notion DB「AI Task Queue」 — タスクの状態管理。pending/in_progress/completed/skippedの4ステータス
- collect — Slackからタスクを自動収集してNotionに登録
- execute — Notionのpendingタスクを1件ずつ取り出し、サブエージェントで実行
これらをcronで5分/10分おきに回します。reconcile(整合性チェック)は手動で不整合を検出・修正するフェーズですが、今回は省略します。
collect: Slackから仕事を拾う
collectフェーズでやっていることは単純です。Slackの特定チャンネルを読み、自分に関係するタスクを検出してNotionに登録します。
検出の起点になっているのは slack-review-notify というbotです。GitHub PRのレビュー依頼やレビューコメントをSlackに通知してくれます。このbotの投稿メッセージとスレッド内のリプライを解析して、自分に関係するタスクを拾っています。
検出対象
| 検出パターン | 判定条件 | タスク種別 |
|---|---|---|
| レビュー依頼 | slack-review-notifyで自分宛メンション | PR Review |
| レビュー指摘 | 自分のPRスレッドに💬リアクション付きリプライ | Review Fix |
| アラート | 監視ツールからの通知 | Alert Triage |
重複チェック
同じPR番号+同じタスク種別の組み合わせがNotion DBに既にあれば、登録をスキップします。これがないと同じレビュー依頼が5分おきに積まれ続けます。
課題: 直近50件問題
現在の実装はSlackチャンネルの直近50件のメッセージに依存しています。ここに落とし穴があります。
2日前に投稿されたレビュー依頼スレッドへ、今日新しいリプライがつきました。しかし親メッセージは直近50件から外れており、collectはこのリプライを検出できませんでした。
対策として検討しているのはSlack Search APIへの切り替えです。from:slack-review-notify in:#your-ops-channel after:yesterdayのようなクエリで、メッセージの位置に依存しない検出が可能になります。ただしSearch APIはレートリミットが厳しい(Tier 2: 20回/分)ため、collectの実行間隔とのバランスを取る必要があります。
execute: タスクを自動実行する
executeフェーズの核心はリスク分類です。レビュー自動化で「ガードを作る→問題ないか確認→範囲を広げる」を繰り返してきたのと同じ考え方で、全タスクを無条件に自動実行するわけではありません。
リスク分類: 間違えたときの損害で判断する
| リスクレベル | 判定基準 | 挙動 |
|---|---|---|
| 高リスク | 決済処理、認証、データ削除を含む変更 | skippedにしてSlack DMで通知 |
| 中リスク | ビジネスロジックの変更 | worktreeで修正、diff確認後にpush |
| 低リスク | typo修正、コメント追加、インデント修正 | 自動修正・push・レビュー回答まで完結 |
この分類の考え方は「間違えたときの損害の大きさ」で決めています。typoを直し忘れても影響は小さいですが、決済ロジックを誤って変更すれば実害が出ます。AIが判断を間違える前提で、間違えても被害が小さいものだけ自動実行します。
実際にこの日skippedにしたのは3件。いずれもリスク分類表の「高リスク」に該当するタスクでした。
実例: レビュー指摘のインデント修正
社内リポジトリのPRでレビュアーから「インデントが揃っていない」という指摘を受けました。executeの処理フローはこうなります。
- Notion DBからpendingタスクを取得
- タスク種別が「Review Fix」、対象PRのdiffを読む
- レビューコメントの内容を解析 → インデント修正 → 低リスクと判定
- worktreeを作成し、ソースを読んで修正
- commitしてpush
- GitHub APIのCheck Runs APIでCI結果を確認(Commit Status APIでは不十分。詳細は後述)
- CI通過を確認後、
gh pr reviewでレビュー回答を投稿 - re-review requestを送信
- Notion DBのステータスをcompletedに更新
ここまでの所要時間は約1分です。午前中に自分で手動対応した同種のタスクは、割り込みやコンテキストスイッチを含めて約1時間かかりました。インデント修正という単純なタスクだったからこそ出た差で、複雑なタスクならここまで開きません。
手動では以下の各ステップの間に待ち時間が入ります。
- PRを開く
- 差分を読む
- エディタを開く
- 修正
- commit → push
- CI待ち
- レビュー回答を書く
サブエージェント並行実行: この日のハイライト
この日の最大の生産性ブーストは、夕方のサブエージェント並行実行でした。
午前 vs 夕方の比較
| 時間帯 | 方式 | 成果 | 所要時間 |
|---|---|---|---|
| 午前 | 手動でレビュー指摘を修正 | PR1本 | 約1時間 |
| 夕方 | サブエージェント4並行 | PR3本 | 約10分 |
午前のタスクはレビュー指摘への対応で、夕方は定型的なコード削除なので、単純な速度比較にはなりません。並行実行の効果が出やすいのは、こうした定型タスクです。
夕方に実行したのは旧構成コードの削除PR3本。いずれも「このファイル/メソッドはもう使われていないので削除する」という定型的なタスクです。
worktree隔離
並行実行で重要なのは、各サブエージェントが独立したworktreeで作業することです。
git worktree add ../app--cleanup-a feature/cleanup-a
git worktree add ../app--cleanup-b feature/cleanup-b
git worktree add ../app--cleanup-old-config feature/cleanup-old-config
こうすることで、4つのサブエージェントが同じリポジトリに対して同時に作業しても、ファイルの競合が起きません。各worktreeは独立したディレクトリなので、あるサブエージェントのcommitが別のサブエージェントの作業を壊すことがありません。
バッチ移設の並行実行
バッチ移設2件(レガシーアプリからRailsへの移植)も並行で実行しました。こちらはコード削除より複雑で、1件あたり8〜11分かかりました。
サブエージェントに渡す指示はこのレベルの粒度になります。
レガシーアプリの app/batch/some_task.php を
Railsアプリの lib/tasks/some_task.rake に移植してください。
- 既存のRakeタスクのパターンに従う
- テストも書く
- 両方のロジックが一致することを確認する
抽象的な指示ではなく、入力(PHPファイル)と出力(Rakeタスク+テスト)を明示します。
学んだこと: 失敗と対処
きれいな成功談だけ書いても再現性がないので、この日に実際に踏んだ問題を書きます。
1.「聞かずに実行する」フィードバック
問題: サブエージェントが確認を求めてタスクが止まる。
初期のexecute実装では、サブエージェントが「この修正でよいですか」と確認を求めてきました。これが致命的に遅いです。人間の確認待ちでタスクが止まり、自動化の意味がなくなります。
対処: サブエージェントへの指示に「判断を求めすぎず自分で実行する」「低リスクタスクは確認不要で完結させる」というルールを明示しました。
2. CIステータス確認のAPI問題
問題: Commit Status APIだけ見てCI通過と誤判定した。
GitHub APIでCIの結果を確認する方法が2つあります。
- Commit Status API (
GET /repos/{owner}/{repo}/statuses/{sha}) - Check Runs API (
GET /repos/{owner}/{repo}/commits/{sha}/check-runs)
GitHub Actionsを使っている場合、結果はCheck Runs APIにしか出ません。Commit Status APIだけ見て「CIが通った」と判断すると、実際にはまだ実行中だったり失敗していたりします。
検証段階でこの問題が発覚したため、現在は両方のAPIを確認し、全てsuccessになるまで待機する実装にしています。
3. scope管理の失敗
問題: 別セッションが意図しないタスクをキューに投入した。
別のClaude Codeセッションが意図しないタスクをNotion Task Queueへ投入してしまった事例がありました。collectの検出範囲を広く設定しすぎたことが原因です。
対処: タスク投入時にscopeラベル(例: service-a, service-b)を付与し、executeはscopeが一致するタスクだけ実行するようにしました。
4. collectの検出漏れ
問題: スレッド内リプライがチャンネル一覧に出ない。
前述の「直近50件問題」に加え、もう1つの検出漏れパターンがありました。Slackのスレッド内リプライは、チャンネルのメッセージ一覧には表示されません。スレッドの親メッセージを見つけた上で、conversations.repliesでリプライを取得してください。
この2段階の取得処理を実装していなかった初期バージョンでは、スレッド内のレビュー指摘を検出できませんでした。
再現のためのポイント
自分の環境で同様の仕組みを作りたい人向けに、最低限必要な要素を列挙します。
必要なもの
- Claude Code — サブエージェント起動、コード修正、Git操作の実行基盤
- Notion API — タスクキューのデータストア。DBのCRUDができればよい
- Slack API —
conversations.history,conversations.repliesでメッセージ取得 - GitHub CLI (gh) — PR操作、CI確認、レビュー投稿
- git worktree — 並行実行時の隔離
:::details 最小構成の手順(これから始める人向け)
全部を一気に作る必要はありません。最小構成はこうなります。
- Notion DBを1つ作る(プロパティ: title, status, pr_url, risk_level)
- 手動でタスクを登録する
- Claude Codeにexecuteスクリプトを書かせる(Notion APIでpendingを取得→実行→completed更新)
- 動くことを確認してから、collectを追加する
collectを後回しにする理由は、Slack APIの認証設定やメッセージ解析のパターンマッチに時間がかかるからです。まず「キューからタスクを取って実行する」部分だけ動かして手応えを確認するのがよいです。

コメント