v2.6.0 - Remote Access
Dispatch has always been a localhost tool, and it still is by default. This release adds one thing on top, on your terms: flip a switch in Settings and your board, including the live agent terminals, becomes reachable from any device's browser over a temporary public HTTPS link that you guard with a self-minted access code. There is no account to create, no domain to buy, and nothing left standing open when you are not using it. Turn it off, restart, or shut down, and remote access is gone. When it is off, Dispatch behaves exactly as it did before, with no code prompt and no friction on your own machine.
The hard part here was never the tunnel. It was the terminals. Every agent session runs its own terminal server on a private loopback port that the board embeds as a direct http://127.0.0.1:<port> iframe, which is exactly the one thing a naive tunnel cannot carry. Most of this release is the internal rework that folds those terminals under a single origin so they travel through one guarded door, plus the door itself.
See it
Higher-quality video: dispatch-v2.6.0-remote-access.webm
Reaching the board from anywhere
There is a new Remote tab in Settings. Enable it and Dispatch starts an on-demand Cloudflare Quick Tunnel and mints a fresh access code, then shows you a live public URL, a QR code with the code already embedded for your own phone, the plain code to paste on a borrowed laptop, and a live status while the tunnel comes up. Scan the QR or paste the code and you land on the same board you see locally, terminals included. The tunnel is treated the way ttyd and tmux already are: cloudflared is checked only when you enable the feature, and if it is missing you get a brew install cloudflared message instead of a failure. Nothing is bundled or auto-downloaded, and the tunnel URL changes each time you enable, which is the accepted tradeoff for a zero-account setup.
A single door in front of everything
Because a public URL removes the loopback guarantee that Dispatch has always leaned on, there is now one access gate sitting in front of the SPA, the API, the live update stream, and the terminal WebSocket, all at once. Requests from your own machine pass straight through as before. Anything arriving from the tunnel needs a valid session or it is turned away and handed a small, self-contained code-entry page. The access code is a four-word passphrase that is easy to read off a screen and type on a phone, and it is checked in constant time with a progressive lockout so repeated wrong guesses back off instead of letting anyone hammer the code. A correct code sets a signed, HttpOnly, Secure, SameSite session cookie that lives only in memory and dies the moment you disable remote access or the server restarts. The gate is fail-closed by construction: it never trusts an "is this feature on" flag, so a request that is not from loopback and has no valid session is refused whether the feature is on, off, or somewhere in between.
One subtlety worth calling out, because it took real work to get right. Since the tunnel connects to Dispatch over loopback, the server cannot tell local traffic from tunnel traffic by connection alone, only by the requested host. To keep that from becoming a way to impersonate a local request, tunnel traffic is pinned to a host that can never look local, and the cross-check that protects the code submission compares against the tunnel's real public address rather than the rewritten one. Both halves were verified against a live tunnel, including a spoofing attempt that is correctly rejected while a genuine remote sign-in still works.
Folding the terminals under one origin
Each session's terminal is now served through the main Dispatch origin at a stable path derived from the card, over both HTTP and the WebSocket upgrade, instead of the old hardcoded loopback address. The terminal server is launched with a matching base path so its own assets and socket resolve correctly behind the proxy, and it stays bound to loopback, reachable only through the gated path. The board iframe simply points at the relative path now, which keeps the terminal from ever remounting when you toggle fullscreen or the details panel. The proxy re-resolves the live terminal port on every request and every socket upgrade, so a terminal that respawns mid-session reconnects to the new port on its own. Locally this changes nothing you can see: typing, scrollback, resize, and the cmd-click and shift-enter behaviors all work exactly as before.
Seeing the board over the tunnel
There is an honest limitation here that shaped part of the release. Cloudflare Quick Tunnels carry the terminal WebSocket fine, but they do not pass the server-sent event stream the board uses for live updates, so over the tunnel the board would have loaded empty even after signing in. Rather than ship a blank board, Dispatch now loads the board from a plain request on first paint and quietly polls for changes whenever the live stream is not delivering, which is exactly the tunnel case. On your own machine the live stream still arrives instantly and nothing polls, so local behavior and latency are unchanged. Over the tunnel the board renders and stays current: move a card locally and it shows up on your phone within the poll interval. If you ever outgrow the quick tunnel, a stable bring-your-own-tunnel option remains the documented path forward.
Fail-closed everywhere
Remote access is designed to disappear cleanly. The tunnel process is a direct child of the server rather than a detached one, so it dies when Dispatch does. There is a new signal handler, the first in the app, that tears down the tunnel and clears the token on shutdown while deliberately leaving your tmux and terminal sessions alone so a normal restart does not disturb your work. On boot Dispatch sweeps any stray tunnel process left behind by an unclean exit and never adopts it, which is the opposite of how it treats terminals. Nothing about remote access is written to disk, the code and tunnel are never resumed automatically after a restart, and a tunnel URL from a previous run is dead the moment the server comes back.
Full changelog: v2.5.3...v2.6.0
Requires Node ≥ 22.22, tmux, ttyd, git, and the Claude Code CLI. Reaching the board remotely also needs cloudflared, which Dispatch checks for only when you enable remote access. Setup is in the README.
