# Protocol Implementation

GoClaw's gateway serves HTTP REST and a custom WebSocket envelope on `server.port`, with the webhook listener on `gateway.ingress.port` when one is set. This page compares that protocol design with OpenClaw's, which also serves HTTP and WebSocket but as JSON-RPC.

## Network Topology

```mermaid
flowchart TD
    subgraph OC["OpenClaw"]
        direction LR
        OC_GW["<b>Gateway (:18789)</b><br/>• HTTP REST<br/>• WebSocket JSON-RPC<br/>• SSE (streaming)<br/>• TLS (optional)<br/>• Tailscale Serve/Funnel"]
        OC_MED["<b>Media Server &amp; Discovery</b><br/>• GET /media/:id (TTL auto-cleanup)<br/>• mDNS/Bonjour local discovery"]
        OC_AUTH["<b>Bind &amp; Auth</b><br/>• Bind: loopback / lan / tailnet / auto / custom<br/>• Auth: token / password / device-pairing / trusted-proxy"]
    end

    subgraph GC["GoClaw"]
        direction LR
        GC_GW["<b>Gateway (server.port, :8080)</b><br/>• HTTP REST<br/>• WebSocket (custom)<br/>• SSE (chat, logs, doctor)<br/>• OpenAI-compat API<br/>• App API<br/>• Static Web UI"]
        GC_WH["<b>Webhook Listener &amp; Ingress</b><br/>• gateway.ingress.port (else main port)<br/>• POST /goclaw/hook/&lt;type&gt;[/&lt;key&gt;]<br/>• /hook/[&lt;slug&gt;/]msteams, facebook, …<br/>• ngrok tunnel (gateway.ingress.type: ngrok)"]
        GC_SEC["<b>Bind, Auth &amp; Security</b><br/>• Bind: loopback / lan (0.0.0.0) / IP<br/>• Auth: token / rate-limit / trust-proxy / WS auth<br/>• Security: SSRF protection / IP allowlist / access log"]
    end
```

## WebSocket Protocol Comparison

| Aspect | OpenClaw | GoClaw |
|--------|----------|---------|
| Library | `ws` (Node.js) | `nhooyr.io/websocket` (Go) |
| Path | Upgrade on any path | `/gateway` |
| Protocol | JSON-RPC v3 (`req`/`res`/`event`) | Custom envelope (`inbound`/`outbound`/`error`/`canvas`) |
| Handshake | `ConnectParams` → `HelloOk` with features, snapshot, auth | Token auth on upgrade |
| Protocol version | `PROTOCOL_VERSION = 3` | None |
| Methods | 40+ RPC methods | Implicit — `kind` field determines action |
| Events | 15+ event types | `outbound_chunk` streaming |
| Streaming | `chat` event with chunks | `outbound_chunk` kind |
| Auth | Token/password/device in `ConnectParams` | Gateway token on the upgrade request (`X-GoClaw-Token` or `Bearer` header, `?token=`, or cookie) |
| Bidirectional RPC | Yes | Partial — client `inbound`, server `outbound` |

**OpenClaw WebSocket frame:**
```json
{ "type": "req", "id": "abc123", "method": "chat.send", "params": { "content": "hello" } }
{ "type": "res", "id": "abc123", "ok": true, "payload": { "sessionId": "..." } }
{ "type": "event", "event": "chat", "payload": { "content": "...", "streaming": true } }
```

**GoClaw WebSocket frame:**
```json
{ "id": "uuid", "kind": "inbound", "session_id": "s1", "payload": { "channel": "web", "content": "hello" } }
{ "id": "uuid", "kind": "outbound_chunk", "payload": { "content": "Hel" } }
{ "id": "uuid", "kind": "outbound", "payload": { "content": "Hello! How can I help?" } }
```

---

## REST API Endpoints

### GoClaw Endpoint Summary

| # | Endpoint | Method | Description | Status |
|---|----------|--------|-------------|--------|
| 4.1 | `/gateway` | WS | WebSocket chat + streaming | Done |
| 4.2 | `/api/webhook` | POST | Inbound messages from integrations | Done |
| 4.3 | `/api/logs` | GET | SSE log streaming (real-time) | Done |
| 4.4 | `/api/stats` | GET | Provider, model, sessions, WS count, channels, version | Done |
| 4.5 | `/api/sessions` | GET | List sessions (`id`, `title`, `message_count`, `last_seen`); history is `GET /api/session?id=` | Done |
| 4.6 | `/api/inspect` | GET | Session + memory + paths inspection | Done |
| 4.7 | `/api/memory` | GET | Memory.md + SQLite global + personal records | Done |
| 4.8 | `/api/canvas` | GET | List canvas artifacts (name, size, mod_time) | Done |
| 4.9 | `/api/pairing` | GET/POST | Channel pairing (approve/revoke/update_role) | Done |
| 4.10 | `/api/agents` | GET | **Multi-agent list + bindings + subagent runs** | Done |
| 4.11 | `/api/skills` | GET | **Skills with dependency status, tags, pure_go flag** | Done |
| 4.12 | `/api/cron` | GET/POST | **Cron jobs list + run, enable, disable, reschedule, delete** | Done |
| 4.13 | `/api/hooks` | GET | **Registered hook events + handler counts** | Done |
| 4.14 | `/api/extensions` | GET | **Discovered + active Go extensions** | Done |
| 4.15 | `/api/search` | GET | **Unified memory search (global+personal+archive)** | Done |
| 4.16 | `/api/memory/core?agent=<id>` | GET/POST | **Per-agent core instruction editor** | Done |
| 4.17 | `/api/send` | POST | **Loopback-only channel sender (cron → channel)** | Done |
| 4.18 | `/api/secrets` | GET/POST/DELETE | Secrets vault management | Done |
| 4.19 | `/api/config` | GET/POST | CLI-like config management (get/set/append/remove) | Done |
| 4.20 | `/api/gateway?limit=N` | GET | **Runtime info, ingress, access logs** | Done |
| 4.21 | `/` | GET | Static Web UI | Done |
| 4.22 | `/hook/msteams` (`/hook/<webhook_secret_slug>/msteams`) | POST | MS Teams Bot Framework webhook, on the webhook listener | Done |
| 4.23 | `/health` `/healthz` `/ready` `/readyz` | GET | Health/readiness probes (`status`, `uptime_seconds`) | Done |
| 4.24 | `/v1/chat/completions` | POST | OpenAI-compatible API (stream + non-stream) | Done |
| 4.25 | Auth middleware | — | Token auth on all API/WS routes, health exempt | Done |
| 4.26 | Rate limiting | — | Per-IP token bucket middleware (configurable) | Done |
| 4.27 | `/api/chat` | POST | Web UI chat, reply streamed as SSE | Done |

### Endpoints Comparison (OpenClaw vs GoClaw)

| Endpoint | OpenClaw | GoClaw | Status |
|----------|----------|---------|--------|
| Health probe | `GET /health`, `/healthz` | Same, returns `status` and `uptime_seconds` | Done |
| Chat completions | `POST /v1/chat/completions` | Same + subagent command routing | Done |
| OpenResponses | `POST /v1/responses` | — | **TODO** |
| Tool invoke | `POST /tools/invoke` | — | **TODO** |
| HTTP hooks | `POST /hooks/*` | `POST /goclaw/hook/<type>[/<key>]` | Done |
| Stats | via WS RPC | `GET /api/stats` | Done |
| Sessions | via WS RPC | `GET /api/sessions` (list), `GET /api/session` (history) | Done |
| Memory | via WS RPC | `GET /api/memory` (+ SQLite records) | Done |
| **Search** | — | `GET /api/search` (keyword scoring, multi-source) | **GoClaw only** |
| Canvas | via WS RPC | `GET /api/canvas` | Done |
| Pairing | via WS RPC | `GET/POST /api/pairing` (approve/revoke/update_role) | Done |
| **Agents** | — | `GET /api/agents` (multi-agent + bindings + subagent runs) | **GoClaw only** |
| **Skills** | — | `GET /api/skills` (dep check, tags, pure_go) | **GoClaw only** |
| **Cron** | via WS RPC | `GET/POST /api/cron` (list, run, enable, disable, reschedule, delete) | **GoClaw only** |
| **Hooks** | — | `GET /api/hooks` (events + handlers) | **GoClaw only** |
| **Extensions** | — | `GET /api/extensions` (discovered + active) | **GoClaw only** |
| **Core Inst.** | — | `GET/POST /api/memory/core?agent=<id>` (per-agent) | **GoClaw only** |
| **Send** | — | `POST /api/send` (loopback → channel) | **GoClaw only** |
| Secrets | credential store | `GET/POST/DELETE /api/secrets` | Done |
| Config | via WS RPC | `GET/POST /api/config` (CLI-like operations) | Done |
| **Runtime info** | — | `GET /api/gateway` (ingress, access logs) | **GoClaw only** |
| Log stream | via WS events | `GET /api/logs` (SSE) | Done |
| Control UI | `{basePath}/*` SPA | `GET /` (static) | Done |
| Webhook | via WS RPC | `POST /api/webhook` | Done |
| Media hosting | `GET /media/:id` | `GET /media/<id>` | Done |
| Canvas host | `/__openclaw__/canvas` | `/canvas/<file>`; HTML pages at `/goclaw/view/<slug>` | Done |
| A2UI host | `/__openclaw__/a2ui` | — | **TODO** |
| Avatar | `{basePath}/avatar/*` | — | **TODO** |
| Plugin routes | `/{plugin}/api/*` | — | **TODO** |

---

## Additional Protocols

| Protocol | OpenClaw | GoClaw | Status |
|----------|----------|---------|--------|
| TLS/HTTPS | Optional `gateway.tls.enabled` | — | **TODO** |
| Tailscale Serve | `https://*.ts.net` | — | **TODO** |
| Tailscale Funnel | Public HTTPS tunnel | — | **TODO** |
| mDNS / Bonjour | Local network discovery | — | **TODO** |
| Media server | Separate HTTP server | `/media/<id>` on the main port | Done |
| SSE streaming | Chat + responses | `/api/chat`, `/v1/chat/completions` (`stream: true`), `/api/app/events`, `/api/doctor?stream=1`, `/api/logs` | Done |
| Bot Framework | — | `/hook/msteams` or `/hook/<webhook_secret_slug>/msteams` (Teams), on the webhook listener | Done |
| ngrok tunneling | — | Tunnel to the webhook listener when `gateway.ingress.type: ngrok` (IP allowlist) | Done |

---

## Gateway Auth & Security

| Feature | OpenClaw | GoClaw | Status |
|---------|----------|---------|--------|
| No auth (loopback) | Default | Not offered: the gateway does not start without `gateway.auth.token`, on any bind | — |
| Token auth | `X-OpenClaw-Token` | `X-GoClaw-Token` / `Bearer` header, `?token=`, or cookie | Done |
| **WebSocket auth** | ConnectParams | Token on the upgrade request (header, `?token=` or cookie), reject unauthorized | Done |
| Password auth | `gateway.auth.password` | — | **TODO** |
| Device pairing | Public key + signature | — | **TODO** |
| Trusted proxy | Tailscale proxy headers | `gateway.rate_limit.trust_proxy` (X-Forwarded-For) | Done |
| Rate limiting | `AuthRateLimiter` | Per-IP token bucket, configurable req/min; requests with the token are exempt | Done |
| **Ingress IP allowlist** | — | ngrok + M365 presets + CIDR | **GoClaw only** |
| **Access logging** | — | Timestamp, IP, method, path, status, duration, host | **GoClaw only** |
| **SSRF protection** | — | DNS-level private IP blocking | **GoClaw only** |
| Remote connect | `OPENCLAW_GATEWAY_URL` | — | **TODO** |

---

## Gateway Source Files

Routes are registered in `cmd/gateway/startup.go` (`registerAPIRoutes`) and
`cmd/gateway/main.go` (the Web UI's files, `/canvas/`, `/uploads/` and the
middleware chain), and implemented under `internal/gateway`. The route list,
with each route's request and response, is in
[Gateway Endpoints](../api-reference/gateway_endpoints.md).

---

## OpenClaw vs GoClaw Protocol Comparison

| Aspect | OpenClaw | GoClaw |
|--------|----------|---------|
| **WebSocket protocol** | JSON-RPC v3 (40+ methods) | Custom envelope (simple) |
| **REST endpoints** | ~15 (most via WS RPC) | **A REST endpoint for each feature** |
| **GoClaw only endpoints** | — | agents, skills, cron, hooks, extensions, search, memory/core, send, gateway (runtime info) |
| **Auth** | token/password/device-pairing | token + WebSocket auth + rate limit + trust proxy |
| **Network security** | — | **SSRF + IP allowlist + access logging** |
| **Tunneling** | Tailscale Serve/Funnel | **ngrok tunnel to the webhook listener** |
| **API style** | Mostly WS-based RPC | **REST-first** (each feature has its own endpoint) |

