Local-first routing
The dashboard probes 127.0.0.1:33120 first on every API call. If reachable, the request stays local. If not, it falls back to the outbound WebSocket broker at <uid6>-<machine-slug>.bernato.dev — no inbound ports, no third-party tunnel.
Why it matters for terminals
A PTY pushes a byte for every keystroke. Round-trip latency is the difference between "it feels local" and "it feels like a relay."
The paths
Same-machine loopback is the shortest path. Same-LAN remote daemon traffic stays local to your network. Off-LAN control uses the tunnel and inherits relay/network latency.
How the probe works
Every API call has a 150ms timeout to localhost. If it answers, we're on LAN. If it doesn't, we fall back. The dashboard caches the choice for 30 seconds to skip the probe on subsequent calls.
The tunnel
A single outbound wss:// connection from the daemon to the Bernato broker — no inbound ports, no third-party tunnel binaries. All API requests, SSE, and terminal sessions are multiplexed over that one socket. Per-machine hosts are namespaced as <uid6>-<machine-slug>.bernato.dev, and the daemon still enforces its own auth and capability gates on every relayed request.
Detailed: LAN-direct routing post and Tailscale vs Cloudflare Tunnel vs bore.
FAQ
Does the phone approval view use LAN-direct?
No — phones can't reach your laptop's loopback. Phone browsers use the tunnel.
Does it work offline?
Pairing requires internet. After pairing, LAN-only operation is fine — you just lose tunnel fallback.