Gateway プロトコル(WebSocket)

Gateway WS プロトコルは、OpenClaw の統合されたコントロールプレーン兼ノードトランスポートです。すべてのクライアント(CLI、Web UI、macOS アプリ、iOS/Android ノード、ヘッドレスノード)が WebSocket で接続し、ハンドシェイク時にロールスコープを宣言します。

トランスポート

  • WebSocket、テキストフレームで JSON ペイロード。
  • 最初のフレームは connect リクエストでなければなりません。

ハンドシェイク(connect)

Gateway → クライアント(接続前チャレンジ):

{
  "type": "event",
  "event": "connect.challenge",
  "payload": { "nonce": "…", "ts": 1737264000000 }
}

クライアント → Gateway:

{
  "type": "req",
  "id": "…",
  "method": "connect",
  "params": {
    "minProtocol": 3,
    "maxProtocol": 3,
    "client": {
      "id": "cli",
      "version": "1.2.3",
      "platform": "macos",
      "mode": "operator"
    },
    "role": "operator",
    "scopes": ["operator.read", "operator.write"],
    "caps": [],
    "commands": [],
    "permissions": {},
    "auth": { "token": "…" },
    "locale": "en-US",
    "userAgent": "openclaw-cli/1.2.3",
    "device": {
      "id": "device_fingerprint",
      "publicKey": "…",
      "signature": "…",
      "signedAt": 1737264000000,
      "nonce": "…"
    }
  }
}

Gateway → クライアント:

{
  "type": "res",
  "id": "…",
  "ok": true,
  "payload": { "type": "hello-ok", "protocol": 3, "policy": { "tickIntervalMs": 15000 } }
}

デバイストークンが発行された場合、hello-ok には以下も含まれます:

{
  "auth": {
    "deviceToken": "…",
    "role": "operator",
    "scopes": ["operator.read", "operator.write"]
  }
}

ノードの例

{
  "type": "req",
  "id": "…",
  "method": "connect",
  "params": {
    "minProtocol": 3,
    "maxProtocol": 3,
    "client": {
      "id": "ios-node",
      "version": "1.2.3",
      "platform": "ios",
      "mode": "node"
    },
    "role": "node",
    "scopes": [],
    "caps": ["camera", "canvas", "screen", "location", "voice"],
    "commands": ["camera.snap", "canvas.navigate", "screen.record", "location.get"],
    "permissions": { "camera.capture": true, "screen.record": false },
    "auth": { "token": "…" },
    "locale": "en-US",
    "userAgent": "openclaw-ios/1.2.3",
    "device": {
      "id": "device_fingerprint",
      "publicKey": "…",
      "signature": "…",
      "signedAt": 1737264000000,
      "nonce": "…"
    }
  }
}

フレーミング

  • リクエスト{type:"req", id, method, params}
  • レスポンス{type:"res", id, ok, payload|error}
  • イベント{type:"event", event, payload, seq?, stateVersion?}

副作用のあるメソッドには冪等性キーが必要です(スキーマを参照)。

ロールとスコープ

ロール

  • operator = コントロールプレーンクライアント(CLI/UI/自動化)。
  • node = ケイパビリティホスト(カメラ/画面/キャンバス/system.run)。

スコープ(operator)

主なスコープ:

  • operator.read
  • operator.write
  • operator.admin
  • operator.approvals
  • operator.pairing

メソッドスコープは最初のゲートにすぎません。chat.send 経由で到達する一部のスラッシュコマンドは、その上にさらに厳密なコマンドレベルのチェックを適用します。たとえば、永続的な /config set/config unset の書き込みには operator.admin が必要です。

Caps/commands/permissions(node)

ノードは接続時にケイパビリティのクレームを宣言します:

  • caps:上位レベルのケイパビリティカテゴリ。
  • commands:invoke 用のコマンド許可リスト。
  • permissions:きめ細かなトグル(例:screen.recordcamera.capture)。

Gateway はこれらをクレームとして扱い、サーバーサイドの許可リストで強制します。

プレゼンス

  • system-presence はデバイスアイデンティティをキーとするエントリを返します。
  • プレゼンスエントリには deviceIdrolesscopes が含まれ、operatornode の両方で接続している場合でも、UI がデバイスごとに1行で表示できるようになっています。

ノードヘルパーメソッド

  • ノードは skills.bins を呼び出して、自動許可チェック用のスキル実行ファイルの現在のリストを取得できます。

オペレーターヘルパーメソッド

  • オペレーターは tools.catalogoperator.read)を呼び出して、エージェントのランタイムツールカタログを取得できます。レスポンスにはグループ化されたツールと出所メタデータが含まれます:
    • sourcecore または plugin
    • pluginIdsource="plugin" の場合のプラグインオーナー
    • optional:プラグインツールがオプションかどうか

実行承認

  • 実行リクエストに承認が必要な場合、Gateway は exec.approval.requested をブロードキャストします。
  • オペレータークライアントは exec.approval.resolve を呼び出して解決します(operator.approvals スコープが必要)。
  • host=node の場合、exec.approval.request には systemRunPlan(正規の argv/cwd/rawCommand/セッションメタデータ)を含める必要があります。systemRunPlan が欠けているリクエストは拒否されます。

バージョニング

  • PROTOCOL_VERSIONsrc/gateway/protocol/schema.ts に定義されています。
  • クライアントは minProtocol + maxProtocol を送信し、サーバーが不一致を拒否します。
  • スキーマとモデルは TypeBox 定義から生成されます:
    • pnpm protocol:gen
    • pnpm protocol:gen:swift
    • pnpm protocol:check

認証

  • OPENCLAW_GATEWAY_TOKEN(または --token)が設定されている場合、connect.params.auth.token が一致しなければソケットが閉じられます。
  • ペアリング後、Gateway は接続ロール + スコープにスコープされたデバイストークンを発行します。hello-ok.auth.deviceToken で返され、クライアントは次回の接続のために永続化する必要があります。
  • デバイストークンは device.token.rotatedevice.token.revoke でローテーション/失効できます(operator.pairing スコープが必要)。
  • 認証失敗には error.details.code とリカバリーヒントが含まれます:
    • error.details.canRetryWithDeviceToken(boolean)
    • error.details.recommendedNextStepretry_with_device_tokenupdate_auth_configurationupdate_auth_credentialswait_then_retryreview_auth_configuration
  • AUTH_TOKEN_MISMATCH に対するクライアントの動作:
    • 信頼済みクライアントはキャッシュされたデバイストークンで1回の制限付きリトライを試みることができます。
    • そのリトライも失敗した場合、自動再接続ループを停止し、オペレーターに操作ガイダンスを表示してください。

デバイスアイデンティティとペアリング

  • ノードはキーペアのフィンガープリントから導出された安定したデバイスアイデンティティ(device.id)を含める必要があります。
  • Gateway はデバイス + ロールごとにトークンを発行します。
  • ローカル自動承認が有効でない限り、新しいデバイス ID にはペアリング承認が必要です。
  • ローカル接続にはループバックと Gateway ホスト自体の Tailnet アドレスが含まれます(同一ホスト Tailnet バインドでも自動承認が可能です)。
  • すべての WS クライアントは connect 時に device アイデンティティを含める必要があります(operator + node)。 コントロール UI は以下のモードでのみ省略できます:
    • gateway.controlUi.allowInsecureAuth=true:localhost 限定の非セキュア HTTP 互換。
    • gateway.controlUi.dangerouslyDisableDeviceAuth=true(緊急用、深刻なセキュリティ低下)。
  • すべての接続はサーバー提供の connect.challenge nonce に署名する必要があります。

デバイス認証移行の診断

チャレンジ署名以前の動作を使用するレガシークライアントでは、connecterror.details.codeDEVICE_AUTH_* の詳細コードと安定した error.details.reason を返すようになりました。

よくある移行エラー:

メッセージdetails.codedetails.reason意味
device nonce requiredDEVICE_AUTH_NONCE_REQUIREDdevice-nonce-missingクライアントが device.nonce を省略(または空)。
device nonce mismatchDEVICE_AUTH_NONCE_MISMATCHdevice-nonce-mismatch古い/誤った nonce で署名。
device signature invalidDEVICE_AUTH_SIGNATURE_INVALIDdevice-signature署名ペイロードが v2 ペイロードと不一致。
device signature expiredDEVICE_AUTH_SIGNATURE_EXPIREDdevice-signature-stale署名タイムスタンプが許容範囲外。
device identity mismatchDEVICE_AUTH_DEVICE_ID_MISMATCHdevice-id-mismatchdevice.id が公開鍵フィンガープリントと不一致。
device public key invalidDEVICE_AUTH_PUBLIC_KEY_INVALIDdevice-public-key公開鍵のフォーマット/正規化に失敗。

移行の目標:

  • connect.challenge を常に待機する。
  • サーバー nonce を含む v2 ペイロードに署名する。
  • 同じチャレンジ nonce を connect.params.device.nonce で送信する。
  • 推奨署名ペイロードは v3。デバイス/クライアント/ロール/スコープ/トークン/nonce フィールドに加え、platformdeviceFamily もバインドされます。
  • レガシーの v2 署名は互換性のために引き続き受け付けられますが、ペアリング済みデバイスのメタデータピニングが再接続時のコマンドポリシーを制御します。

TLS + ピニング

  • WS 接続では TLS がサポートされています。
  • クライアントはオプションで Gateway 証明書のフィンガープリントをピニングできます(gateway.tls の設定および gateway.remote.tlsFingerprint または CLI の --tls-fingerprint を参照)。

スコープ

このプロトコルは完全な Gateway API(ステータス、チャネル、モデル、チャット、エージェント、セッション、ノード、承認など)を公開します。正確なサーフェスは src/gateway/protocol/schema.ts の TypeBox スキーマで定義されています。