-
Notifications
You must be signed in to change notification settings - Fork 0
Remote Access
The daemon binds 0.0.0.0 and the only authentication is the token (or an invite link) plus the
host's own /accept. Never put that on a public IP you advertise. Everything below is a way
of moving the bytes; none of it adds a second factor.
| route | how | what it costs |
|---|---|---|
| LAN | the printed ws://<host-ip>:7777 line. Works with no extra software |
everyone has to be on the same network |
| SSH tunnel |
ssh -L 7777:127.0.0.1:7777 host, then claude-jam join ws://127.0.0.1:7777 …
|
the guest needs an SSH account on the host |
| Tailscale | install Tailscale on both machines. If it is installed, the printed join line already uses the tailnet IP | both sides join the tailnet |
| a public relay |
--tunnel or --funnel, below |
the URL is the only thing between the internet and your session — keep it private |
Needs cloudflared on PATH.
claude-jam host --name Roy --cwd . --tunnelSpawns two quick tunnels (one for the WebSocket, one for the browser view if --view is on) and
prints wss://<random-words>.trycloudflare.com join and view URLs. Your guest installs nothing.
The hostname is random and changes on every respawn. That is the one real gotcha: an invite
link fixes its addresses at the moment it is minted, so links minted before a respawn reach the
jam only over their LAN address. Mint fresh ones, or use --funnel.
Needs tailscale on PATH and Funnel enabled for the tailnet.
claude-jam host --name Roy --cwd . --funnelSame job, but the URL is your node's own name — wss://<machine>.<tailnet>.ts.net, and
https://…:8443 for the view — so it is the same every run. Your guest still installs
nothing and does not need to be on your tailnet.
Two things need a human, once:
-
Grant the
funnelnode attribute for the tailnet in Tailscale's Access Controls. Without it the CLI refuses and claude-jam repeats the reason verbatim. -
Use the standalone Tailscale build on macOS. The App Store build is sandboxed and cannot
change funnel configuration at all — its CLI answers
The Tailscale GUI failed to start … (Tailscale.CLIError error 3.). The build from tailscale.com can.--funnel-cli <path>points at a CLI elsewhere.
--tunnel is always available as the fallback.
Neither relay is launch-only. Three surfaces, one code path:
claude-jam remote off|tunnel|funnel [--jam NAME] [--reissue] # from a shell-
/remote off|tunnel|funnelinside the host's client /menu → Access → Remote
Nobody already connected is dropped. A mode that cannot run here says why, with the exact
fix. When a relay comes up, host clients get tunnel ready: <the whole join command> rather than
a silent refresh.
Links minted earlier carry the old address, so the switch offers --reissue to mint every live
link again — and it waits for the new hostname first, because minting immediately would
hand out exactly the address it is replacing. claude-jam invites shows the result.
Only one relay at a time: two for one port is a startup error, and the runtime switch keeps that rule.
claude-jam host … --viewNeeds ttyd. Serves the live TUI read-only at http://jam:<token>@<host>:7778 (port + 1 by
default, --view-port moves it). Each tab gets its own grouped tmux session, so viewers never
move each other's screen. Over --tunnel or --funnel the view gets its own URL.
-
A quick tunnel's hostname changes when
cloudflaredrespawns. Guests already connected keep their socket; guests reconnecting seestill retrying — the join URL changed. The host runs/joinand sends the new line, or switches to--funnel. There is a respawn backoff so a flapping relay does not hammer anything. -
Sockets are heartbeated every 30 s. A missed pong shows in the status row as
⚠ stale Ns; the client reconnects on its own, in tiers, so a laptop that slept comes back without anybody typing anything. - A link's addresses are fixed at mint time. A link carries the relay address first and the LAN address second, and the client tries them in order with a 3-second timeout each — so a link whose tunnel is gone still works on the LAN.
-
Revoking or expiring a link disconnects nobody already in. It only stops the next join.
/kick <name> revokeis the pair that actually removes somebody and takes their link back.