Kiến trúc Gateway

Cập nhật lần cuối: 22/01/2026

Tổng quan

  • Một Gateway duy nhất chạy lâu dài sẽ quản lý tất cả các kênh nhắn tin (WhatsApp qua Baileys, Telegram qua grammY, Slack, Discord, Signal, iMessage, WebChat).
  • Các client điều khiển (macOS app, CLI, web UI, automation) kết nối tới Gateway qua WebSocket trên địa chỉ bind đã cấu hình (mặc định 127.0.0.1:18789).
  • Node (macOS/iOS/Android/headless) cũng kết nối qua WebSocket, nhưng khai báo role: node với các capability và command cụ thể.
  • Mỗi host chỉ có một Gateway; đây là nơi duy nhất mở WhatsApp session.
  • Một canvas host (mặc định 18793) phục vụ HTML và A2UI có thể chỉnh sửa bởi Agent.

Các thành phần và luồng hoạt động

Gateway (daemon)

  • Duy trì kết nối với các provider.
  • Cung cấp WS API có kiểu dữ liệu rõ ràng (request, response, server-push event).
  • Validate các frame đầu vào theo JSON Schema.
  • Phát ra các event như agent, chat, presence, health, heartbeat, cron.

Client (mac app / CLI / web admin)

  • Mỗi client có một kết nối WS.
  • Gửi request (health, status, send, agent, system-presence).
  • Subscribe các event (tick, agent, presence, shutdown).

Node (macOS / iOS / Android / headless)

  • Kết nối tới cùng WS server với role: node.
  • Cung cấp device identity trong connect; Pairing dựa trên thiết bị (role node) và việc phê duyệt được lưu trong device pairing store.
  • Cung cấp các command như canvas.*, camera.*, screen.record, location.get.

Chi tiết protocol:

WebChat

  • UI tĩnh sử dụng Gateway WS API để lấy lịch sử chat và gửi tin nhắn.
  • Trong các setup từ xa, kết nối qua cùng SSH/Tailscale tunnel như các client khác.

Vòng đời kết nối (single client)

Client                    Gateway
  |                          |
  |---- req:connect -------->|
  |<------ res (ok) ---------|   (hoặc res error + close)
  |   (payload=hello-ok chứa snapshot: presence + health)
  |                          |
  |<------ event:presence ---|
  |<------ event:tick -------|
  |                          |
  |------- req:agent ------->|
  |<------ res:agent --------|   (ack: {runId,status:"accepted"})
  |<------ event:agent ------|   (streaming)
  |<------ res:agent --------|   (final: {runId,status,summary})
  |                          |

Wire protocol (tóm tắt)

  • Transport: WebSocket, text frame với JSON payload.
  • Frame đầu tiên bắt buộc phải là connect.
  • Sau khi handshake:
    • Request: {type:"req", id, method, params}{type:"res", id, ok, payload|error}
    • Event: {type:"event", event, payload, seq?, stateVersion?}
  • Nếu OPENCLAW_GATEWAY_TOKEN (hoặc --token) được set, connect.params.auth.token phải khớp, nếu không socket sẽ đóng.
  • Idempotency key bắt buộc cho các method có side-effect (send, agent) để retry an toàn; server giữ một dedupe cache tạm thời.
  • Node phải include role: "node" cộng với caps/commands/permissions trong connect.

Pairing + local trust

  • Tất cả WS client (operator + node) đều include device identity khi connect.
  • Device ID mới cần được phê duyệt pairing; Gateway sẽ cấp device token cho các lần connect sau.
  • Kết nối local (loopback hoặc địa chỉ tailnet của chính gateway host) có thể được auto-approve để giữ UX mượt mà trên cùng host.
  • Kết nối non-local phải ký connect.challenge nonce và cần phê duyệt rõ ràng.
  • Gateway auth (gateway.auth.*) vẫn áp dụng cho tất cả kết nối, dù local hay remote.

Chi tiết: Gateway protocol, Pairing, Security.

Protocol typing và codegen

  • TypeBox schema định nghĩa protocol.
  • JSON Schema được generate từ các schema đó.
  • Swift model được generate từ JSON Schema.

Remote access

  • Khuyên dùng: Tailscale hoặc VPN.
  • Cách khác: SSH tunnel
    ssh -N -L 18789:127.0.0.1:18789 user@host
  • Cùng handshake + auth token áp dụng qua tunnel.
  • TLS + optional pinning có thể được bật cho WS trong các setup remote.

Operations snapshot

  • Khởi động: openclaw gateway (foreground, log ra stdout).
  • Health check: health qua WS (cũng có trong hello-ok).
  • Giám sát: launchd/systemd để auto-restart.

Các bất biến (invariant)

  • Chỉ có đúng một Gateway điều khiển một Baileys session trên mỗi host.
  • Handshake là bắt buộc; bất kỳ frame đầu tiên nào không phải JSON hoặc không phải connect sẽ bị đóng ngay.
  • Event không được replay; client phải refresh khi có gap.