--- summary: "WebSocket gateway architecture, components, and client flows" read_when: - Working on gateway protocol, clients, or transports title: "Gateway Architecture" --- # Gateway architecture Last updated: 2026-01-22 ## Overview - A single long‑lived **Gateway** owns all messaging surfaces (WhatsApp via Baileys, Telegram via grammY, Slack, Discord, Signal, iMessage, WebChat). - Control-plane clients (macOS app, CLI, web UI, automations) connect to the Gateway over **WebSocket** on the configured bind host (default `127.0.0.1:18789`). - **Nodes** (macOS/iOS/Android/headless) also connect over **WebSocket**, but declare `role: node` with explicit caps/commands. - One Gateway per host; it is the only place that opens a WhatsApp session. - A **canvas host** (default `18793`) serves agent‑editable HTML and A2UI. ## Components and flows ### Gateway (daemon) - Maintains provider connections. - Exposes a typed WS API (requests, responses, server‑push events). - Validates inbound frames against JSON Schema. - Emits events like `agent`, `chat`, `presence`, `health`, `heartbeat`, `cron`. ### Clients (mac app / CLI / web admin) - 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) - Connect to the **same WS server** with `role: node`. - Provide a device identity in `connect`; pairing is **device‑based** (role `node`) and approval lives in the device pairing store. - Expose commands like `canvas.*`, `camera.*`, `screen.record`, `location.get`. Protocol details: - [Gateway protocol](/gateway/protocol) ### WebChat - 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. ## Connection lifecycle (single client)
```mermaid
%%{init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#ffffff',
'primaryTextColor': '#000000',
'primaryBorderColor': '#000000',
'lineColor': '#000000',
'secondaryColor': '#f9f9fb',
'tertiaryColor': '#ffffff',
'clusterBkg': '#f9f9fb',
'clusterBorder': '#000000',
'nodeBorder': '#000000',
'mainBkg': '#ffffff',
'edgeLabelBackground': '#ffffff'
}
}}%%
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
snapshot: presence + health
Gateway-->>Client: event:presence
Gateway-->>Client: event:tick
Client->>Gateway: req:agent
Gateway-->>Client: res:agent
ack {runId, status:"accepted"}
Gateway-->>Client: event:agent
(streaming)
Gateway-->>Client: res:agent
final {runId, status, summary}
```