2026-01-12 04:44:14 +00:00
---
2026-04-04 21:24:09 +01:00
summary: "Historical bridge protocol (legacy nodes): TCP JSONL, pairing, scoped RPC"
2026-01-12 04:44:14 +00:00
read_when:
- Building or debugging node clients (iOS/Android/macOS node mode)
- Investigating pairing or bridge auth failures
- Auditing the node surface exposed by the gateway
2026-01-31 16:04:03 -05:00
title: "Bridge Protocol"
2026-01-12 04:44:14 +00:00
---
2026-01-19 08:54:21 +00:00
# Bridge protocol (legacy node transport)
2026-01-12 04:44:14 +00:00
2026-03-31 14:37:43 +09:00
<Warning>
The TCP bridge has been **removed ** . Current OpenClaw builds do not ship the bridge listener and `bridge.*` config keys are no longer in the schema. This page is kept for historical reference only. Use the [Gateway Protocol ](/gateway/protocol ) for all node/operator clients.
</Warning>
2026-01-22 23:07:58 +00:00
2026-04-04 21:24:09 +01:00
## Why it existed
2026-01-12 04:44:14 +00:00
- **Security boundary**: the bridge exposes a small allowlist instead of the
full gateway API surface.
- **Pairing + node identity**: node admission is owned by the gateway and tied
to a per-node token.
- **Discovery UX**: nodes can discover gateways via Bonjour on LAN, or connect
directly over a tailnet.
- **Loopback WS**: the full WS control plane stays local unless tunneled via SSH.
## Transport
- TCP, one JSON object per line (JSONL).
2026-01-16 05:28:33 +00:00
- Optional TLS (when `bridge.tls.enabled` is true).
2026-04-04 21:24:09 +01:00
- Historical default listener port was `18790` (current builds do not start a
TCP bridge).
2026-01-12 04:44:14 +00:00
2026-01-16 05:28:33 +00:00
When TLS is enabled, discovery TXT records include `bridgeTls=1` plus
2026-02-14 17:17:46 +01:00
`bridgeTlsSha256` as a non-secret hint. Note that Bonjour/mDNS TXT records are
unauthenticated; clients must not treat the advertised fingerprint as an
authoritative pin without explicit user intent or other out-of-band verification.
2026-01-16 05:28:33 +00:00
2026-01-12 04:44:14 +00:00
## Handshake + pairing
2026-01-31 21:13:13 +09:00
1. Client sends `hello` with node metadata + token (if already paired).
2. If not paired, gateway replies `error` (`NOT_PAIRED` /`UNAUTHORIZED` ).
3. Client sends `pair-request` .
4. Gateway waits for approval, then sends `pair-ok` and `hello-ok` .
2026-01-12 04:44:14 +00:00
2026-04-04 21:24:09 +01:00
Historically, `hello-ok` returned `serverName` and could include
`canvasHostUrl` .
2026-01-12 04:44:14 +00:00
## Frames
Client → Gateway:
2026-01-31 21:13:13 +09:00
2026-01-18 07:44:28 +00:00
- `req` / `res` : scoped gateway RPC (chat, sessions, config, health, voicewake, skills.bins)
2026-01-18 07:57:54 +00:00
- `event` : node signals (voice transcript, agent request, chat subscribe, exec lifecycle)
2026-01-12 04:44:14 +00:00
Gateway → Client:
2026-01-31 21:13:13 +09:00
2026-01-12 04:44:14 +00:00
- `invoke` / `invoke-res` : node commands (`canvas.*` , `camera.*` , `screen.record` ,
`location.get` , `sms.send` )
- `event` : chat updates for subscribed sessions
- `ping` / `pong` : keepalive
2026-01-22 23:07:58 +00:00
Legacy allowlist enforcement lived in `src/gateway/server-bridge.ts` (removed).
2026-01-12 04:44:14 +00:00
2026-01-18 07:57:54 +00:00
## Exec lifecycle events
2026-01-22 00:49:02 +00:00
Nodes can emit `exec.finished` or `exec.denied` events to surface system.run activity.
These are mapped to system events in the gateway. (Legacy nodes may still emit `exec.started` .)
2026-01-18 07:57:54 +00:00
Payload fields (all optional unless noted):
2026-01-31 21:13:13 +09:00
2026-01-18 07:57:54 +00:00
- `sessionKey` (required): agent session to receive the system event.
- `runId` : unique exec id for grouping.
- `command` : raw or formatted command string.
- `exitCode` , `timedOut` , `success` , `output` : completion details (finished only).
- `reason` : denial reason (denied only).
2026-04-04 21:24:09 +01:00
## Historical tailnet usage
2026-01-12 04:44:14 +00:00
- Bind the bridge to a tailnet IP: `bridge.bind: "tailnet"` in
2026-04-04 21:24:09 +01:00
`~/.openclaw/openclaw.json` (historical only; `bridge.*` is no longer valid).
2026-01-12 04:44:14 +00:00
- Clients connect via MagicDNS name or tailnet IP.
- Bonjour does **not ** cross networks; use manual host/port or wide-area DNS‑ SD
when needed.
## Versioning
2026-04-04 21:24:09 +01:00
The bridge was **implicit v1 ** (no min/max negotiation). This section is
historical reference only; current node/operator clients use the WebSocket
[Gateway Protocol ](/gateway/protocol ).