🧭 本記事は Claude Code実務運用シリーズ の STEP 6「サブエージェント化する」です。
前回のクラッシュ調査チームを、症状からコードを逆引きする不具合調査に広げます。チケットへの投稿は人の承認ゲートを通します。
シリーズ全体の地図と読む順は 親記事 にまとめています。
この記事のゴール
Redmine のチケット URL を 1 つ渡すと、Claude Code のエージェントチームが次の作業を続けて行う仕組みを作りました。
- チケットを読み、報告された再現条件を整理する
- 症状から関連コードを探し、根本原因の仮説を立てる
- 別のエージェントがその仮説を反証する
- 修正案・影響範囲・回帰テスト計画を作る
- 調査レポートを Markdown でローカルに保存する
- 人の承認を得てから、レポートをチケットに添付し、要約をコメントで投稿する
この記事では、チームの構成を Mermaid の図で示し、設計で迷った点とその理由を書きます。対象は、Claude Code のスキルとサブエージェントで「調査」を任せたい人と、AI に外部サービスへ書き込ませるときの止め方を考えている人です。
前提となる考え方(仮説を作る役と壊す役を分ける、記憶をファイルに置く、停止条件と予算を先に決める)は、クラッシュ調査チームの記事で詳しく書きました。本記事はその続編で、クラッシュ以外の不具合に広げたときに変えた点を中心に書きます。
スキルとサブエージェントの仕様は 2026 年 10 月時点の Claude Code で確認したものです。
クラッシュ調査との違い
クラッシュ調査では stack trace が手がかりになります。表示崩れや操作不能といった一般の不具合には、それがありません。手がかりはチケットの文章と添付のスクリーンショット、それに「この OS 以降で起きる」といった条件だけです。
そのため、次の 3 点を変えました。
| 観点 | クラッシュ調査 | 一般の不具合調査 |
|---|---|---|
| コード調査の起点 | stack trace のフレーム | 画面名・ボタン文言・部品名からの逆引き |
| 証拠の種類 | クラッシュ集計・コード・履歴 | チケット・添付画像・コード・履歴・関連チケット |
| 外部への書き込み | しない(読み取り専用) | 承認後にレポート添付とコメント投稿 |
最後の行がいちばん大きな違いです。調査結果をチケットに残すところまで自動化したかったので、外部への書き込みを入れました。そのぶん、止める仕組みを設計の中心に置いています。
チーム構成
オーケストレーター(スキル本体)と、~/.claude/agents/ に定義した 6 体のサブエージェントで構成します。オーケストレーターは自分では調査しません。仕事は、入力の確認、ブラウザでの生データ取得、ループ制御、状態ファイルの更新、承認の取得、承認後の投稿です。
| エージェント | 役割 | 主な入力 | 出力 |
|---|---|---|---|
| ticket-analyst | チケットの事実整理、個人情報のマスク、不具合かどうかの分類、関連チケットの検索 | チケット本文・コメント・添付 | ticket.md |
| code-investigator | 画面名や文言から関連コードを特定し、症状が起き得る条件と変更履歴を調べる | ticket.md・リポジトリ | code-map.it<N>.md |
| hypothesis-builder | 根本原因の仮説と、再現条件の説明を作る | 上記すべて | hypotheses.md |
| falsifier | 仮説を壊すつもりで検証する | 仮説・証拠・リポジトリ | falsification.it<N>.md |
| fix-planner | 修正案(適用しない差分スケッチ)、影響範囲、回帰テスト計画を作る | 仮説・反証結果・リポジトリ | fix-plan.md |
| reporter | 全ファイルを統合し、レポートとコメント案を作る | STATE_DIR | report.md・コメント案 |
エージェント同士は会話を共有しません。受け渡しはすべて状態ファイルとプロンプトで行います。会話が長くなっても、途中で止まっても、状態ファイルから再開できます。
事実を集めるだけの ticket-analyst と reporter は軽いモデルに固定し、コードの逆引き・仮説・反証・修正計画はセッションのモデルを引き継ぎます。調査の質を決めるのは後者だからです。
関連チケットは画面名で探させる
チケット本文に関連チケットが書かれていなくても、同じ画面や同じ部品の過去の不具合が見つかることがあります。過去の扱い(OS 側の修正待ちだった、など)は反証の強い材料になります。そこで ticket-analyst には、画面名・部品名をキーワードに、プロジェクトを絞って検索させています。プロジェクトを絞らない検索は、無関係なチケットばかり返ってきて役に立ちませんでした。
現在時刻はオーケストレーターが渡す
サブエージェントは Bash を git の読み取りコマンドだけに制限しているので、date を実行できません。そのままだと成果物の生成日時を推定で書き、実時刻とずれます。オーケストレーターが取得した現在時刻を全エージェントのプロンプトで渡し、その値を使わせています。
ブラウザ操作はオーケストレーターだけが行う
Redmine の MCP サーバーはファイル添付に対応していないので、添付取得と投稿は既存ブラウザを chrome-devtools MCP で操作して行います。このブラウザ操作は、サブエージェントには持たせていません。
理由は 2 つあります。カスタムサブエージェントには MCP ツールが継承されない場合があり、手順の途中で失敗しやすいこと。もう 1 つは、外部に書き込める道具を持つ主体を 1 つに絞ると、承認の確認箇所も 1 つで済むことです。サブエージェントに渡すツールは読み取り系だけにし、定義ファイルに書き込み系ツールが混ざっていないかをスクリプトで検査しています。
ページ本文の取得は evaluate_script で innerText を返させてファイルに保存します。このツールは戻り値を JSON として保存し、拡張子も .json に付け替えます。保存先は .json を前提にして、テキストへの変換を手順に入れておく必要があります。
調査の流れと承認ゲート
承認の質問は 1 つだけで、選択肢は「添付とコメントを投稿」「文面を直してから投稿」「添付のみ」「投稿しない」の 4 つです。無回答のときは投稿しません。状態は「承認待ち」で保存されるので、再実行すると承認の手前から再開します。
送信前の照合
送信の直前には、フォームの状態を機械的に照合します。コメント欄と添付欄以外(ステータス、担当者、優先度、カスタム項目など)が、編集を開いた直後の値から変わっていたら送信しません。
照合は、画面のアクセシビリティツリーではなく、フォームの値を JavaScript で JSON に取り出して行います。編集フォームのスナップショットは数十 KB になり、コンテキストに収まらないためです。編集を開いた直後と送信直前の 2 回分を保存し、差分のキーを列挙して判定します。作業時間の入力欄が空であることも条件に入れています。
コメント欄は ID で特定する
Redmine の編集フォームには、ラベルが「コメント」の入力欄が 2 つあります。単行のほうは作業時間記録のコメント欄で、本当のコメント欄は無名の複数行テキストエリア(#issue_notes)です。ラベルで選ぶと作業時間のほうに入力してしまい、送信すると作業時間の記録が作られます。手順では ID で特定し、入力後に値を読み戻して、用意したコメント案と一致することを確かめています。
停止条件
調査ループは、仮説を作って反証にかける 1 周を最大 2 回まで繰り返します。抜ける条件は次の 6 つです。
S5 だけ分岐を 1 段増やしています。時間を超えた時点で仮説が固まっているなら、修正計画は作ります。修正案はレポートの中心なので、時間超過を理由に落とさない、という判断です。修正計画を作らないのは、S5 だけが成立したときに限ります。
時間予算は 60 分にしています。各エージェントの処理に加えて、添付の取得や状態の統合にも時間がかかり、1 周と修正計画・レポート統合だけで 40 分を超えることがあるためです。
事実と推測を分ける
レポートとコメントは、毎回同じ Markdown の構造で出力します。冒頭に「判定・根本原因・再現条件の解釈・次の一手・詳細の所在」の 5 項目を置き、その後に 10 節を並べます。
すべての主張は次の 3 つのどれかに分けます。
- 確認済み: チケットに書いてある、添付で見える、コードの該当行や履歴にある。証拠 ID を付ける
- 推測: 根拠になる証拠 ID と確度(高・中・低)を付ける
- 未確認: 確認の手段(誰に、どこで、どうやって)を付ける
このチームは実機で再現していないので、レポートにもコメントにも「未再現(コード調査のみ)」と書かせます。
証拠 ID はチケット由来が T、コード調査が M、反証が F、修正計画が P で始まる通し番号です。投稿前に、レポートが引用した ID がすべて元ファイルに実在するかをスクリプトで確かめます。存在しない ID、未記入のプレースホルダー、メールアドレスや電話番号らしき文字列、コメント案に残った見出し記号や証拠 ID は、投稿前に止まります。
スクリプトで拾えないものもあります。たとえば reporter が本文に残した「F11 ではなく F9 を参照」のような作業メモは、ID 自体は実在するので検査を通ります。こうした作業メモの除去は、オーケストレーターが目視で行う修正範囲として手順に明記しています。
改善を人の承認で回す
手順書は、実際の画面やツールの挙動と食い違うことがあります。直す作業を AI に任せきりにしないよう、改善の経路を決めています。
AI が書けるのは、学習候補(LEARNINGS)と提案カード(PROPOSALS)の追記だけです。提案カードは「小さな差分 1 つ」に限り、反映するかどうかは人が決めます。反映後は、スキルの定義ファイル同士の整合性(予算値の一致、書き込み系ツールの混入、エージェントの役割表との対応)をスクリプトで検査します。
投稿手順を変えたときは、本番のチケットで送信ボタンの手前まで操作し、フォームを破棄して履歴が変わっていないことを確かめます。外部に書き込む手順は、送信しない再検証で確かめてから使います。
まとめ
- チケット URL を入口に、事実整理からコード調査、仮説、反証、修正計画、レポートまでを 6 体のサブエージェントで分担した
- 外部への書き込みはオーケストレーターに集め、承認の質問 1 つと送信前の機械的な照合で止める
- 出力は毎回同じ構造にし、事実・推測・未確認を分け、形式はスクリプトで検査する
- 手順の改善は学習候補と提案カードを経由し、人の承認で反映する
このシリーズの歩き方
Claude Code実務運用シリーズ ― 暴走させない、から仕組みにするまで。
- ◀ 前の記事: 【Claude Code】"調査"をエージェントに任せて自壊させない ― ループエンジニアリングで作る自己反証型クラッシュ調査チーム
- ▶ 次の記事: 「このGAイベント、まだ使ってる?」に誰も即答できない ― Google Analytics / Firebase Analytics をコードだけで棚卸しする7体のAIチーム【Claude Code・テンプレ公開】
- 🔍 あわせて読む: Claude Codeでブラウザを“見る”から“操作”へ:接続済みChromeを動かしてみた【chrome-devtools-mcp】 ― 接続済みChromeに操作を任せるときの権限設計
- 🗺 シリーズ全記事の地図(親記事)
