通信方式(トランスポート)
- WebSocket を使用し、テキストフレーム内に JSON ペイロードを含めます。
- 最初のフレームは 必ず
connectリクエストである必要があります。
ハンドシェイク (connect)
ゲートウェイ → クライアント (接続前チャレンジ):hello-ok には以下も含まれます:
ノードの例
フレーム構造
- リクエスト (Request):
{type:"req", id, method, params} - レスポンス (Response):
{type:"res", id, ok, payload|error} - イベント (Event):
{type:"event", event, payload, seq?, stateVersion?}
ロールとスコープ
ロール (Roles)
operator: コントロールプレーンクライアント (CLI, UI, 自動化ツールなど)。node: 機能(Capabilities)を提供するホスト (カメラ, 画面, Canvas, system.run など)。
スコープ (Scopes - operator 用)
一般的なスコープ例:operator.readoperator.writeoperator.adminoperator.approvalsoperator.pairing
chat.send を介して実行される一部のスラッシュコマンドでは、さらに厳格なコマンドレベルのチェックが適用されます。例えば、永続的な /config set や /config unset の実行には operator.admin スコープが必要です。
機能・コマンド・権限 (Caps/commands/permissions - node 用)
ノードは接続時に、自身が提供可能な機能の宣言(クレーム)を行います:caps: 大まかな機能カテゴリ。commands: 外部から呼び出し可能なコマンドの許可リスト。permissions: 詳細なオン/オフ設定 (例:screen.record,camera.capture)。
プレゼンス (Presence)
system-presenceメソッドは、デバイスのアイデンティティをキーとしたエントリを返します。- プレゼンスエントリには
deviceId,roles,scopesが含まれるため、同じデバイスが operator と node の両方として接続していても、UI 上では 1 つの行として集約して表示できます。
ノード用ヘルパーメソッド
- ノードは
skills.binsを呼び出すことで、自動許可チェックに使用する現在のスキル実行ファイルのリストを取得できます。
オペレーター用ヘルパーメソッド
- オペレーターは
tools.catalog(operator.read) を呼び出すことで、特定のエージェントの実行時ツールカタログを取得できます。レスポンスには、グループ化されたツール情報と由来(provenance)メタデータが含まれます:source:coreまたはpluginpluginId:source="plugin"の場合のプラグイン提供元optional: プラグインツールがオプション(任意)であるかどうか
実行承認 (Exec approvals)
execリクエストに承認が必要な場合、ゲートウェイはexec.approval.requestedイベントをブロードキャスト(一斉送信)します。- オペレータークライアントは、
exec.approval.resolveを呼び出すことでこれを解決します(operator.approvalsスコープが必要です)。 host=nodeの場合、exec.approval.requestにはsystemRunPlan(正規化されたargv,cwd,rawCommand, セッションメタデータ)が含まれている必要があります。systemRunPlanが欠落しているリクエストは拒否されます。
バージョン管理
PROTOCOL_VERSIONはsrc/gateway/protocol/schema.tsで定義されています。- クライアントは接続時に
minProtocolとmaxProtocolを送信し、サーバーは不一致がある場合に拒否します。 - スキーマとモデルは、TypeBox の定義から自動生成されます:
pnpm protocol:genpnpm protocol:gen:swiftpnpm protocol:check
認証 (Auth)
OPENCLAW_GATEWAY_TOKEN(または--token) が設定されている場合、connect.params.auth.tokenが一致しなければソケットは即座に閉じられます。- ペアリング成功後、ゲートウェイは接続時のロールとスコープに制限された デバイストークン を発行します。これは
hello-ok.auth.deviceTokenとして返され、クライアント側で保存して次回の接続時に再利用する必要があります。 - デバイストークンは
device.token.rotateおよびdevice.token.revokeメソッドで更新・取り消しが可能です(operator.pairingスコープが必要です)。
デバイスアイデンティティとペアリング
- ノードは、キーペアのフィンガープリントから派生した、固定のデバイスアイデンティティ (
device.id) を含める必要があります。 - ゲートウェイは、デバイスとロールの組み合わせごとにトークンを発行します。
- 未登録のデバイス ID からの接続にはペアリング承認が必要ですが、ローカル環境での自動承認設定が有効な場合はスキップされます。
- ローカル接続には、ループバックおよびゲートウェイホスト自身の Tailnet アドレスが含まれます(そのため、同じホスト内であれば Tailnet バインド経由でも自動承認が可能です)。
- すべての WebSocket クライアント(operator および node)は、
connect時にdevice情報を提示する必要があります。コントロール UI においては、緊急時(break-glass)の利用目的でgateway.controlUi.dangerouslyDisableDeviceAuthが有効な場合にのみ省略可能です。 - すべての接続において、サーバーから提供された
connect.challengeノンス(一時的な数値)への署名が必要です。
デバイス認証の移行診断
チャレンジベースの署名に対応していない古いクライアントに対して、connect 時に error.details.code 配下で DEVICE_AUTH_* 形式の詳細コードと、固定の error.details.reason を返すようになりました。
よくある移行時の失敗例:
| メッセージ | details.code | details.reason | 意味 |
|---|---|---|---|
device nonce required | DEVICE_AUTH_NONCE_REQUIRED | device-nonce-missing | クライアントが device.nonce を省略した(または空で送った)。 |
device nonce mismatch | DEVICE_AUTH_NONCE_MISMATCH | device-nonce-mismatch | 古い、あるいは誤ったノンスで署名した。 |
device signature invalid | DEVICE_AUTH_SIGNATURE_INVALID | device-signature | 署名対象のペイロードが v2 の形式と一致しない。 |
device signature expired | DEVICE_AUTH_SIGNATURE_EXPIRED | device-signature-stale | 署名時刻が許容範囲外(古すぎる)。 |
device identity mismatch | DEVICE_AUTH_DEVICE_ID_MISMATCH | device-id-mismatch | device.id が公開鍵のフィンガープリントと一致しない。 |
device public key invalid | DEVICE_AUTH_PUBLIC_KEY_INVALID | device-public-key | 公開鍵のフォーマットや正規化に失敗した。 |
- 常に
connect.challengeイベントを待機する。 - サーバーからのノンスを含む v2 ペイロードに対して署名する。
connect.params.device.nonceに同じノンスを含めて送信する。- 推奨される署名ペイロードは
v3です。これはデバイス/クライアント/ロール/スコープ/トークン/ノンスに加え、platformとdeviceFamilyも紐付けます。 - 従来の
v2署名も互換性のために受け入れられますが、再接続時のコマンドポリシー制御のために、ペアリング済みデバイスのメタデータの固定(pinning)が引き続き適用されます。
TLS とピン留め (Pinning)
- WebSocket 接続における TLS をサポートしています。
- クライアントは、オプションでゲートウェイ証明書のフィンガープリントを固定できます(
gateway.tls構成、gateway.remote.tlsFingerprint、または CLI の--tls-fingerprintを参照)。
対象範囲 (Scope)
本プロトコルは、ゲートウェイの全 API(ステータス、チャネル、モデル、チャット、エージェント、セッション、ノード、承認など)を公開します。具体的なインターフェース面は、src/gateway/protocol/schema.ts にある TypeBox スキーマによって定義されます。