4.3 KiB
summary, read_when
| summary | read_when | |||
|---|---|---|---|---|
| Node discovery and transports (Bonjour, Tailscale, SSH) for finding the master gateway |
|
Discovery & transports
Clawdis has two distinct problems that look similar on the surface:
- Operator remote control: the macOS menu bar app controlling a “master” gateway running elsewhere.
- Node pairing: Iris/iOS (and future nodes) finding a gateway and pairing securely.
The design goal is to keep all network discovery/advertising in the Node Gateway (clawd / clawdis gateway) and keep clients (mac app, iOS) as consumers.
Terms
- Master gateway: the single, long-running gateway process that owns state (sessions, pairing, node registry) and runs providers.
- 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:18789over 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
Discovery inputs (how clients learn where the master is)
1) Bonjour / mDNS (LAN only)
Bonjour is best-effort and does not cross networks. It is only used for “same LAN” convenience.
Target direction:
- The gateway advertises itself (and/or its bridge) via Bonjour.
- Clients browse and show a “pick a master” list, then store the chosen endpoint.
Current implementation
- Service types:
_clawdis-master._tcp(gateway “master” beacon)_clawdis-bridge._tcp(optional; bridge transport beacon)
- TXT keys (non-secret):
role=masterlanHost=<hostname>.localsshPort=22(or whatever is advertised)gatewayPort=18789(loopback WS port; informational)bridgePort=18790(when bridge is enabled)tailnetDns=<magicdns>(optional hint)
Disable/override:
CLAWDIS_DISABLE_BONJOUR=1disables advertising.CLAWDIS_BRIDGE_ENABLED=0disables the bridge listener.CLAWDIS_BRIDGE_HOST/CLAWDIS_BRIDGE_PORTcontrol bind/port.
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.
If the gateway can detect it is running under Tailscale, it can publish tailnetDns as an optional hint for clients.
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.
See docs/remote.md.
Transport selection (client policy)
Recommended client behavior:
- If a paired direct endpoint is configured and reachable, use it.
- Else, if Bonjour finds a master on LAN, offer a one-tap “Use this master” choice and save it as the direct endpoint.
- Else, if a tailnet DNS/IP is configured, try direct.
- Else, fall back to SSH.
Pairing + auth (direct transport)
The gateway is the source of truth for node/client admission.
- Pairing requests are created/approved/rejected in the gateway (see
docs/gateway/pairing.md). - 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:
- UI for picking a master, showing pairing prompts, and troubleshooting
- 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