Files
openclaw/docs/concepts/architecture.md

140 lines
4.8 KiB
Markdown
Raw Normal View History

---
summary: "WebSocket gateway architecture, components, and client flows"
read_when:
- Working on gateway protocol, clients, or transports
title: "Gateway Architecture"
---
2026-01-31 21:13:13 +09:00
2026-01-08 23:06:56 +01:00
# Gateway architecture
2025-12-09 14:41:41 +01:00
2026-01-22 22:02:00 +00:00
Last updated: 2026-01-22
2025-12-09 14:41:41 +01:00
## Overview
2026-01-08 23:06:56 +01:00
- A single longlived **Gateway** owns all messaging surfaces (WhatsApp via
Baileys, Telegram via grammY, Slack, Discord, Signal, iMessage, WebChat).
2026-01-12 04:44:14 +00:00
- Control-plane clients (macOS app, CLI, web UI, automations) connect to the
Gateway over **WebSocket** on the configured bind host (default
2026-01-08 23:06:56 +01:00
`127.0.0.1:18789`).
- **Nodes** (macOS/iOS/Android/headless) also connect over **WebSocket**, but
declare `role: node` with explicit caps/commands.
2026-01-08 23:06:56 +01:00
- One Gateway per host; it is the only place that opens a WhatsApp session.
- The **canvas host** is served by the Gateway HTTP server under:
- `/__openclaw__/canvas/` (agent-editable HTML/CSS/JS)
- `/__openclaw__/a2ui/` (A2UI host)
It uses the same port as the Gateway (default `18789`).
2026-01-05 21:30:19 +01:00
2025-12-09 14:41:41 +01:00
## Components and flows
2026-01-08 23:06:56 +01:00
### Gateway (daemon)
2026-01-31 21:13:13 +09:00
2026-01-08 23:06:56 +01:00
- Maintains provider connections.
- Exposes a typed WS API (requests, responses, serverpush events).
- Validates inbound frames against JSON Schema.
- Emits events like `agent`, `chat`, `presence`, `health`, `heartbeat`, `cron`.
### Clients (mac app / CLI / web admin)
2026-01-31 21:13:13 +09:00
2026-01-08 23:06:56 +01:00
- One WS connection per client.
- Send requests (`health`, `status`, `send`, `agent`, `system-presence`).
- Subscribe to events (`tick`, `agent`, `presence`, `shutdown`).
### Nodes (macOS / iOS / Android / headless)
2026-01-31 21:13:13 +09:00
- Connect to the **same WS server** with `role: node`.
2026-01-22 22:02:00 +00:00
- Provide a device identity in `connect`; pairing is **devicebased** (role `node`) and
approval lives in the device pairing store.
2026-01-08 23:06:56 +01:00
- Expose commands like `canvas.*`, `camera.*`, `screen.record`, `location.get`.
2026-01-12 04:44:14 +00:00
Protocol details:
2026-01-31 21:13:13 +09:00
2026-01-12 04:44:14 +00:00
- [Gateway protocol](/gateway/protocol)
2026-01-08 23:06:56 +01:00
### WebChat
2026-01-31 21:13:13 +09:00
2026-01-08 23:06:56 +01:00
- Static UI that uses the Gateway WS API for chat history and sends.
- In remote setups, connects through the same SSH/Tailscale tunnel as other
clients.
2025-12-09 14:41:41 +01:00
## Connection lifecycle (single client)
2026-01-08 23:06:56 +01:00
```mermaid
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}
2025-12-09 14:41:41 +01:00
```
2026-01-08 23:06:56 +01:00
2025-12-09 14:41:41 +01:00
## Wire protocol (summary)
2026-01-08 23:06:56 +01:00
2025-12-09 14:41:41 +01:00
- Transport: WebSocket, text frames with JSON payloads.
2026-01-08 23:06:56 +01:00
- First frame **must** be `connect`.
- After handshake:
- Requests: `{type:"req", id, method, params}``{type:"res", id, ok, payload|error}`
- Events: `{type:"event", event, payload, seq?, stateVersion?}`
2026-01-30 03:15:10 +01:00
- If `OPENCLAW_GATEWAY_TOKEN` (or `--token`) is set, `connect.params.auth.token`
2026-01-08 23:06:56 +01:00
must match or the socket closes.
- Idempotency keys are required for sideeffecting methods (`send`, `agent`) to
safely retry; the server keeps a shortlived dedupe cache.
- Nodes must include `role: "node"` plus caps/commands/permissions in `connect`.
2025-12-09 14:41:41 +01:00
## Pairing + local trust
- All WS clients (operators + nodes) include a **device identity** on `connect`.
- New device IDs require pairing approval; the Gateway issues a **device token**
for subsequent connects.
- **Local** connects (loopback or the gateway hosts own tailnet address) can be
autoapproved to keep samehost UX smooth.
- All connects must sign the `connect.challenge` nonce.
- Signature payload `v3` also binds `platform` + `deviceFamily`; the gateway
pins paired metadata on reconnect and requires repair pairing for metadata
changes.
- **Nonlocal** connects still require explicit approval.
- Gateway auth (`gateway.auth.*`) still applies to **all** connections, local or
remote.
Details: [Gateway protocol](/gateway/protocol), [Pairing](/channels/pairing),
[Security](/gateway/security).
2026-01-08 23:06:56 +01:00
## Protocol typing and codegen
- TypeBox schemas define the protocol.
- JSON Schema is generated from those schemas.
- Swift models are generated from the JSON Schema.
2025-12-09 14:41:41 +01:00
## Remote access
2026-01-08 23:06:56 +01:00
- Preferred: Tailscale or VPN.
- Alternative: SSH tunnel
2026-01-08 23:06:56 +01:00
```bash
ssh -N -L 18789:127.0.0.1:18789 user@host
```
2026-01-08 23:06:56 +01:00
- The same handshake + auth token apply over the tunnel.
- TLS + optional pinning can be enabled for WS in remote setups.
2025-12-09 14:41:41 +01:00
## Operations snapshot
2026-01-30 03:15:10 +01:00
- Start: `openclaw gateway` (foreground, logs to stdout).
2026-01-08 23:06:56 +01:00
- Health: `health` over WS (also included in `hello-ok`).
- Supervision: launchd/systemd for autorestart.
## Invariants
- Exactly one Gateway controls a single Baileys session per host.
- Handshake is mandatory; any nonJSON or nonconnect first frame is a hard close.
- Events are not replayed; clients must refresh on gaps.