Gatewayアーキテクチャ
最終更新: 2026-01-22
概要
- 単一の常駐Gatewayがすべてのメッセージングサーフェス(Baileys経由のWhatsApp、grammY経由のTelegram、Slack、Discord、Signal、iMessage、WebChat)を管理します。
- コントロールプレーンクライアント(macOSアプリ、CLI、Web UI、自動化)は、設定されたバインドホスト(デフォルト
127.0.0.1:18789)上のWebSocketでGatewayに接続します。 - ノード(macOS/iOS/Android/ヘッドレス)もWebSocketで接続しますが、
role: nodeを宣言し、明示的なcaps/commandsを持ちます。 - ホストごとにGatewayは1つだけ。WhatsAppセッションを開くのはGatewayだけです。
- CanvasホストはGateway HTTPサーバーの以下のパスで提供されます:
/__openclaw__/canvas/(エージェント編集可能なHTML/CSS/JS)/__openclaw__/a2ui/(A2UIホスト) Gatewayと同じポート(デフォルト18789)を使用します。
コンポーネントとフロー
Gateway(デーモン)
- プロバイダー接続を維持します。
- 型付きWS API(リクエスト、レスポンス、サーバープッシュイベント)を公開します。
- 受信フレームをJSON Schemaに対して検証します。
agent、chat、presence、health、heartbeat、cronなどのイベントを発行します。
クライアント(macアプリ / CLI / Web管理画面)
- クライアントごとに1つのWS接続。
- リクエスト(
health、status、send、agent、system-presence)を送信。 - イベント(
tick、agent、presence、shutdown)を購読。
ノード(macOS / iOS / Android / ヘッドレス)
- 同じWSサーバーに
role: nodeで接続。 connectでデバイスIDを提供。ペアリングはデバイスベース(rolenode)で、承認はデバイスペアリングストアに保持されます。canvas.*、camera.*、screen.record、location.getなどのコマンドを公開。
プロトコルの詳細:
WebChat
- Gateway WS APIを使用してチャット履歴と送信を行う静的UI。
- リモート構成では、他のクライアントと同じSSH/Tailscaleトンネルを通じて接続します。
接続ライフサイクル(単一クライアント)
sequenceDiagram
participant Client
participant Gateway
Client->>Gateway: req:connect
Gateway-->>Client: res (ok)
Note right of Gateway: or res error + close
Note left of Client: payload=hello-ok<br>snapshot: presence + health
Gateway-->>Client: event:presence
Gateway-->>Client: event:tick
Client->>Gateway: req:agent
Gateway-->>Client: res:agent<br>ack {runId, status:"accepted"}
Gateway-->>Client: event:agent<br>(streaming)
Gateway-->>Client: res:agent<br>final {runId, status, summary}
ワイヤプロトコル(概要)
- トランスポート: WebSocket、JSONペイロードのテキストフレーム。
- 最初のフレームは必ず
connectでなければなりません。 - ハンドシェイク後:
- リクエスト:
{type:"req", id, method, params}→{type:"res", id, ok, payload|error} - イベント:
{type:"event", event, payload, seq?, stateVersion?}
- リクエスト:
OPENCLAW_GATEWAY_TOKEN(または--token)が設定されている場合、connect.params.auth.tokenが一致しないとソケットが閉じられます。- 副作用のあるメソッド(
send、agent)には安全にリトライするための冪等性キーが必要です。サーバーは短命の重複排除キャッシュを保持しています。 - ノードは
connectでrole: "node"に加えてcaps/commands/permissionsを含める必要があります。
ペアリングとローカル信頼
- すべてのWSクライアント(オペレーター+ノード)は
connect時にデバイスIDを含めます。 - 新しいデバイスIDはペアリング承認が必要です。Gatewayは以降の接続用にデバイストークンを発行します。
- ローカル接続(ループバックまたはGatewayホスト自身のtailnetアドレス)は、同一ホストのUXを円滑にするため自動承認できます。
- すべての接続は
connect.challengeノンスに署名する必要があります。 - 署名ペイロード
v3はplatform+deviceFamilyもバインドします。Gatewayは再接続時にペアリング済みメタデータを固定し、メタデータ変更時には再ペアリングを要求します。 - 非ローカル接続では明示的な承認が引き続き必要です。
- Gateway認証(
gateway.auth.*)はローカル・リモートを問わずすべての接続に適用されます。
詳細: Gatewayプロトコル、ペアリング、セキュリティ
プロトコルの型定義とコード生成
- TypeBoxスキーマがプロトコルを定義。
- JSON Schemaがそれらのスキーマから生成。
- SwiftモデルがJSON Schemaから生成。
リモートアクセス
-
推奨: TailscaleまたはVPN。
-
代替: SSHトンネル
ssh -N -L 18789:127.0.0.1:18789 user@host -
トンネル経由でも同じハンドシェイク+認証トークンが適用されます。
-
リモート構成ではWSのTLS+オプションのピンニングを有効にできます。
運用のスナップショット
- 起動:
openclaw gateway(フォアグラウンド、標準出力にログ)。 - ヘルスチェック: WS経由の
health(hello-okにも含まれる)。 - 監視: 自動再起動にはlaunchd/systemdを使用。
不変条件
- 1つのGatewayが1ホストにつき1つのBaileysセッションを制御。
- ハンドシェイクは必須。非JSONまたは非connectの最初のフレームは即座に切断。
- イベントはリプレイされません。クライアントはギャップ発生時にリフレッシュが必要。