Skip to main content
tesserd is a small proxy on your laptop. It gives every box its own address and makes bare localhost behave like the laptop were the boxes you are looking at. tesser dev, use, and review start it in the background when it is not running, and tesser daemon install makes it a login service (see the daemon). It listens on port 3000 for its own panel and status page, and on every port any of your boxes declares or depends on. A port means that port everywhere: nothing is ever redirected to some other port of some other box.

Every box has an address

This is what tesser dev prints, with the port the service listens on (3000 for a typical Next.js app). Browsers resolve *.localhost to your own machine without any configuration, so two tabs on two box ids show two branches side by side. Every port a box declares is a door — <box_id>.localhost:9229 for a debugger port, say. A port the box does not declare answers 404. A box’s dependency ports are doors as well. If a frontend box’s manifest says 5000 = "api", then <box_id>.localhost:5000 is the api that frontend is talking to: the box you wired it to, or the org’s shared instance, whichever its routing table says right now. When that backend is one of your own boxes the request rides the tunnel the laptop already holds to it; otherwise the daemon opens one through the frontend box’s own loopback port. A dep with nothing behind it answers 503 and names the tesser wire command that fixes it.

From a box

The same address works on the boxes themselves. Code running on any of your boxes can open http://<box_id>.localhost:<port> for any other box in the org and reach that box’s declared port, whether or not the two are wired together. It works for a browser or curl on the box too, which never ask the resolver about *.localhost and dial plain loopback with the name in Host: on a port some other box declares, that connection is routed by the name, the way the laptop does it. Nothing is bound on the box for this, and anything that listens on the box wins its port, whether it started before or after: the box’s own ports, its dependency ports, a database a test brought up. So from a browser on a box, a peer’s copy of a port something on this box is listening on reaches this box, not the peer. The other way round, a port some other box declares accepts a connection on this box’s loopback even when nothing local is listening, so a raw TCP probe (nc -z, wait-on tcp:) cannot tell that port is free; probe over HTTP instead. A port the other box does not declare is refused immediately. This includes the shared instances of main: a shared box can call back into a dev box that handed it its address, which is how a dev box registers for webhooks. The run command gets that address as TESSER_BOX_URL (and the id as TESSER_BOX_ID), so a run script does not need to work it out.

A name that follows the shared instance

A box id names one box for as long as it lives. On a box, <service>.localhost:<port> names whichever box is currently the org’s shared instance of that service, so it survives a promote: the name moves to the new box and the superseded one drains. Use it when the other side is meant to be the shared instance rather than a particular box, such as a webhook subscription that should keep working across deploys. In-flight connections are not moved; a new connection after the promote lands on the new box.

Bare localhost is the focused boxes, port by port

Selecting a box selects its entire recursive dependency graph. Each box brings its declared ports and dependency ports. Shared dependencies are included even when you do not have a local target or SSH key for them: the daemon tunnels through one of your registered boxes using its access to the box mesh. For a dashboard wired to a server, where the server uses hp and a worker: The last explicit selection wins for every port in its subtree. Unrelated ports remain where they were. Remove a selection to reveal the previous selection underneath it. A missing binding fails with an explanation; it does not silently fall back to an older selection. Shared nodes and cycles are visited once per selected root. This changes your laptop’s routes. Dashboard A’s remote server process still calls the backend wired to A. To browser-test a backend-only branch B, run a personal dashboard B and wire it to backend B, even if its frontend code is unchanged. See Wiring a dependency.

Databases and other TCP

Anything that speaks on a port works. A dependency that is a database is reachable from laptop tooling on bare localhost:5432 just as the box reaches it: HTTP on a door is routed by name, everything else is passed through as bytes.

Cookies and OAuth callbacks

Moving the focus does not change the bare address, so an OAuth callback registered for localhost:3000 keeps working as you move between branches. Cookies stay with the address too, exactly as they would for two local copies of your app on one port: if each box keeps sessions in its own database, the next box will ask you to sign in again. A box’s own address has its own cookies, so a tab opened there keeps a sign-in per box. When the focus moves, the proxy closes the old box’s connections on the ports that moved, so a hot-reload socket that was talking to one branch does not keep feeding the page after you have moved to another; pages on ports that did not move are not touched.

The panel

The square in the bottom-right corner opens the panel (⌘⇧U), which lists the branches serving this port; hover it to see which branch you are on. “Hide until tesserd restarts” at the bottom of the panel takes the square off every page; ⌘⇧U still opens the panel, and expired AWS credentials still show. Choose a branch to select the service serving this page and its complete dependency graph. Selecting the current branch again restores its graph after overrides. A tab keeps the kind of address you opened it on. On a box’s address, choosing a branch moves the tab to that branch’s box, http://<box_id>.localhost:<port>, on the same path; every box keeps its own cookies there, so a sign-in on one branch survives a visit to another. On bare localhost the address stays and the page reloads onto the chosen branch. A service whose manifest sets box_address = true never stays on bare localhost: a page you open there moves to the box that port shows, http://<box_id>.localhost:<port>, on the same path. Only page loads move: API calls and sockets to bare localhost go where they always did. Ports that fail to connect are listed under the branches. Bare localhost follows the choice either way, so a URL your app has baked in (http://localhost:8080 for its API, say) reaches the branch you are looking at. To a browser, a page on a box’s address and an API on bare localhost are different sites, and it will not send that API’s cookies. If your frontend calls its API at a hardcoded http://localhost:<port> and signs in with cookies, point it at http://$TESSER_BOX_ID.localhost:<port> instead and set box_address = true, or serve the API through the dev server’s proxy so the page only talks to its own origin.

From a terminal

From a terminal:
Selection is saved even if the daemon is unavailable; the command then fails and says routing was not verified. It also fails when the selection is applied but its routes are unavailable. A ready route means the local tunnel accepts connections and the last known box status permits serving; it is not an application-level health check. A new tesser dev joins the selection at the bottom, taking unclaimed ports. Re-running an existing box preserves its priority. Starting a service does not rewire its dependencies or launch other services.

Over Tailscale

The daemon answers requests from your own machine and from Tailscale peers, so a phone or a second laptop on your tailnet can open the proxy’s address and see the same focus. It refuses requests from the rest of your LAN unless you start it with --allow-lan.