2025-12-13 03:47:27 +00:00
---
2025-12-19 23:12:52 +01:00
summary: "Node discovery and transports (Bonjour, Tailscale, SSH) for finding the gateway"
2025-12-13 03:47:27 +00:00
read_when:
- Implementing or changing Bonjour discovery/advertising
- Adjusting remote connection modes (direct vs SSH)
- Designing bridge + pairing for remote nodes
---
# Discovery & transports
2026-01-04 14:32:47 +00:00
Clawdbot has two distinct problems that look similar on the surface:
2025-12-13 03:47:27 +00:00
2025-12-19 23:12:52 +01:00
1) **Operator remote control** : the macOS menu bar app controlling a gateway running elsewhere.
2025-12-18 13:18:33 +01:00
2) **Node pairing** : iOS/Android (and future nodes) finding a gateway and pairing securely.
2025-12-13 03:47:27 +00:00
2026-01-04 14:32:47 +00:00
The design goal is to keep all network discovery/advertising in the **Node Gateway** (`clawd` / `clawdbot gateway` ) and keep clients (mac app, iOS) as consumers.
2025-12-13 03:47:27 +00:00
## Terms
2025-12-19 23:12:52 +01:00
- **Gateway**: the single, long-running gateway process that owns state (sessions, pairing, node registry) and runs providers.
2025-12-13 03:47:27 +00:00
- **Gateway WS (loopback)**: the existing gateway WebSocket control endpoint on `127.0.0.1:18789` .
- **Bridge (direct transport)**: a LAN/tailnet-facing endpoint owned by the gateway that allows authenticated clients/nodes to call a scoped subset of gateway methods. The bridge exists so the gateway can remain loopback-only.
- **SSH transport (fallback)**: remote control by forwarding `127.0.0.1:18789` over SSH.
## Why we keep both “direct” and SSH
- **Direct bridge** is the best UX on the same network and within a tailnet:
- auto-discovery on LAN via Bonjour
- pairing tokens + ACLs owned by the gateway
- no shell access required; protocol surface can stay tight and auditable
- **SSH** remains the universal fallback:
- works anywhere you have SSH access (even across unrelated networks)
- survives multicast/mDNS issues
- requires no new inbound ports besides SSH
2025-12-19 23:12:52 +01:00
## Discovery inputs (how clients learn where the gateway is)
2025-12-13 03:47:27 +00:00
### 1) Bonjour / mDNS (LAN only)
Bonjour is best-effort and does not cross networks. It is only used for “same LAN” convenience.
Target direction:
2025-12-19 23:12:52 +01:00
- The **gateway** advertises its bridge via Bonjour.
- Clients browse and show a “pick a gateway” list, then store the chosen endpoint.
2025-12-13 03:47:27 +00:00
2026-01-06 18:59:06 +01:00
Troubleshooting and beacon details: [`docs/bonjour.md` ](https://docs.clawd.bot/bonjour ).
2025-12-13 04:28:12 +00:00
2025-12-13 03:47:27 +00:00
#### Current implementation
- Service types:
2026-01-04 14:32:47 +00:00
- `_clawdbot-bridge._tcp` (bridge transport beacon)
2025-12-13 03:47:27 +00:00
- TXT keys (non-secret):
2025-12-19 23:12:52 +01:00
- `role=gateway`
2025-12-13 03:47:27 +00:00
- `lanHost=<hostname>.local`
- `sshPort=22` (or whatever is advertised)
- `gatewayPort=18789` (loopback WS port; informational)
- `bridgePort=18790` (when bridge is enabled)
2026-01-04 14:32:47 +00:00
- `canvasPort=18793` (default canvas host port; serves `/__clawdbot__/canvas/` )
- `cliPath=<path>` (optional; absolute path to a runnable `clawdbot` entrypoint or binary)
2025-12-20 16:43:08 +01:00
- `tailnetDns=<magicdns>` (optional hint; auto-detected when Tailscale is available)
2025-12-13 03:47:27 +00:00
Disable/override:
2026-01-04 14:32:47 +00:00
- `CLAWDBOT_DISABLE_BONJOUR=1` disables advertising.
- `CLAWDBOT_BRIDGE_ENABLED=0` disables the bridge listener.
- `bridge.bind` / `bridge.port` in `~/.clawdbot/clawdbot.json` control bridge bind/port (preferred).
- `CLAWDBOT_BRIDGE_HOST` / `CLAWDBOT_BRIDGE_PORT` still work as a back-compat override when `bridge.bind` / `bridge.port` are not set.
- `CLAWDBOT_SSH_PORT` overrides the SSH port advertised in the bridge beacon (defaults to 22).
- `CLAWDBOT_TAILNET_DNS` publishes a `tailnetDns` hint (MagicDNS) in the bridge beacon (auto-detected if unset).
2025-12-13 03:47:27 +00:00
### 2) Tailnet (cross-network)
For London/Vienna style setups, Bonjour won’ t help. The recommended “direct” target is:
- Tailscale MagicDNS name (preferred) or a stable tailnet IP.
2025-12-20 15:02:23 +01:00
If the gateway can detect it is running under Tailscale, it publishes `tailnetDns` as an optional hint for clients (including wide-area beacons).
2025-12-13 03:47:27 +00:00
### 3) Manual / SSH target
When there is no direct route (or direct is disabled), clients can always connect via SSH by forwarding the loopback gateway port.
2026-01-06 18:59:06 +01:00
See [`docs/remote.md` ](https://docs.clawd.bot/remote ).
2025-12-13 03:47:27 +00:00
## Transport selection (client policy)
Recommended client behavior:
1) If a paired direct endpoint is configured and reachable, use it.
2025-12-19 23:12:52 +01:00
2) Else, if Bonjour finds a gateway on LAN, offer a one-tap “Use this gateway” choice and save it as the direct endpoint.
2025-12-13 03:47:27 +00:00
3) Else, if a tailnet DNS/IP is configured, try direct.
4) Else, fall back to SSH.
## Pairing + auth (direct transport)
The gateway is the source of truth for node/client admission.
2026-01-06 18:59:06 +01:00
- Pairing requests are created/approved/rejected in the gateway (see [`docs/gateway/pairing.md` ](https://docs.clawd.bot/gateway/pairing )).
2025-12-13 03:47:27 +00:00
- The bridge enforces:
- auth (token / keypair)
- scopes/ACLs (bridge is not a raw proxy to every gateway method)
- rate limits
## Where the code lives (target architecture)
- Node gateway:
- advertises discovery beacons (Bonjour)
- owns pairing storage + decisions
- runs the bridge listener (direct transport)
- macOS app:
2025-12-19 23:12:52 +01:00
- UI for picking a gateway, showing pairing prompts, and troubleshooting
2025-12-13 03:47:27 +00:00
- SSH tunneling only for the fallback path
- iOS node:
- browses Bonjour (LAN) as a convenience only
- uses direct transport + pairing to connect to the gateway