開発者向け
CC Bridge 開発者向けガイド
CC Bridge の API を使うと、ペアリング済みの PC やブラウザを、自分のプログラムや AI エージェント(Claude Code など)から操作できます。 認証、API、端末ごとに使えるツール、記録と安全装置、独自の端末をつなぐ方法をまとめています。
しくみ
CC Bridge は 3 つの役割でできています。
- 端末はブリッジへ外向きにつなぐので、端末側でポートを開けたり、公開 IP を用意したりする必要はありません。
- API の 1 回の呼び出しが 1 つの命令です。端末が結果を返すまで応答を待ちます。
- 端末・利用者はテナント(会社や部署の単位)に分かれていて、自分のテナントの外の端末は見えません。
はじめかた
- トークンを受け取る。管理者にコンソールの「利用者」で利用者を作ってもらい、アクセストークン(
ccu_で始まる文字列)を受け取ります。トークンは発行したときに一度だけ表示されます。 - 端末をつなぐ。インストールのページからアプリか Chrome 拡張を入れ、サインインするか接続コードで登録します。
- API を呼ぶ。まず、トークンの持ち主と操作できる端末を確かめます。
export CC_BRIDGE_URL=https://cc-bridge.elc-gateway.com
export CC_BRIDGE_TOKEN=ccu_... # 管理者から受け取ったトークン
# トークンの持ち主と、操作できる端末
curl -s -H "Authorization: Bearer $CC_BRIDGE_TOKEN" $CC_BRIDGE_URL/api/whoami
curl -s -H "Authorization: Bearer $CC_BRIDGE_TOKEN" $CC_BRIDGE_URL/api/handlers端末 ID(hdl_ で始まる文字列)は、一覧の handlerId です。コンソールの端末一覧でも、ID を押すとコピーできます。つながっている端末(connected: true)に命令を送ってみます。
curl -s -X POST $CC_BRIDGE_URL/api/handlers/hdl_0123456789abcdef/cmd \
-H "Authorization: Bearer $CC_BRIDGE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"desktop.system.info","params":{}}'認証と権限
すべての API に Authorization: Bearer <トークン> を付けます。トークンがない、または無効なときは 401 unauthorized が返ります。
| 役割 | 操作できる端末 |
|---|---|
| メンバー | 自分が所有する端末と、管理者に割り当ててもらった端末 |
| テナント管理者 | 同じテナントのすべての端末。端末の停止と再開もできます |
操作できない端末を指定すると、存在しない端末と同じ 404 unknown-handler が返ります。ほかの人の端末があるかどうかは分からない作りです。端末が接続中でも、割り当てがなければ 404 です。自分の端末ではない PC を使うときは、管理者に端末の ID を伝えて割り当ててもらってください。GET /api/handlers に出てくる端末が、いま操作できる端末です。
- トークンは環境変数などで渡し、コードやリポジトリには書かないでください。
- 漏れたときは管理者に再発行を頼んでください。再発行すると、古いトークンはすぐに使えなくなります。
- 同じトークンを複数のプログラムで使うときは、
X-Sessionヘッダーに見分けるための名前(40 文字まで)を付けてください。監査ログと、同時操作の知らせに出ます。
API
ベース URL は https://cc-bridge.elc-gateway.com です。{id} は端末 ID です。
端末
/api/whoamiトークンの持ち主。{ kind, userId, name }
/api/handlers操作できる端末の一覧。{ handlers: [...] }
/api/handlers/{id}1 台の詳細。connected・os・hostname・handlerVersion・tools(その端末で使えるツール)など
命令
/api/handlers/{id}/cmd任意のツールを実行します。{ name, params, timeoutMs }。ツールは下の「ツール」を見てください。
/api/handlers/{id}/execコマンドを実行します(desktop.exec の近道)。{ cmd, cwd, timeoutMs, env } → { exitCode, stdout, stderr, durationMs }
/api/handlers/{id}/screenshot画面を撮ります(desktop.screenshot の近道)。本文は desktop.screenshot の引数です。
ファイル
/api/handlers/{id}/fs/read読む。{ path, encoding, maxBytes }。encoding は utf-8 か base64
/api/handlers/{id}/fs/write書く。{ path, content, encoding, mkdirs, overwrite }。既にあるファイルは overwrite: true のときだけ上書きします
/api/handlers/{id}/fs/push?path=…&mkdirs=1&overwrite=1大きなファイルを送ります。本文はバイト列そのまま(Content-Type: application/octet-stream)。4 MB ずつ中継し、最後に SHA-256 で照合します → { ok, path, bytes, sha256, verified }
/api/handlers/{id}/fs/pull?path=…ファイルを受け取ります。応答の本文がファイルのバイト列です
# 送る(本文はファイルのバイト列そのまま)
curl -s -X POST "$CC_BRIDGE_URL/api/handlers/$ID/fs/push?path=C:/work/data.zip&mkdirs=1&overwrite=1" \
-H "Authorization: Bearer $CC_BRIDGE_TOKEN" \
-H "Content-Type: application/octet-stream" \
--data-binary @data.zip
# 受け取る
curl -s -o report.pdf "$CC_BRIDGE_URL/api/handlers/$ID/fs/pull?path=C:/work/report.pdf" \
-H "Authorization: Bearer $CC_BRIDGE_TOKEN"接続と記録
/api/handlers/{id}/testブリッジから端末への接続テスト。{ ok, results: { ws, tunnel, … } }
/api/handlers/{id}/update-check端末に更新の確認を指示します。自動更新がオンの端末は、新しい版があれば入れ替わります
/api/handlers/{id}/audit?limit=200その端末の監査ログ。{ audit: [...] }
登録と停止
/api/pair/{code}/approve接続コード(ABCD-EFGH)を承認します。承認した端末はあなたの所有になります。/deny で拒否
/api/handlers/{id}/block端末を停止します(テナント管理者)。すぐに切断し、/unblock するまで再接続を断ります
/api/handlers/{id}ペアリングを解除します(所有者)。もう一度つなぐには登録し直しが必要です
近道の /exec・/screenshot・/fs/* は Windows・Mac のアプリ用です。Chrome 拡張には /cmd でツール名を指定して送ります。
応答とエラー
命令が成功すると、次の形で返ります。data の中身はツールごとに違います。
{
"ok": true,
"data": { "os": "windows", "hostname": "…", "cpu": { … }, "memory": { … } }
}直近 60 秒以内に別のセッションが同じ端末を操作していると、contention が付きます。命令は実行されます(ロックではありません)。マウスやキーボードの操作がぶつかるおそれがある、という知らせです。
{
"ok": true,
"data": { … },
"contention": {
"others": [{ "actor": "user:usr_…(…)@nightly", "secondsAgo": 12 }],
"warning": "この端末は直近60秒以内に他のセッション(…)も操作しています。…"
}
}| 状態 | error | 意味 |
|---|---|---|
| 400 | name-required など | 必要な項目がありません |
| 401 | unauthorized | トークンがない、または無効です |
| 404 | unknown-handler | 端末がない、または操作できません |
| 409 | handler-not-connected | 端末がつながっていません(停止中を含む) |
| 422 | ssh-sweep-blocked | SSH を大量に試すコマンドを止めました(「記録と安全装置」) |
| 501 | client-too-old | 端末のアプリが古く、その機能に対応していません |
| 502 | command-timeout など | 時間切れ、または端末側のエラーです。error に理由が入ります |
時間と大きさ
- 命令の待ち時間は既定で 60 秒です。
timeoutMsで変えられますが、途中の経路で 100 秒前後で切れることがあります。長い処理は 90 秒以内に分けるか、端末側で裏で動かして結果をファイルで受け取ってください。 - JSON の本文は 32 MB までです。大きなファイルは
fs/pushとfs/pullを使ってください。
ツール
端末で使えるツールは、GET /api/handlers/{id} の tools に出ます。/cmd の name にツール名、params に引数を入れて呼びます。
Windows・Mac のアプリ
| ツール | 主な引数 | 内容 |
|---|---|---|
desktop.screenshot | display, region | 画面を PNG で返します(pngBase64・width・height) |
desktop.mouse.move | x, y, durationMs | マウスを動かします |
desktop.mouse.click | x, y, button, clicks | クリックします |
desktop.mouse.scroll | clicks, x, y | スクロールします |
desktop.keyboard.type | text | 文字を入力します |
desktop.keyboard.press | keys | キーを押します。"enter" や ["ctrl","c"] |
desktop.clipboard.read / write | text | クリップボードを読む・書く |
desktop.exec | cmd, cwd, timeoutMs, env | コマンドを実行します |
desktop.fs.read / write / stat | path ほか | ファイルの読み書きと情報(stat は sha256 も返せます) |
desktop.window.list / focus | title | ウィンドウの一覧と切り替え |
desktop.screen.info | — | 画面の大きさ・倍率・ディスプレイの数 |
desktop.locateImage | template, confidence | 画面の中から画像(PNG の base64)を探し、位置を返します |
desktop.system.info | includePublicIp, includeGpu | OS・CPU・メモリなど |
desktop.permissions.check | — | Mac で、入力と画面収録の許可が効いているか |
desktop.execはシェルを通しません。パイプや&&を使うときは、["bash","-lc","…"]や["powershell","-Command","…"]のようにシェルを明示してください。- マウス・キーボード・画面の操作は、1 台につき 1 つずつ順に実行されます。
Chrome 拡張
| ツール | 主な引数 | 内容 |
|---|---|---|
screenshot | tabId, format, fullPage, transferMode | タブを撮ります |
getDom | selector, maxBytes | ページの HTML を取ります |
click / type / pressKey | selector ほか | 要素を押す・入力する・キーを送る |
scroll / waitForSelector | selector, timeoutMs | スクロールする・要素が出るのを待つ |
navigate | url | ページを開きます |
executeJs | code, world, timeoutMs | ページで JavaScript の式を実行し、値を返します |
tabs.* / windows.* / tabGroups.* | — | タブとウィンドウの一覧・作成・切り替えなど |
bookmarks.* / history.* / downloads.* / cookies.* | — | ブックマーク・履歴・ダウンロード・Cookie |
clipboard.read / write, systemInfo | — | クリップボードとブラウザの環境 |
- 操作の対象は、最後に使ったウィンドウで表示中のタブです。
- 拡張 0.9.2 以降は、ページを扱うツール(
screenshot・getDom・click・type・pressKey・scroll・waitForSelector・navigate・executeJs)にtabIdを渡すと、そのタブを前面に出さずに操作します。人が別のタブを使っていても画面は切り替わりません。tabIdはtabs.listで調べるか、tabs.createにactive: falseを付けて自分用のタブを作ってください。tabs.activateは人の画面を奪うので、見せたいときだけ使います。0.9.2 より前の拡張はtabIdを無視して前のタブを操作してしまうため、ブリッジが501 client-too-oldで断ります。 - 操作できるのはページのいちばん外側の枠だけです。ほかのサイトの iframe の中、
chrome://のページ、拡張機能のページ、PDF は操作できません。 screenshotなどで画像を受け取るときはtransferMode: "base64"を指定してください。executeJsの既定(world: "DEBUGGER")では、Chrome の上部に「デバッグ中」の帯が出ます。
記録と安全装置
- 監査ログ。送った命令は、誰が・いつ・どの端末に・何を(引数を含めて)送ったかが記録されます。結果の中身は記録しません。8KB を超える引数は、先頭 2KB と長さ・SHA-256 だけを記録します。パスワードなどの秘密は引数に入れないでください。記録は
GET /api/handlers/{id}/auditで見られます。 - 端末の停止。管理者やテナント管理者が端末を停止すると、その端末はすぐに切断され、再開されるまでつながりません。そのあいだの命令は
409になります。 - 緊急停止。管理者はすべての端末を一度に止められます。止まっているあいだは、どの端末にも命令は届きません。
- SSH の連続実行を止める。ループの中の ssh や、同じ相手への繰り返しなど、SSH を大量に試すコマンドは実行前に止めて
422を返します。 - 同時操作の知らせ。ほかのセッションが同じ端末を操作していると、応答に
contentionが付きます。
AI エージェントから使う
Claude Code などの AI エージェントに使わせるときは、トークンを環境変数で渡し、使い方をプロジェクトの説明(CLAUDE.md など)に書いておきます。例:
## CC Bridge
- PC の操作は CC Bridge の API で行う。ベース URL は $CC_BRIDGE_URL、
認証は "Authorization: Bearer $CC_BRIDGE_TOKEN"。
- 操作できる端末は GET /api/handlers。端末ごとに使えるツールは tools に出る。
- 命令は POST /api/handlers/<端末ID>/cmd に {"name": "<ツール名>", "params": {...}}。
- X-Session ヘッダーに作業名を付ける(同じトークンの別セッションと見分けるため)。
- パスワードなどの秘密は引数に入れない(引数は監査ログに残る)。
- 応答に contention が付いたら、ほかの人も同じ端末を操作している。画面操作は控える。プログラムから呼ぶ
JavaScript(Node.js 18 以降):
const res = await fetch(`${process.env.CC_BRIDGE_URL}/api/handlers/${id}/cmd`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CC_BRIDGE_TOKEN}`,
'Content-Type': 'application/json',
'X-Session': 'nightly-report', // 監査ログで自分の作業を見分ける名前
},
body: JSON.stringify({
name: 'desktop.exec',
params: { cmd: ['git', 'status', '--short'], cwd: 'C:/work/app', timeoutMs: 30000 },
}),
});
const { ok, data, error } = await res.json();Python(標準ライブラリだけ):
import json, os, urllib.request
req = urllib.request.Request(
f"{os.environ['CC_BRIDGE_URL']}/api/handlers/{hid}/cmd",
data=json.dumps({"name": "desktop.screenshot", "params": {}}).encode(),
headers={
"Authorization": f"Bearer {os.environ['CC_BRIDGE_TOKEN']}",
"Content-Type": "application/json",
},
)
with urllib.request.urlopen(req, timeout=90) as r:
shot = json.load(r)["data"] # pngBase64, width, height独自の端末をつなぐ
配布しているアプリや拡張のほかに、自分で作ったプログラムを端末(ハンドラー)としてつなぐこともできます。
1. 接続コードで登録する
POST /device/code
{"handlerType":"my-handler","handlerName":"検査ラインの PC","os":"linux"}
→ {"device_code":"…","user_code":"ABCD-EFGH",
"verification_uri":"https://cc-bridge.elc-gateway.com/activate","expires_in":600,"interval":3}user_code を人に見せ、コンソールか /activate で承認してもらいます。そのあいだ interval 秒ごとに次を呼び、承認されたらトークンを受け取ります。コードの期限は 10 分です。
POST /device/token
{"device_code":"…"}
→ {"status":"pending","interval":3}
→ {"status":"approved","handler_token":"cch_…","handler_id":"hdl_…","handler_type":"my-handler"}2. WebSocket でつなぐ
つないだら、まず自分の情報(handler-manifest)を送ります。命令(cmd)が届いたら、同じ cmdId で結果(result)を返します。
wss://cc-bridge.elc-gateway.com/ws?token=cch_…&handlerType=my-handler&handlerVersion=1.0.0
→ {"type":"handler-manifest","handlerType":"my-handler","handlerVersion":"1.0.0",
"os":"linux","hostname":"line3-pc","tools":["my.hello"]}
← {"type":"cmd","cmdId":"c_…","name":"my.hello","params":{"to":"world"}}
→ {"type":"result","cmdId":"c_…","ok":true,"data":{"message":"hello, world"}}
→ {"type":"result","cmdId":"c_…","ok":false,"error":"理由"}| 切断コード | 意味 | 端末がすること |
|---|---|---|
| 4401 | トークンが無効 | トークンを消し、登録し直します |
| 4403 | 停止中(端末の停止・緊急停止) | トークンは残し、間をあけてつなぎ直します |
| 4000 | ペアリング解除 | 登録し直します |
- ブリッジは 25 秒ごとに WebSocket の ping を送ります。切れたら、1 秒から 30 秒まで間隔を延ばしながらつなぎ直してください。
- 新しい版があると
{"type":"update-available","version":"…"}が届きます。無視してもかまいません。