chrome-relay について
Chrome Relay は、ブラウザー拡張機能とローカルのネイティブホストを介して実際の Chrome を操作する、エージェント向けコマンドラインツールです。ログイン済みのブラウザープロファイルを対象に、ページの確認、操作、ネットワーク情報の取得、ファイルのアップロードを行えます。
主な機能
- 01ブラウザープロファイルへのコマンド振り分け
- 02操作可能な参照付きページ確認
- 03クリック、入力、文字入力、ページ移動
- 04条件待機とページ変更の確認
- 05スクリーンショットとネットワーク情報の取得
- 06複数方式によるファイルアップロード
活用シーン
- 01ログイン済みブラウザーでのタスク自動化
- 02ウェブページの確認と操作
- 03複数の Chrome プロファイルでの作業
- 04ブラウザーフォームからのファイルアップロード
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ kiluazen/ kstack --skill chrome-relayインストール後、Claude Code で/chrome-relayを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.mdreferences/patterns.mdtroubleshooting.md詳細
Chrome リレー
Chrome 拡張機能とローカルネイティブホストを介して、ユーザーが実際に使用している Chrome を操作します。ログイン済みブラウザーの状態(認証 Cookie、セッション、インストール済み拡張機能)が重要な場合に優先して使用してください。
セットアップ
- Chrome 拡張機能
- CLI:
npm install -g chrome-relay@latest chrome-relay install chrome-relay --version chrome-relay doctor
最新の CLI を使用してください。複数ブラウザー/プロファイルのルーティングとアップロードには >= 0.8.0 が必要です。Dia の検出とエージェント向けのプロファイル選択機能には >= 0.8.1 が必要です。インストール後も表示されるバージョンが 0.8 未満の場合は、0.8 のコマンドを使用する前に停止し、PATH 上の古いバイナリを解決してください:
chrome-relay --version
which -a chrome-relay # macOS/Linux; use `where chrome-relay` on Windows
セッションの開始時に、chrome-relay profile list を実行してください。接続済みのインスタンスが 1 つなら、通常のコマンドでプロファイルフラグは不要です。複数ある場合は、操作を開始する前に、どのブラウザーとプロファイルにアクセスできるかを正確に確認できます。
基本的な流れ
chrome-relay tabs # find or create a tab
chrome-relay navigate "https://kushalsm.com" --new # background tab by default
chrome-relay snapshot --tab 1234 -i # see the page: actionable elements get @refs
chrome-relay click @e12 # act on refs, no --tab, no selector
chrome-relay fill @e14 "hello"
chrome-relay wait --text "Saved" --tab 1234 # block until the page reacts
chrome-relay snapshot --tab 1234 --diff # print only what changed (~100 tokens)
スナップショットの出力はコンパクトなインデント付きテキストで、ほとんどのページで通常 1~15 KB です。jq は不要なので、直接読み取ってください:
- link "Hacker News" [ref=e4]
- textbox "Search" [ref=e41]: current value
- checkbox "Remember me" [checked, ref=e42]
- clickable "Open card" [ref=e88] # cursor-pointer div the AX tree missed
参照にはタブ情報が含まれます。 click @e12 は e12 を生成したタブを操作し、アクティブなタブは操作しません。ユーザーが引き続きブラウジングしていても安全です。矛盾する --tab を指定すると、target_conflict エラーが返されます。
参照の有効期間。 参照は同一ページ内の DOM 変更をまたいで有効です(バックエンドの nodeId をキャッシュし、ノードが置き換えられた場合はロールと名前による再検索で修復します)が、実際のナビゲーションが発生すると無効になります。無効な参照は error.code = stale_ref を返します。snapshot を再実行してください。
クリックの横取り。 参照によるクリックでは、まずクリック位置のヒットテストが行われます。オーバーレイ/固定ヘッダー/モーダルがその位置を占有している場合、横取りしている要素を示す error.code = click_intercepted が返されます。閉じるかスクロールしてから再試行してください。クリックは配信されていません。fill/type ではこのチェックを省略します(覆われた入力欄にも書き込めます)。
ツールの概要
| コマンド | 説明 |
|---|---|
tabs | ウィンドウとタブを、それぞれの tabId とともに一覧表示します |
navigate <url> | 現在のタブで開きます。--new を指定するとバックグラウンドタブで開きます(デフォルト)。--active を指定すると前面に表示します。--tab <id> を指定すると、既存のタブに切り替えます。 |
snapshot --tab <id> -i | 操作可能な @refs を含むページスナップショットです。アクセシビリティツリーとカーソルで操作できる要素の走査を組み合わせ、単一の ref 空間でコンパクトなテキストを出力します。-d N は深さの上限、-s <css> はサブツリーへの範囲指定、-u は href の追加、--diff は前回のスナップショットからの変更のみの出力、--json は refs マップを含む構造化されたエンベロープを指定します。 |
wait <css|@ref> / wait --text / --url <glob> / --load networkidle / --fn <js> | 条件が満たされるまで待機します(1 回の呼び出しにつき 1 条件、デフォルトは 10 秒、最大 25 秒)。wait 1500 は単に待機します。タイムアウト時のエラーには現在のページ状態が含まれます。 |
get text|value|attr|count|title|url <target> | 値を 1 つ取得し、プレーンテキストで標準出力に出力します。完全なスナップショットは取得しません。get text @e12、get attr @e7 href、get count ".row" のように指定します。 |
batch '[{"name":"chrome_...","args":{...}}, ...]' | 1 回のラウンドトリップで N 件のツールを順番に呼び出します。デフォルトではエラー時に中断します。ワイヤーツール名を使用してください。 |
skills get core | インストール済みバイナリのバージョンに一致した、この手順書を出力します。 |
click <@ref | selector> --tab <id> | 要素の中央で、信頼されたホバー、押下、解放を行います(pointerType: "mouse")。ref の場合は --tab は不要です。 |
click --x N --y N --tab <id> | DOM ハンドルのないキャンバス/SVG チャート内部で座標指定のクリックを行います。 |
hover <@ref | selector | --x --y> | ポインターの移動のみを行います。:hover スタイルが適用されます。 |
fill <@ref | selector> <value> | <input>/<textarea>/<select> に値をアトミックに書き込みます。React の値トラッカーをバイパスします。ref はシャドウ DOM の内部にも到達します(セレクターでは到達できません)。 |
type <text> [-s <@ref | selector>] | CDP の Input.insertText を使用します。contenteditable/Draft.js/Lexical/ProseMirror で使用します。キャレット位置に追記するため、値が入力済みの場合は先に入力欄をクリアしてください。 |
keys <chord> --tab <id> | 単一キーまたはキーの組み合わせを送信します。例:Enter、Tab、Escape、Cmd+K、Shift+ArrowDown。 |
js <code> --tab <id> | MAIN world で Runtime.evaluate を実行します。値を返すには return を使用します。トップレベルの await を使用できます。 |
screenshot --tab <id> -o <path> | PNG 形式のスクリーンショットを撮影します。--full はビューポート外もキャプチャします。--max-edge N はサイズを変更します。 |
screencast --tab <id> -o <path> | CDP を介してタブを録画します(描画駆動)。アクティブなタブが必要です。 |
network --tab <id> | HTTP リクエスト/レスポンスのリングバッファを表示します。タブごとに直近 200 件が保持されます。network body <requestId> は Chrome にデータが残っている間に本文を取得します。network har --with-bodies は本文付きの HAR をエクスポートします。 |
console --tab <id> | console.log/warn/error とページ例外を表示します。直近 200 件が保持されます。 |
viewport | デバイスのビューポート、DPR、モバイルフラグ、タッチ、UA をエミュレートします。 |
workspace / group | 名前付きウィンドウ/タブグループを管理し、複数のエージェントが別々のウィンドウを操作できるようにします。 |
switch <tabId> / close <tabIds...> | タブをアクティブ化または閉じます |
self-reload | 再ビルド後に拡張機能のサービスワーカーを再起動します |
release-notes --since <ver> / update | 問い合わせ可能な変更履歴です。エージェントが読み取れる JSON 形式です。 |
call <tool> [json] | 任意の内部ツールにそのまま渡します。 |
read / ax / click-ax | 非推奨。snapshot/click @ref のエイリアスです。削除予定のため、新しい作業では使用しないでください。 |
適切なテキスト入力ツールの選び方
| 対象要素 | ツール |
|---|---|
<input>、<textarea>、<select>(React 制御、シャドウ DOM を含む) | fill @ref |
[contenteditable]、role="textbox"、Draft.js/Lexical/ProseMirror、X の投稿作成欄、LinkedIn の DM、新しい Reddit の投稿作成欄 | type |
| 送信、メニューの操作、修飾キーのショートカット | keys |
| コンボボックス/オートコンプリートの候補選択 | フィルターに type で入力し、続けて keys ArrowDown、keys Enter を実行します(理由) |
| フレームワーク内部への操作、スクレイピング、カスタムウィジェット | js |
複数のブラウザーとプロファイル(CLI >= 0.8)
主にサポートされている対象は、Google Chrome(複数の Chrome プロファイルを含む)、Dia、Brave です。1 つの CLI から、拡張機能がインストールされている接続済みのすべてのインスタンスにアクセスできます。各 Chrome プロファイルは、個別に指定できるインスタンスです。
インストーラーは、Chrome Canary、Chromium、Edge、Vivaldi、Arc、Opera のネイティブホストのマニフェストパスも認識します。現在のタスクで検証されていない限り、これらは互換性のある対象として扱ってください。マニフェストが検出されただけで、ブラウザーが完全にサポートされているとは限りません。
アクセスしたい各ブラウザー/プロファイルに拡張機能を一度ずつインストールし、その後 chrome-relay install を一度実行すると、検出された各ブラウザーがそれぞれ独自のホストを起動できるようになります。
chrome-relay profile list # who's connected: label, browser, id prefix
chrome-relay profile label work # one connected: label it directly
chrome-relay --profile 3f2a profile label personal # several: first pick by id prefix
chrome-relay --profile work tabs # scope any command (global or per-command flag)
chrome-relay click @3f2a:e12 # snapshot refs are profile-qualified and route by THEMSELVES
接続されているインスタンスが 1 つの場合、フラグは不要で、すべての操作が暗黙的にそのインスタンスにルーティングされます。複数ある場合、プロファイルを指定しないコマンドは profile_ambiguous で失敗します。このエラーは選択肢として扱い、表示された正確な --profile <label|idprefix> のいずれかを選んで、コマンドを再実行してください。推測で選ばれることはありません。参照にはタブと同じようにプロファイルが紐付けられるため、一度 snapshot を実行すれば、その後フラグが必要になることはほとんどありません。古いラベルを解除するには chrome-relay profile unlabel <name> を実行してください。
アップロード(CLI >= 0.8)
方法は 3 つあり、自動フォールバックはありません。失敗した場合は方法名が示されるので、次の方法を選んでください。
chrome-relay upload set --selector 'input[type=file]' --tab 123 ./cv.pdf # direct; works on HIDDEN inputs
chrome-relay upload choose --click-ref @e4 ./cv.pdf # trigger opens the OS picker: intercepted, NO dialog appears
chrome-relay upload drop --selector '.dropzone' ./avatar.png
ファイルはパスで指定します。Chrome が直接読み込むため、サイズ上限はありません。not_a_file_input の場合は choose を使用してください。no_file_chooser の場合は、トリガーが間違っているか、ドロップゾーンです。file_access_denied の場合は、chrome://extensions → Chrome Relay →「Allow access to file URLs」を確認してください。set/choose は呼び出し後に入力欄が実際に保持している値を返します。
要素の指定方法:フォールバックの順序
snapshot -iの@ref:デフォルトの方法です。ボタン/リンク/入力欄、名前付きコンテンツ、カーソルポインターのある div の集合(スイープ)、シャドウ DOM に対応します。- CSS セレクター:セレクターを静的に把握していて、snapshot が不要な場合に使用します。
jsで調査してから、座標でクリック:canvas の内部や SVG チャートのセグメントに使用します(匿名の<path>要素には、どこにも DOM ハンドルがありません)。chrome-relay js --tab 1234 "const r = document.querySelector('svg path').getBoundingClientRect(); return {x: r.x + r.width/2, y: r.y + r.height/2}" chrome-relay click --tab 1234 --x 312 --y 218
ポーリングせず、待機する
操作のたびに snapshot を実行すると、ターンを無駄にします。変化するページでは、次の低コストなループを使用してください。
chrome-relay click @e12
chrome-relay wait --text "Saved" --tab 1234 # or wait <selector> / --url / --load
chrome-relay snapshot --tab 1234 --diff # only the changes, refs included
よくある落とし穴
snapshot -iは情報の抽出ではなく、操作のために使います。 ref が付く要素だけが出力されます。ダッシュボードの指標、段落のテキスト、チャートのラベルなど、インタラクティブでない値は除外されます。実際に確認したところ、Cloudflare Pages のメトリクスページでは-iを使うとすべての数値が表示されませんでした。情報を読み取るには、通常のsnapshot、get text <target>、またはjsによる射影を使用してください。typeは追記します。 キャレットの位置に挿入します。入力欄に値(自動保存された下書きやデフォルトのテキスト)がある場合は、まずjsまたはkeys(Cmd+A の後に Backspace)で消去してください。- ページ遷移後、ref は無効になります。
stale_refは、ページが変化したことを示します。snapshot を取り直してください。同じ ref を再試行しないでください。 - 座標はすぐに古くなります。
getBoundingClientRectで確認してからスクロール/リフローが発生すると、クリック先が誤った要素になります。特にオートコンプリートのポップアップでは、座標クリックではなくキーボード操作を使用してください。 - クリックは「成功」したのに何も起きません。 最初に
document.elementFromPoint(x, y)で診断してください。ラッパーやフォームの背景が返された場合、座標が間違っています。正しい要素が返されたのに状態が変わらない場合は、chrome-relay <0.5.20 を使用している可能性が高いです。アップグレードしてください。
その他のレシピ:references/patterns.md 障害モード:references/troubleshooting.md
運用ガイダンス
- 早々に諦めないでください。 クリックの失敗は情報であり、停止の合図ではありません。
capture:trueを指定してドキュメントレベルのリスナーをアタッチし、何が発火するかを確認してください。chrome-relay js --tab 1234 " ['pointerdown','mousedown','click'].forEach(t => document.addEventListener(t, e => console.log(t, e.target.tagName, e.target.className), {capture:true}) ); return 'listening' " # do the action, then: chrome-relay console --tab 1234 - シークレットを出力しないでください。
jsでトークンや API キーを取得するときは、結果を直接ファイルに書き込んでください。echo $TOKENを実行したり、シェル文字列に展開したりしないでください。スクロールバック、ログ、ツールのトランスクリプトに残ります。 networkの出力は秘匿してください。 リクエスト/レスポンスのヘッダーには、Cookie、認証/CSRF トークン、アカウント ID、プロジェクト ID が含まれます。chrome-relay networkの出力をそのままチャット、ドキュメント、課題、コミットに貼り付けないでください。必要なフィールド(URL、ステータス、タイミング)だけに絞るか、先にヘッダーを秘匿してください。- 取り消せない操作(フォームの送信、メッセージの送信、アカウントの変更)を行う前に、キャプチャしてください。スクリーンショットのパスを保存してください。
ガードレール
- エラーは構造化されています。メッセージのテキストではなく、
relayError.code(stale_ref、click_intercepted、element_not_found、target_conflict、profile_ambiguous、timeout)に基づいて分岐してください。 - フラグの意味が不明な場合は、
chrome-relay <command> --helpを正式な情報源として参照してください。これらのドキュメントは最新でない場合があります。