ログインしたままのChromeを、AIエージェントがどうやって遠隔操作しているのか。今日その仕組みを腑分けして、手順書とスキルにまとめ、別系統のAIエージェントに再帰的にレビューさせて穴を潰した。途中で「タブは開けるのにDOMが読めない」という壁にぶつかり、その壁の正体を突き止めるところが一番の山だった。
発端:拡張機能だと思っていた
Claude Code がブラウザ確認のとき、自分のログイン済み Chrome をそのまま操作しているように見える。最初これを Chrome 拡張機能の仕業だと思い込んでいた。
調べてもらうと違った。正体は Chrome DevTools Protocol(CDP) だった。Chrome が昔から備えている「外部からブラウザを遠隔操作するための口」(リモートデバッグ。既定ポート 9222)に、MCP サーバーが WebSocket で繋いでいるだけだった。拡張機能は一切介在していない。
ここがわかると、別のソフトでも同じ口を叩けば同じことができるはず、という見通しが立った。
課題:別系統のAIが自分のログイン環境に繋げない
別系統のAIエージェント(codex)を使おうとしたら、こちらがログインしている Chrome にアクセスできなかった。そこで「Claude Code がやっているやり方」を手順書(マークダウン)に書き起こし、codex 側に渡すことにした。
まず Chrome のバージョンを確認した。バージョンで推奨される接続方式が変わるからだ。手元は Chrome 148 だった。144 以降なので、複数の接続方式がそのまま使える。
ここで Chrome 136 の仕様変更が効いてくる。
- Chrome 136 以降:ログイン済みの既定プロファイルでは、従来の
--remote-debugging-portが無効化された(Cookie 窃取対策)。デフォルトの User Data ディレクトリを指定したまま 9222 を開こうとすると、DevTools remote debugging requires a non-default data directoryで弾かれる。 - 逃げ道は2つ。専用の
--user-data-dirを切る(ただしログインは引き継がれない)か、chrome://inspect/#remote-debuggingで「incoming debugging connections」を許可して、生きているログイン済み Chrome に後付けでアタッチする。
手順書には、後者(生セッションへのアタッチ)を本命に据えた。
山場:「タブは開ける」と「DOMが読める」は別レイヤー
codex の試行ログを読んで原因を追ったとき、ここで詰まった。
タブが開いていること自体は確認できる。なのに、その開いているタブの DOM をこちらが読めない。
CDP ではこの2つが別レイヤーになっている。
- 列挙・起動:どんなターゲット(タブ)があるかを並べる、新しいタブを開く
- アタッチ:特定のターゲットに繋いで、その DOM を読み書きする
「開く」は通っても「アタッチ」で止まる、という現象が起きていた。経路を切り分けるため、agent-browser の --profile 指定でログインプロファイルを開く経路を個別に確かめた。
agent-browser --profile "Profile 1" の Profile 1 が、Chrome の内部ディレクトリ名なのか表示名なのかでズレると「開くけど読めない」を再現する。agent-browser が認識しているプロファイル名を読み取り系のコマンドで確認したところ、Profile 1 = 表示名 eurekapu.com(自分のログインアカウント)で一致していた。名前のズレは原因ではなかった。
残ったのは純粋に CDP の「列挙はできるがアタッチできない」壁、そして --profile 指定が実プロファイルをその場で使おうとするために、通常 Chrome がそれを開いているとロックがぶつかる問題だった。
codexが先にスキル化していた
手順を詰めている最中に、codex 側で chrome-login-cdp というスキルが先に出来上がっていた。動いたらしい。中身をレビューしてほしいと頼まれたので、本体の SKILL.md を精読した。
よく出来ていた。生セッション優先・コピー方式の回避・good/bad signs・known-good な接続URLまで揃っていた。ただ1点だけ重大な見落としを指摘した。
--auto-connectが「生のログイン済み Chrome」に刺さる前提条件= incoming debugging connections の有効化が、トラブルシュート欄に埋もれている。本来は冒頭の必須セットアップに置くべきだ。
裏取りもした。Local State に "remote_debugging":{"user-enabled":true} が入っていた。つまり過去に chrome://inspect でこの許可を有効化してあったから、--auto-connect が生の Chrome に刺さっていた。これがスキル成立の条件そのものなのに、文章では末尾に追いやられていた。
再帰レビュー:自分のレビューを別系統のAIに検算させる
ここで筆者は、自分のレビューをそのまま信じず、codex 自身に第三者レビューさせることにした。AIのレビューを別のAIに検算させる、再帰的なレビューだ。
引数にコード断片を詰め込むとツール呼び出しが壊れる(tool call malformed)ので、提案5件を整理したファイルを作り、codex にはそのファイルを参照させた。
返ってきた判定で、自分の認識が事実誤認だったとわかった。
codex は agent-browser のバイナリ文字列(agent-browser-profile-, Failed to copy profile, could not copy Local State)まで読み込み、--profile は実プロファイルをその場で使うのではなく、一時ディレクトリにコピーする実装だと突き止めた。
つまり「通常 Chrome を閉じれば --profile が実体を占有してログインを維持できる」という自分の提案は誤りで、それ自体がコピー方式(= App-Bound Encryption で失敗するやつ)だった。残る提案も全部「要修正」だった。
結論はシンプルだった。
- codex が作ったスキルはそのまま使って問題なし
- 自分の「改善案」の方に穴があった(特に提案5は事実誤認)
- スキルへの修正はほぼ不要
人間が判断する係、AI が実行・検算する係、という構図がそのまま出た一日だった。自分のレビューを過信せず別系統のAIに検算させたら、自分の事実誤認の方が先に見つかった。
別件:月次収益取り込み手順書も再帰レビューにかけた
同じ日に、もう1本の手順書を再帰レビューにかけた。FinMind API から台湾上場銘柄の月次売上を取得し、Turso(libSQL/SQLite互換)へ冪等に格納する実行指示書だ。
codex(gpt-5.5)に渡したら、初回は「このまま実行は不可。6点直せば実行可」と返ってきた。create_time 欠落・エラー再試行・レスポンス検証・接続手順に実行事故リスクがある、という指摘だった。
「全部反映して、問題がなくなるまで再帰的にレビュー」と指示して回した。
- Round 1:6点指摘 → 全反映(Turso 接続情報はスキルで確認)
- Round 2:2点(
executescript非対応など)→ 反映 - Round 3:2点(404 未分類・402/403 の ban 悪化)→ エラーを3クラスに整理して反映
- Round 4:「重要な問題は残っていない」= 収束
ただし Round 4 で事故が起きた。resume --last を重ねてセッション文脈が肥大化(3回目で90万トークン)し、codex が頼んでもいない無関係な git コミットを勝手に実行しようとして .git/index.lock 権限エラーでハングした。実際にコミット ee95dad9 が作られてしまっていた。ハングしたタスクは即停止した。
再帰レビューは効くが、resume を重ねすぎると文脈が汚染されて暴走する、という教訓を体で覚えた。
この手順書は明日の積み残しにした。
-
tw_monthly_revenue_ingest.mdの指示書に沿って実装・実行する(codex レビュー4周で収束済み)
今日の学び
- ログイン済み Chrome の遠隔操作は拡張機能ではなく CDP(リモートデバッグ 9222)
- Chrome 136+ で既定プロファイルのデバッグは封じられた。逃げ道は専用 user-data-dir か
chrome://inspectの許可接続 - CDP では「タブを開ける」と「DOM を読める(アタッチ)」が別レイヤー
-
agent-browser --profileは実体ではなく一時コピーを使う実装。ログイン維持を期待してはいけない - 自分のレビューを別系統の AI に検算させると、自分の事実誤認が先に見つかることがある
-
resume --lastの重ねがけは文脈汚染で暴走を招く。長くなったら切る