> ## Documentation Index
> Fetch the complete documentation index at: https://tesser.sh/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# localhost rules

> Box addresses, focus, cookies, sockets, and the panel

The exact rules for localhost routing, for looking things up. What a single command
does is in the [CLI reference](https://tesser.sh/docs/cli-reference.md), and timers and box sizes are
in [Configuration](https://tesser.sh/docs/config.md).

The [See any branch at localhost](https://tesser.sh/docs/localhost.md) page explains the ideas.

## localhost routing

### The daemon

* `tesser dev`, `use`, and `review` start tesserd in the background when it
  is not running. `tesser daemon install` makes it a login service (see
  [`tesser daemon`](https://tesser.sh/docs/cli-reference#tesser-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 redirected to another port of another box.
* It answers only requests addressed to a name that reaches this machine:
  `localhost`, any `*.localhost` name, an IP address, the machine's hostname
  or `<hostname>.local`, and its Tailscale name when Tailscale is running.
  Any other `Host` gets a 403 that says to open `localhost:<port>` instead.
  A proxy of your own in front of tesserd must send `Host: localhost`.
* It answers your own machine and Tailscale peers, and refuses the rest of
  the LAN unless started with `--allow-lan`.
* Your app is shown a `localhost` address. A request to
  `box-<id>.localhost:<port>`, the Tailscale name, the hostname or a LAN IP
  arrives with `Host: localhost:<port>`, and `acme.box-<id>.localhost` with
  `Host: acme.localhost:<port>`. A browser's `Origin` on any of these is
  rewritten the same way. A request to `127.0.0.1` keeps its own `Host` and
  `Origin`, except a WebSocket, which gets `localhost:<port>`.
* A write (any method but GET and HEAD) with no `Origin` and no
  `Sec-Fetch-Site`, such as curl, sent to a `localhost` name or a loopback IP,
  arrives with `Origin` set to its `Host`. An `Origin` from another site, or
  `null`, passes through as sent.

### Box addresses

* A box id such as `box_a1b2c3` appears in its address as `box-a1b2c3`,
  because a Content-Security-Policy does not accept a hostname with an
  underscore. `box_a1b2c3.localhost` still reaches the same box.
* Any `tesser` command that takes a box id also takes the box's address, such
  as `box-a1b2c3.localhost:5173` or `http://box-a1b2c3.localhost:5173/`.
* Every port a box declares is served, such as `box-<id>.localhost:9229` for
  a debugger. Opening a page on a port the box does not serve, such as 3000,
  sends the browser to the same path on the box's own port. Any other request
  on that port answers 404.
* The laptop serves the boxes it started, boxes opened from a share link, and
  the org's shared instances. A shared instance needs no share link: the
  first request to its address adds it to the laptop, and opening it in a
  browser wakes it. `tesser service ls` shows each shared instance box.
* A box the laptop cannot add, such as a teammate's box nobody shared with
  you, answers 404 `NO_TARGET` with the reason, such as that the box does not
  exist or that you are not allowed to run on it. A browser shows the reason
  as the page heading. When the daemon cannot reach Tesser to ask, the
  request answers 503 and can be retried.
* A request from another site's page, such as an image on an unrelated site,
  never adds a box. Open the box's address from the address bar first.

### Dependency ports on a box address

* If a frontend's manifest says `5000 = "api"`, `box-<id>.localhost:5000` is
  the `api` that frontend talks to: its wire, the org's shared instance, or
  your box of `api` from the same worktree, whichever its routing table says now.
* When that backend is one of your boxes, the request rides the tunnel the
  laptop already holds to it. Otherwise the daemon opens one through the
  frontend box's loopback port.
* A dependency with nothing behind it answers 503 and names the
  `tesser wire` command that fixes it.

### A box page calling bare localhost

* A page on a box's address stays with that box when it calls bare
  `localhost`. If `box-<id>.localhost:3000` fetches `http://localhost:8080`,
  loads a script or image from it, or opens a websocket to it, the request
  goes where `box-<id>.localhost:8080` would. So a URL your app has baked in
  stays in that box's worktree.
* tesserd recognizes these requests by their `Origin` header, or `Referer`
  when there is no `Origin`.
* A port outside that box's declared and dependency ports goes to the focused
  box.
* Page loads on bare `localhost` are never routed this way. Moving the focus
  does not reload these tabs or close their sockets.

### From a box

* Code on any of your boxes can open `http://box-<id>.localhost:<port>` for
  any instance box in the org and reach that box's declared port, wired or
  not. This includes the org's shared instances, so a shared box can call
  back into a dev box that handed it its address, such as for webhooks.
* Workbenches declare no ports, so they have no address, and bare
  `localhost:<port>` on a workbench is the workbench itself, which runs no
  server. A box holds
  addresses for at most 254 others.
* A browser or curl on the box, which dials loopback with the name in
  `Host`, is routed by name on a port some other box declares.
* Nothing is bound on the box for this. Anything listening on the box wins
  its port, whether it started before or after: its own ports, its
  dependency ports, a database a test started. So from a browser on a box, a
  peer's copy of a port this box listens on reaches this box.
* A port another box declares accepts a connection on this box's loopback
  even when nothing local listens, so a raw TCP probe (`nc -z`,
  `wait-on tcp:`) cannot tell the port is free. Probe over HTTP. A port the
  target box does not declare is refused immediately.
* The run command gets the box's own address as `TESSER_BOX_URL` and its id
  as `TESSER_BOX_ID`.
* `<service>.localhost:<port>` names whichever box is the org's shared
  instance of that service now, so it survives a promote: the name moves to
  the new box and the old one drains. In-flight connections stay; a new
  connection after the promote lands on the new box. Use it when the other
  side should be the shared instance rather than one box, such as a webhook
  subscription that should survive deploys.

### Focus

* Focusing a box focuses its whole dependency graph. Each box brings its
  declared ports and dependency ports. Shared dependencies are included even
  without a local target or SSH key for them: the daemon tunnels through one
  of your registered boxes.
* The last explicit focus wins for every port in its subtree. Unrelated ports
  stay where they were. Removing a focus reveals the one underneath.
* A missing binding fails with an explanation. It never falls back to an
  older focus.
* Shared nodes and cycles are visited once per focused root.
* Focus changes only the laptop's routes. Dashboard A's server process still
  calls the backend wired to A. To browser-test a backend-only branch B, run
  a dashboard B and wire it to backend B (see
  [Wiring a dependency](https://tesser.sh/docs/wiring.md#wiring-a-dependency)).
* A new `tesser dev` joins the focus at the bottom, taking unclaimed ports.
  Re-running an existing box keeps its priority. Starting a service does not
  rewire its dependencies or launch other services.

For a dashboard wired to a server, where the server uses hp and a worker:

| Choice | Dashboard | Server | hp and worker |
| - | - | - | - |
| Use dashboard A | A | A's server | A's dependencies |
| Use server B | stays A | B | B's dependencies |
| Use hp C | stays A | stays B | hp C; worker stays unless hp C depends on another worker |
| Use dashboard A again | A | A's server | A's dependencies again |

### `tesser use`

* The focus is saved even when the daemon is unavailable. The command then
  fails and says routing was not verified.
* It also fails when the focus is applied but its routes are unavailable. A
  ready route means the local tunnel accepts connections and the last known
  box status allows serving. It is not an application health check.
* `tesser use --json` prints the same graph and status the panel reads.

### TCP

HTTP on a port is routed by name. Anything else is passed through as bytes,
so a database dependency is reachable from laptop tools on bare
`localhost:5432`, the same as from the box.

### Cookies and sockets

* `localhost` and `box-<id>.localhost` are different sites to the browser,
  so a `Lax` or default cookie is not sent between them. A box's address has
  its own cookies, so a tab there keeps a sign-in per box.
* A `SameSite=None` cookie set on `localhost` is sent with a box page's calls
  to bare `localhost`, and those calls reach the page's box, not the focused
  one.
* When the focus moves, the proxy closes the old box's connections on the
  ports that moved, so a hot-reload socket stops feeding the page from the
  old branch. Pages on ports that did not move are not touched.
* A frontend that calls its API at a hardcoded `http://localhost:<port>` and
  signs in with cookies should call its box's address 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.

### The panel

* `⌘⇧U` opens the panel. It lists the branches serving this port, each
  followed by its repository when the repository's name differs from the
  branch's. Hovering shows which branch you are on.
* "Hide until tesserd restarts" takes the square off every page. `⌘⇧U` still
  opens the panel, and expired AWS credentials still show.
* Choosing a branch focuses the service serving this page and its whole
  dependency graph. Choosing the current branch again restores its graph
  after overrides.
* Ports that fail to connect are listed under the branches.
* A tab keeps the kind of address it was opened on. On a box address,
  choosing a branch moves the tab to that branch's box address on the same
  path, and each box keeps its own cookies. On bare `localhost`, the address
  stays and the page reloads onto the chosen branch.
* A service with `box_address = true` never stays on bare `localhost`: a page
  opened there moves to the box that port shows, on the same path. Only page
  loads move.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.