
前回構築したClaude Codeのマルチエージェント環境を実践投入してみた 〜要件定義から実装まで〜
はじめに
前回は、Windows 11+WSL+tmux+Claude Codeを使って、split panes機能を使って画面を分割しマルチエージェント開発環境を立ち上げるところまで行いました。
今回はその続きとして、前回構築した環境を実際に使い、Claude Codeのマルチエージェントで要件定義から実装まで進めてみたいと思います。

前回の記事では「環境を作る」ことが主目的でしたが、今回は「その環境を使って、実際にどう開発を進めていくのか」を検証するのが目的です。
今回試したことは大きく3つ。
- 実装に備え、
CLAUDE.mdを改善する - マルチエージェント体制で要件定義を進める
- 同じ体制で要件定義に従って実装する
では、やってきましょう!
今回作るもの
今回作るのは、Chrome拡張機能のタブマネージャーに設定しました。
イメージとしては同じサイトのタブを自動でまとめたり、同じURLのタブを統合したりするような拡張機能って感じです。

自分はかなりタブを開く方で、資料を読んでいて気になった関連情報を開き、その中にある知らない単語をまた調べて……というのを繰り返していると、気付けばタブが50個近く開いていることがあります。しかも「あとで読もう」と思って開いたタブはずっと残り続けています。
今回、何を題材に開発しようかなと考えた際、この大量のタブが同じサイトのタブは自動でグルーピングされ、アルファベット順や50音順できれいに並んでいたら便利そうだなと感じ、作ってみて~となったので題材としました。
マルチエージェント開発の進め方を検証することが主目的のため、要件定義や設計だけで記事の大半が埋まってしまうような規模の大きすぎる題材は避けました。Chrome拡張機能は、実用性がありつつも今回の検証に収めやすいサイズの題材です。最初に手を出す小規模のモノとして、個人的にはおススメです!
まずCLAUDE.mdをベストプラクティス寄りに改善
前回作成したCLAUDE.mdは動かすことを優先しましたが、今回は実践投入の前にCLAUDE.mdを見直し、基本的な振る舞いを整えてから検証を行うことにします。
見直しに際して、以下のリポジトリを参考にCLAUDE.mdを改善するようClaudeへ依頼することにしました。
こちらのリポジトリは海外の開発者がClaude Codeのベストプラクティスをまとめてくれたもので、全87個のTipsが記載されています。とても良い読み物ですので読むのをお勧めしますが、今回はこのベストプラクティスを前回作成したCLAUDE.mdに反映させてみましょう。
反映させるには、Claudeに以下のプロンプトを渡すだけです!
今のCLAUDE.mdに記載されている内容を元にhttps://github.com/shanraisshan/claude-code-best-practiceを読んで、ベストプラクティスをCLAUDE.mdに反映して。
但し、マルチエージェント部分は触らないか追記のみで。
ポイントとして、マルチエージェント部分は壊さないように指示し、それ以外のベストプラクティスだけを取り込ませるようにしました。
理由として、マルチエージェントの挙動はCLAUDE.mdの記述内容に影響を受けるためです。特にマルチエージェント体制に関する指示を書き換えると、期待通りにsplit panesで分割されなくなる場合があることを記事作成前に色々弄っているとき判明しました。
また、split panesを安定して動作させたい場合は、設定ファイルだけでなくプロンプト側でも明示することが重要でした。タスクが軽い場合、分割するまでもないと判断されマルチエージェント自体は内部で動作していても、画面上ではsplit panesで分割されずバックグラウンド的に処理されることがありました。そのため、画面分割された状態を確実に再現したい場合はプロンプト内で「必ずsplit panesで分割して進めて」のようにあえて明示しておくと良いでしょう。
今回のように画面分割の挙動も含めて検証したい場合は、以下のように捉えると整理しやすいでしょう。
settings.jsonはAgent Teamsを有効化する設定tmuxとteammateModeはsplit panes表示の土台CLAUDE.mdはClaudeに「複数人で進めるべき」と判断させる文脈づけ- プロンプトは、split panesで進めるかどうかを明示する指示
要件定義フェーズ
いきなり実装には入らず、まずはplanモードで要件定義の整理から始めましょう。
Claude Codeにはいくつかのモードがあり、今回使ったplanモードは、ファイル変更やコマンド実行をせず、読み取り中心で調査と計画だけを進めるためのモードです。要件定義や設計整理のように、まだ実装に入らない段階で使いやすいです。標準のdefaultモードは通常の権限確認つきの実行、acceptEditsモードはファイル編集系を自動承認する実装向きのモードです。
また、2026年3月12日にresearch previewとして追加されたautoモードもあります。これは、Claude自身がパーミッション判断を行う新しいモードで、自動で承認を行うが、無条件にすべてを許可するわけではなく、Claudeがリスクを見ながら判断するモードです。便利な一方で、まだresearch preview段階であり、隔離された環境での利用が推奨されている点や、完全にすべての危険な操作を防げるわけではない点には注意が必要です。
これらのモードはClaude codeの対話画面でshift+tabキーを押すことで切り替える事が出来ます。

このフェーズでは、まず4人体制で要件定義を進めてみます。各エージェントの役割は次の通りです。
- マネージャーが要件定義の確認と差戻し判断を担当する
- フロントエンドとバックエンドが追加機能や考慮漏れを議論する
- QAが議論内容を取りまとめ、他2人に追加情報がないか確認したうえで報告する
- 最後にマネージャーが要件定義の最終版を確認して報告する
そして、要件定義だけ整理したかったためplanモードを使います。そのうえで、上記の役割分担で要件定義フェーズを進めるよう、以下のプロンプトを渡しました。
今回、マルチエージェント機能の試運転も兼ねる。4人体制でまずは要件定義を進めて欲しく、必ずsplit panesで分割して進めて。
1人はマネージャーとして指示出しや意見の取りまとめを、3人はエンジニアでそれぞれフロントエンド、バックエンド、QA。
まず、マネージャーは最後に示す要件定義を確認し、エンジニア側に考慮漏れや追加すべき機能を考え3人がお互いに話し合いQAが意見を取り纏めるよう伝える。
エンジニア側は意見がまとまったらマネージャーに報告,QAは報告前に他2人から追加の情報が無いか確認すること。
マネージャーは更新された要件定義に考慮漏れや矛盾が無いか考え、エンジニア側へ差戻し再度話し合いを指示するか、要件定義の最終版をこちらへ報告する。プログラムの作成はこの段階で行わないように注意。
要件:
- 同じサイトのタブを自動的にグループ化する
- 同じサイトのタブが2個以上のときのみグループ化する
- 同じサイトのタブが1個になったらグループ解除する
- グループ内で別のドメインのサイトを開いたらグループ外へ移動する
- グループ内ではアルファベット・50音順で整列する
- 並び替え機能はON/OFF可能にする
- グループ名はURLから決める
- 同じURLのタブが開かれたときは古い方へ統合する
- 同一URL統合もON/OFF可能にする
- Manifest V3対応
この要件定義は抜け漏れをエージェント同士の議論で補完できるかどうか見るため、あえて最初の要件には一部の考慮事項を書きませんでした。
例えば、
- 手動グループへの対応
- 固定タブをグループ化しないこと
等です。同様に非機能要件、例えばどの機能がどの順番で動作するか、どの機能が優先的に働くのかもプロンプトには入れず、どういった形で実装されるか検証してみます。
では、実行してみましょう。プロンプトを打ち込んで実行してみると・・・

ペインが立ち上がってきました!

全員autoモードになってる。なんでや・・・(設定でautoモードをデフォに指定してた)。
さ、最近はplanモード使わなくなったって偉い人が言ってたので大丈夫?です。
気を取り直して観察しているとエンジニア側から提出された要件定義がマネージャーによって差戻されています。

エンジニア側とマネージャー側で2回往復が行われ、その後に要件定義が完了したと報告が挙がりました!
実際に出てきた要件定義最終版がこちら。そこそこ長いです。
Chrome Tab Manager — 要件定義最終版
作成日: 2026-04-15
策定プロセス: FE/BE/QA 3者議論 + マネージャー精査(差し戻し2回)
- 確認・同意した要件(変更なし)
| # | 要件 |
|---|---|
| 2 | 同じサイトのタブが2個以上のときのみグループ化する |
- 修正要件
要件1: 同じサイトのタブを自動的にグループ化する
- 「同じサイト」のグループキー判定方式は新規K-1の設定に従う(デフォルト: eTLD+1モード)
- eTLD+1モード(デフォルト): registrable domainで判定。
tldts(~15KB)を使用- 例:
mail.google.comとdocs.google.com→ 同じgoogle.comグループ - 例:
user1.github.ioとuser2.github.io→ 別グループ(PSL対応)
- 例:
- ホスト名モード: フルホスト名(hostname)で判定
- 例:
en.wikipedia.orgとja.wikipedia.org→ 別グループ - 例:
mail.google.comとdocs.google.com→ 別グループ(トレードオフ)
- 例:
- ポートのグループキーへの包含は新規K-2の設定に従う(デフォルト: 含めない)
要件3: 同じサイトのタブが1個になったらグループ解除する
- 「グループ解除」= タブをグループから外し、空になったグループは削除する
- 理由: 空グループ残存によるUI混乱を防止
要件4: グループ内で別のドメインのサイトを開いたらグループ外へ移動する
- ページナビゲーション完了時にeTLD+1を再判定し、不一致なら即座にグループ外へ移動
- OAuth認証フロー等で一時的に別ドメインに遷移した場合もグループから外れる(V1既知制限)
要件5: グループ内ではアルファベット・50音順で整列する
- ソートキー: タブタイトル
- ソート方式:
Intl.Collator('ja')による比較 - ソート実行トリガー:
- タブがグループに追加された時
- グループ内のタブでURLナビゲーションが発生し、グループ追加/移動が実行された直後
- 並び替え設定がOFF→ONに変更された時
- タイトルのみの変更(未読通知数の変化等)では再ソートしない
要件6: 並び替え機能はON/OFF可能にする
- OFF時: ソート処理を停止、現在のタブ順序はそのまま維持
- ON時: 全グループ内のタブを即座に再ソート
要件7: グループ名はURLから決める
- eTLD+1モード時:
.comの場合: SLD部分のみ(例:google.com→google).com以外: eTLD+1をそのまま表示(例:amazon.co.jp→amazon.co.jp)
- ホスト名モード時(新規K-1でホスト名モード選択時):
- フルホスト名をそのまま表示(例:
en.wikipedia.org→en.wikipedia.org)
- フルホスト名をそのまま表示(例:
- ポートON時(新規K-2でON選択時):
- グループ名にポートを付記(例:
localhost:3000、example.com:8080)
- グループ名にポートを付記(例:
- ユーザーが手動でグループ名を変更した場合は上書きしない
要件8: 同じURLのタブが開かれたときは古い方へ統合する
- 「同じURL」の定義:
scheme + host + path + query + fragmentの完全一致(何も除外しない)- 比較方法:
new URL(url).hrefによる正規化後の完全一致 - 理由: フラグメント除外はSPAハッシュルーティングで誤統合→データロスのリスク。安全側に倒す
- 比較方法:
- 「古い方」の定義: タブIDが小さい方(≒作成が古い方)を残す
- 「統合」の挙動: 新しいタブを閉じ、古いタブにフォーカスを移す。古いタブはリロードしない(スクロール位置・フォーム入力状態を維持)
- 判定タイミング: 新タブが
complete状態(ページ読み込み完了)になった時点で実行
要件9: 同一URL統合もON/OFF可能にする
- OFF時: 統合処理を即座に停止。既に閉じられたタブは復元しない
- ON切り替え時のフロー:
- 全タブスキャンで重複件数を算出
- 対象0件: 確認なしで即座にON
- 対象1件以上: 「N個の重複タブが見つかりました。統合しますか?」と確認表示 + 対象タブのプレビュー
- 「統合する」: 統合を実行しON確定
- 「キャンセル」: ONにはなるが既存タブの一括統合はスキップ。以降の新規重複のみ統合
要件10: Manifest V3対応
- Service Worker駆動(バックグラウンドページ不使用)
- SW停止→再起動時の状態復元: 実際のタブ状態を正(truth)とし、
chrome.storage.localは差分検出の起点 - イベントリスナーはトップレベルで同期的に登録
chrome.alarmsによる5分間隔の定期整合性チェック- イベントデバウンス: タブ操作イベントに300msのデバウンスを適用しバッチ処理
manifest.jsonにminimum_chrome_version: "89"を明記
- 新規追加要件
新規A: 自動グループ化全体のON/OFFトグル
- 拡張機能の自動グループ化を一時停止できるトグル
- OFF時: イベント受信するが処理をスキップ。既存グループはそのまま維持
- ON復帰時: 全タブ再スキャンでグループ化を再適用
新規B: 対象外タブの定義
グループ化の対象外:
| タブの種類 | 理由 |
|---|---|
| ピン留めタブ | Chrome APIの制約でグループに追加不可 |
chrome://, about:blank, chrome-extension://, devtools:// |
特殊URL |
新規タブページ(chrome://newtab) |
グループ化の意味なし |
data: URL / blob: URL |
eTLD+1判定不可 |
file:// URL |
追加パーミッションが必要(V1対象外) |
グループ化の対象(特殊処理あり):
| タブの種類 | 処理 |
|---|---|
localhost / 127.0.0.1 / [::1] |
グループキー = localhost(ポート含有は新規K-2に従う)、グループ名 = localhost または localhost:PORT |
| IPアドレス(プライベート/グローバル) | グループキー = IPアドレスそのもの(ポート含有は新規K-2に従う)、グループ名 = IPアドレス |
- ポートのグループキーへの包含は新規K-2の設定に従う(デフォルト: 含めない)
新規C: 複数ウィンドウはウィンドウごとに独立管理
- グループ化はウィンドウ単位で独立動作(クロスウィンドウのグループ化なし)
- タブがウィンドウ間でドラッグ移動された場合は移動先のルールで再グループ化
新規D: グループカラーの自動割り当て
- ドメイン名のハッシュ値から色を決定(9色: grey, blue, red, yellow, green, pink, purple, cyan, orange)
- 同じドメインには常に同じ色(一貫性)。9色超は重複許容
- ユーザーが手動で色を変更した場合は上書きしない
新規E: ユーザーの手動変更の尊重
- 拡張機能が作成したグループIDを
chrome.storage.localに記録 - ユーザー手動作成グループには一切干渉しない
- 拡張機能作成グループでも: グループ名・色の手動変更は上書きしない。タブの自動移動は引き続き実行
- SW再起動時の判定: ストレージに記録されていないグループ = ユーザー作成とみなし干渉しない(安全側)
- Chrome再起動でグループIDがリセットされるため、再起動後は全グループがユーザー作成扱い → ゼロから管理開始
- 既存グループに干渉せず、新たに条件を満たすタブのみ新規グループ作成
新規F: グループ展開/折りたたみ状態の維持
- 新規グループは展開状態で作成
- 既存グループの展開/折りたたみ状態は自動操作時に変更しない
新規G: タブ統合時の通知
- 統合発生時: 拡張機能アイコンに一時的なバッジ表示(数秒で消える)
- ポップアップ内に直近の統合履歴表示(例: 「gmail.com のタブを統合しました - 2分前」)
- OS通知は使用しない(頻繁な統合で過剰になるため)
新規H: 設定UIの構成
- ポップアップ: 全体ON/OFF・並び替えON/OFF・同一URL統合ON/OFF(日常操作)
- オプションページ: グループ化キーモード(K-1)・ポート分離(K-2)などの詳細設定
- バッジ: 拡張機能の有効/無効状態の視覚表示
新規I: ストレージ戦略
chrome.storage.sync: ユーザー設定(ON/OFFトグル等)。デバイス間同期。102KB制限chrome.storage.local: グループ状態キャッシュ、管理対象グループIDリスト。5MB制限
新規J: アクセシビリティ要件(V1最低限対応)
- キーボードナビゲーション(Tab/Enter/Spaceでトグル操作可能)
- 適切なARIAラベル
- フォーカスインジケーターの可視化
- フォントサイズはシステム設定に追従
新規K: グループ化粒度の設定オプション
K-1: グループ化キーモード(オプションページで設定、デフォルト: eTLD+1)
eTLD+1モード(デフォルト): registrable domainでグループ化。mail.google.comとdocs.google.comは同グループホスト名モード: フルホスト名でグループ化。en.wikipedia.orgとja.wikipedia.orgは別グループ(mail.google.comとdocs.google.comも別グループになるトレードオフあり)- モード切り替え時: 全タブ再スキャンで即座に再グループ化
K-2: ポートをグループキーに含める(オプションページで設定、デフォルト: OFF)
- OFF(デフォルト): ポートを無視して同一グループ(現行動作)
- ON: 非標準ポート(http:80・https:443 以外)をグループキーに含める
localhost:3000とlocalhost:8080→ 別グループexample.comとexample.com:8080→ 別グループ- グループ名にもポートを付記(例:
localhost:3000、example:8080) - 標準ポート(http:80・https:443)は含めない(通常のサイトの動作に影響なし)
- ON/OFF切り替え時: 全タブ再スキャンで即座に再グループ化
- スコープ外とした提案
| 提案 | 理由 |
|---|---|
| OAuth/リダイレクトのグレース期間 | SWタイマー管理の複雑さがV1品質リスク。V2で対応 |
| Undo機能 | 実装コスト高。V1ではポップアップ内の統合履歴で代替 |
| ユーザーカスタムグループ化ルール(ドメイン除外・正規表現等) | グループ化の粒度設定(K-1/K-2)はV1対応済み。V2でより細かいカスタマイズを検討 |
file:// URL対応 |
追加パーミッションが必要でユーザーの信頼コスト増 |
| シークレットモード対応 | 通常/シークレット間の設定同期方針要決定。V2で検討 |
| 設定のインポート/エクスポート | ユーザーニーズ確認後に対応 |
| クエリパラメータのブラックリスト | UTMパラメータ無視等。V2以降で検討 |
| ダークモード/ライトモード対応 | Chrome拡張はシステム設定追従が標準。特別対応不要 |
| フラグメント除外オプション | V2でユーザー設定として提供を検討 |
| graceful degradation | minimum_chrome_version: "89" 指定により非対応ブラウザではインストール不可のため不要 |
-
V1既知制限事項
-
OAuth認証フロー等で一時的に別ドメインに遷移した場合、即座にグループから外れる
-
Chrome再起動後はグループIDリセットにより管理状態がゼロから再構築される(既存グループへの干渉なし)
※ 旧制限「サブドメインが意味的に異なるサイトが同一グループになる」は 新規K-1(ホスト名モード) で解消可能。
※ 旧制限「ポート違いが同一グループになる」は 新規K-2(ポートON) で解消可能。
-
V2以降の検討事項
-
OAuth/リダイレクトフロー時のグレース期間
-
Undo機能(
chrome.sessions.restore()ベース) -
シークレットモード対応
-
file://URL対応 -
設定のインポート/エクスポート
-
ユーザーカスタムグループ化ルール(ドメイン除外・正規表現等、粒度設定はV1対応済み)
-
クエリパラメータのブラックリスト
-
フラグメント除外オプション
-
手動グループ間移動後の再グループ化抑制オプション
- 確定技術仕様
| 項目 | 確定値 |
|---|---|
| eTLD+1判定ライブラリ | tldts(~15KB) |
| ソート方式 | Intl.Collator('ja') によるタイトル比較 |
| URL比較方法 | new URL(url).href による正規化後の完全一致 |
| デバウンス時間 | 300ms(バッチ処理) |
| 定期整合性チェック | chrome.alarms 5分間隔 |
| 最低Chrome版 | 89(manifest.json に明記) |
| ユーザー設定ストレージ | chrome.storage.sync |
| 状態キャッシュストレージ | chrome.storage.local |
- 未解決事項(実装開始前に決定が必要)
- 設定データのマイグレーション方針: 将来のバージョンアップで設定スキーマが変わった場合の移行戦略
あえて入れていなかった要件定義以外も追加されており、十分見栄えの良い内容ではないでしょうか・・・!
非機能要件に関して記載が無いのが少し心配ですが、今回はあくまで検証なのでこのまま実装へ進んでいきましょう!実務では絶対にスルーしちゃダメですよ!
実装フェーズ
要件定義に従い、そのまま同じ4人体制で実装を進めていきます。
実際に渡したプロンプトは以下の通りです。
先ほどと同じ4人体制で開発を進めて下さい、必ずsplit panesで分割して進めて。
マネージャーは、決定した要件定義に従いフロントエンドとバックエンドが実装をQAが全体の管理とレビューをする、実装完了後にQAからマネージャーへ報告を行うようにエンジニア側に指示を。
また、お互いに適宜協力しながら実装し、実装完了後に各々報告書を纏めマネージャーに提出するようエンジニア側に指示して。
マネージャーはQAから報告が上がったら製品を確認しバグ、実装漏れやその他気になる箇所をレビューし差戻または完成品をこちらに納品して。
また、各エンジニアから受け取った報告書はマネージャーで纏めて内容をこちらに報告し.md形式で保存して。
ここでは、
- マネージャーが全体方針と確認を担当する
- フロントエンドとバックエンドが実装を進める
- QAが全体の確認とレビューを行う
- 最後にマネージャーが成果物を確認して納品する
という流れで進めました。
実際の画面がこちら

4人体制が整えられ、実装がどんどん進んでいきます。その様子をぼ~っと眺めていると

いつの間にか完成間近です。バックエンドエンジニアが感謝を述べ、QAエンジニアが労いの言葉をかけています。この後は飲み会ですかね、これは。
エンジニア側が解散した後、それぞれから送られた報告書をマネージャーが纏め、全てのタスクが終了したようです。
マネージャーから受け取ったレポートがこちら。結構長めです。
Chrome Tab Manager V1 — 実装報告書
作成日: 2026-04-15
作成者: manager(プロジェクトマネージャー)
- 実装ファイル一覧
| # | ファイル | 行数 | 担当 | 概要 |
|---|---|---|---|---|
| 1 | manifest.json |
27 | BE | MV3マニフェスト |
| 2 | background.js |
616 | BE | Service Worker(グループ化・ソート・統合・整合性チェック) |
| 3 | popup/popup.html |
50 | FE | ポップアップUI |
| 4 | popup/popup.css |
200 | FE | ポップアップスタイル |
| 5 | popup/popup.js |
147 | FE | ポップアップロジック |
| 6 | options/options.html |
42 | FE | オプションページUI |
| 7 | options/options.css |
151 | FE | オプションページスタイル |
| 8 | options/options.js |
45 | FE | オプションページロジック |
| - | icons/ |
- | - | アイコン(icon-16/32/48/128.png、事前配置済み) |
合計: 8ファイル、約1,278行
- 要件定義との照合結果
確認済み要件
| 要件 | 状態 | 実装箇所 |
|---|---|---|
| 要件2: 2個以上でグループ化 | ✅ 充足 | background.js L330 |
修正要件
| 要件 | 状態 | 実装箇所 | 備考 |
|---|---|---|---|
| 要件1: 自動グループ化 | ✅ 充足 | background.js L69-112 | eTLD+1/hostname切替、ポート含有対応 |
| 要件3: 1個でグループ解除 | ✅ 充足 | background.js L389-404 | ungroup + 空グループ削除 |
| 要件4: 別ドメインでグループ外移動 | ✅ 充足 | background.js L380-387 | ナビゲーション後の再判定 |
| 要件5: タイトルソート | ✅ 充足 | background.js L185-206 | Intl.Collator('ja')、タイトルのみ変更では非トリガー |
| 要件6: ソートON/OFF | ✅ 充足 | popup.js L129, background.js L498-499 | OFF→ON時に全グループ再ソート |
| 要件7: グループ名決定 | ✅ 充足 | background.js L115-147 | .com時SLD、ポート付記、手動変更尊重 |
| 要件8: 同一URL統合 | ✅ 充足 | background.js L231-277 | new URL().href完全一致、古いタブ保持 |
| 要件9: 統合ON/OFF | ✅ 充足 | popup.js L104-117, background.js L470-500 | ベースライン方式でキャンセルフロー実現 |
| 要件10: MV3対応 | ✅ 充足 | manifest.json, background.js全体 | SW駆動、alarm 5分、デバウンス 300ms |
新規追加要件
| 要件 | 状態 | 実装箇所 | 備考 |
|---|---|---|---|
| 新規A: 全体ON/OFF | ✅ 充足 | popup.js L124-126, background.js L291,L486,L496 | OFF時処理スキップ、ON時再スキャン |
| 新規B: 対象外タブ | ✅ 充足 | background.js L49-51,L161-169 | 全対象外プロトコル + localhost/IP特殊処理 |
| 新規C: ウィンドウ独立管理 | ✅ 充足 | background.js L279,L561-567 | detach/attach対応 |
| 新規D: グループカラー | ✅ 充足 | background.js L149-158 | ハッシュ→9色、作成時のみ設定 |
| 新規E: 手動変更の尊重 | ✅ 充足 | background.js L176-182,L305-310,L606-607 | managedGroups追跡、SW再起動時クリア |
| 新規F: 展開/折りたたみ | ✅ 充足 | background.js L368 | 新規: collapsed=false、既存: 変更なし |
| 新規G: 統合通知 | ✅ 充足 | background.js L208-219, popup.js L47-78 | バッジ✓(3秒)、履歴(BE:20件/FE:5件表示) |
| 新規H: 設定UI構成 | ✅ 充足 | popup/, options/ | popup=日常操作、options=詳細設定 |
| 新規I: ストレージ戦略 | ✅ 充足 | 全ファイル | sync=設定、local=状態 |
| 新規J: アクセシビリティ | ✅ 充足 | popup/options HTML/CSS | ARIA、focus-visible、rem単位、fieldset/legend |
| 新規K-1: グループ化キーモード | ✅ 充足 | options.js L34-38, background.js L94-98 | dissolve→reprocess |
| 新規K-2: ポート含有 | ✅ 充足 | options.js L41-42, background.js L101-107 | 標準ポート除外 |
- FE/BE統合検証
| チェック項目 | 結果 |
|---|---|
chrome.storage.sync キー名一致(3ファイル) |
✅ enabled, sortEnabled, mergeEnabled, groupingMode, includePort |
chrome.storage.local キー名一致 |
✅ managedGroups, mergeHistory, mergeBaselineMaxTabId |
chrome.runtime.sendMessage 形式一致 |
✅ settingsChanged, getMergePreview, executeMerge |
DEFAULT_SETTINGS 定義一致(popup.js, options.js, background.js) |
✅ 全5キー・デフォルト値一致 |
- セキュリティ検証
| チェック項目 | 結果 |
|---|---|
| XSS | ✅ 全DOM操作がtextContent/createElement。innerHTML/eval不使用 |
| MV3 CSP準拠 | ✅ インラインスクリプトなし、外部URLなし |
| URL解析 | ✅ new URL() + try/catch |
- QAレビュープロセス
BE(5件指摘)
- 指摘2(要件9キャンセルフロー): mergeBaselineMaxTabId方式で修正済み
- 指摘3(onInstalledでreprocessAllWindows未実行): 修正済み
- 指摘4(processWindow同時実行ガード): processingWindows Setで修正済み
- 指摘5(空catchブロック): V1対応見送り(QA合意)
FE(3件指摘)
- title追加: 修正済み
- ダイアログa11y: 修正済み
- updateBadge重複: V1許容(即時フィードバック目的、QA合意)
- マネージャー製品レビュー結果
全8ファイルを精読し、以下を確認:
- ロジックの正確性: eTLD+1判定(getETLD1)、グループ名決定(getGroupName)、ソートトリガー条件、ベースライン方式の統合フロー — いずれも要件定義の仕様通り動作することを手動トレースで確認
- エッジケース: localhost/IPv6(
::1)、about:blank、chrome://newtab — 全て正しく対象外判定 - タイトルのみ変更時の非ソート:
onUpdatedリスナーがchangeInfo.urlとchangeInfo.statusのみを検知し、changeInfo.titleは無視 — 要件5を正確に実現 - 差し戻し: なし
- 既知の課題・技術的負債
7.1 tldtsライブラリ未使用(要件定義からの逸脱)
- 理由: 環境制約(npm install、外部CDN、tgz展開すべてブロック)
- 現状: 自前のハードコードリスト(MULTI_PART_TLDS: 約120エントリ、WILDCARD_TLDS: 17エントリ)
- 影響: PSL完全リスト(約9,000エントリ)ではないため、マイナーなccTLDや新gTLDで誤判定の可能性
- 対応: manager承認済み。V2でビルドパイプライン整備後にtldts移行を推奨
- カバー済み: 主要30か国以上のccSLD + メジャーPSLワイルドカード(github.io, herokuapp.com, vercel.app等)
7.2 空catchブロック(コード品質)
- 内容: background.jsに約15箇所。タブ閉じ等の想定内エラーとバグ由来エラーの区別不可
- 対応: V2でデバッグモードまたはconsole.warn導入を検討
7.3 updateBadgeロジック重複
- 内容: popup.jsとbackground.jsの両方にバッジ更新ロジック
- 判断: FE側の即時フィードバックはUX上有益。V1許容
7.4 processWindow同時実行ガード
- 内容: 処理中に来たイベントはドロップされるが、5分間隔のconsistency-checkで補完
- 判断: V1許容
- 未実装項目
V1スコープ内の未実装: なし
全要件(要件1-10、新規A-K)が実装済み。
- 総合評価
出荷可(Approve)
- V1スコープの全要件が実装済みであり、要件定義書との不整合なし
- FE・BE間のインターフェースは完全に一致
- セキュリティ面でXSS・CSP違反のリスクなし
- アクセシビリティ要件を充足
- MV3ベストプラクティスに準拠
- tldts未使用は唯一の確定技術仕様からの逸脱だが、環境制約による合理的判断(manager承認済み)
- 既知課題4件はいずれもV1リリースに支障なし
-
V2への引き継ぎ事項
-
tldtsライブラリ導入(ビルドパイプライン整備後)
-
空catchブロックの整理(デバッグモード導入)
-
updateBadge共通化の検討
-
processWindow同時実行時のイベント再キュー検討
内容を確認すると、要件に従ってどの機能をどのファイルの何行目に実装したか、セキュリティリスクの確認内容、レビューのプロセスと結果まで整理されており、実装結果の報告として読みやすい内容でした。
また、今回の実装で残った課題や、次回のアップデートで対応したい項目も引継ぎ事項としてまとめられており、そのまま次の開発へつなげやすい形になっていました。
実際の成果物
完成したものをそのまま拡張機能に追加しました。実際に動いている姿がコチラ

GIFだと分かりづらいですが、ええ感じに動いています!
今回の検証を経て振り返り
今回の検証では、4人のマルチエージェント体制で要件定義と実装を進めてみました。
その中で、実際に手順を追って確認できたことを整理してみます。
1. 要件定義フェーズと実装フェーズは分けた方が進めやすい
今回は、最初に要件定義を進め、その後に実装フェーズへ移るという手順で行いました。
このように段階を分けたことで、
最初に何を作るのかを自分の中でも整理出来る
整理した内容を踏まえて実装に入れる
となり、要件の確認とコード作成がごっちゃにならず安心感がありました。
Vibe coding的な観点からみると要件定義と実装は地続きの方が良いと思いますが、個人的にAIで開発を進める場合は、要件定義と実装を最初から分けて進めた方が手順や産物を整理しやすく安心感がありました。
2. 役割を分けると、確認の観点を増やしやすい
今回は、マネージャー1人と、フロントエンド・バックエンド・QAの3人という構成にしました。
この構成にしたことで、要件定義フェーズでは
- 追加すべき機能がないか
- 考慮漏れがないか
- 矛盾がないか
を複数の立場から確認しやすくなりました。
特に今回は、QAが他2人の意見を確認してからマネージャーへ報告する流れにしたため、議論結果を一度整理してから上げる形になっていました。
結果、マネージャーが2回差し戻しを行いより内容が煮詰まっていきました。
これはマルチエージェントを使ったからこその成果であると考えており、単にAIと壁打ちするだけではこちらの知識不足による考慮不足や効率の面で得られなかった成果ではないでしょうか。
3. split panesを再現したい場合は、設定だけでなくプロンプトでも明示した方がよい
今回の検証にあたり、split panesの成否にはsettings.jsonだけでなく、CLAUDE.mdとプロンプトの両方が影響している事が事前調査で判明しました。
特に、軽いタスクでは、マルチエージェント自体は動いていても画面上ではsplit panesにならず、バックグラウンド的に処理されることがありました。
そのため、画面分割された状態を確認したい場合は、環境設定だけに頼らずプロンプトでもsplit panesを明示しておく方が再現しやすいと分かりました。
4. 最初のプロンプトで指定しなかった内容は、必要に応じて後から補う前提で見た方がよい
今回は、要件定義の抜け漏れを議論で補完できるかを見るため、あえて最初の要件から一部を外していました。
その結果、手動グループへの対応や固定タブの扱い以外にも、多くの補足事項が追加されました。
一方で、非機能要件である機能が動く順番・優先度は定義されませんでした。最初のプロンプトでもう少し明示した方が、後続の実装フェーズを安定させやすかったと感じました。
そのため、マルチエージェントで要件定義を進める場合でも、
- 何をあえて議論に委ねるか
- 何を最初から明示しておくか
は分けて考えた方がよさそうです。
特に、処理順序・優先順位・例外時の扱いのような非機能要件に近い部分は、最初からプロンプトに含めた方が実装時のブレを減らしやすいと考えています。
この辺りは自分の好みかどうかといった観点も絡んできますので、自分は何が好きかという観点でプロンプトに組み込む事も視野に入れると良いと思います。
まとめ
今回の検証を通して、少なくとも次のことが確認できたと考えています。
- 要件定義と実装は分けて進めた方が整理しやすい
- 役割を分けると、要件の確認観点を増やしやすい
- split panesを再現したい場合は、設定だけでなくプロンプトでも明示した方がよい
CLAUDE.mdの内容も挙動に影響するため、変更時は確認しながら進めた方がよい
今回は、まずこの流れで実際に開発を進められることを確認できました。
最後に
今回は、Claude Codeのマルチエージェントを使って、要件定義から実装までを実際にやって検証してみました。
前回は「環境を作った」段階で終わりましたが、今回はもう一歩踏み込んで、
CLAUDE.mdの改善- マルチエージェント体制での要件定義
- マルチエージェント体制での実装
- 動作確認と振り返り
まで試してみました。
マルチエージェント体制で開発することにより、AIとの対話形式では得られない経験や、プロンプト次第でまだまだ精度よく開発出来そうだなという感触を得ることが出来ました!
次回は、なぜ今回4人体制で進めたのか、その理由からより抽象化したマルチエージェントの構造に対する知見へと内容を深めていきたいと思います。
おわり!








