Runners

A runner is a Linux machine running Strado headless. Its worktrees, terminals and agents appear in your desktop app beside your local ones, and you work on them from there.

What a runner is made of

The same stack as the desktop, minus Electron:

PieceSame as the desktop?
HTTP and WebSocket APIYes — the same server package
The web UIYes — the same built app
ptyd, the terminal daemonYes
Tunnel clientRunner-only: dials out so nothing has to be opened inbound
Node and node-ptyVendored into the bundle — the box needs no Node installed

It installs under ~/.strado/runner without root, and it runs as you: a systemd user unit, not a system service, so your SSH keys, your git config and your agent credentials are the ones it uses.

If the box also has podman or docker, each new worktree additionally gets its own container — see sandboxes.

What a runner cannot do

Heads up

A remote worktree has no embedded VS Code tab, no preview browser, no Logs button, no diff and commit view, and no changes rail — and a runner raises no desktop notifications. An agent working on a runner can read and write code and run commands; it cannot look at the page it is building, and you cannot review its diff in Strado.

This is the single most important expectation to set, so it is worth being precise about how it shows up: those surfaces are hidden, not disabled. The runner tells the desktop what it can do, and the desktop leaves out what it cannot deliver rather than rendering a tab that fails when clicked. The rest are absent for a plainer reason — they read local git and process state, which does not exist for a worktree on another machine.

There is no diff surface for a remote worktree anywhere in Strado. Reviewing changes on one means git diff in a terminal, or pushing the branch and reading it on your provider.

What does work remotely: terminals and agent sessions, worktree creation and deletion, dev servers, and reaching those dev servers from your own browser through a forwarded port. Git itself is available the way it always is — as commands in a shell on the runner.

Your keyboard shortcuts are unaffected. They belong to the desktop app you are sitting at, not to the machine the worktree lives on.

Why put work on one

Three reasons the design keeps coming back to:

  • The box is bigger than your laptop, or it is already the machine your build needs.
  • The code should not leave the network it lives on. The runner dials out; nothing inbound is ever opened on it, and it never needs a public address.
  • The work outlives your session. Agent sessions live in ptyd on the runner, so closing your laptop, restarting your desktop app, or updating the runner leaves them running.

Where the traffic goes

Your desktop does not connect to the runner directly. The runner opens an outbound WebSocket to Strado's relay and keeps it; your desktop reaches the runner through that same connection.

That is what makes a runner work behind NAT and on a network with no inbound ports, and it is also the cost: every request takes the long way round. See remote ports for what that means in practice.

Where to go next