How it's built
Alto app · alto command another computer (this computer) over Tailscale │ │ TCP, Tailscale addresses only │ ┌─────────────▼──────────────┐ │ │ service: finds and starts │ │ │ sessions, pairs devices, │ │ │ keeps the computer awake, │ │ │ passes remote clients │ │ │ through, untouched │ │ └─────────────┬──────────────┘ │ local socket, │ passed │ straight to the session │ through ▼ ▼ ─────┬───────────────────┬──────────────────────┬────────── ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ session 1│ │ session 2│ … │ session N│ one process each │ terminal │ │ terminal │ │ terminal │ (a pseudo-terminal, │ state │ │ state │ │ state │ ConPTY on Windows) └────┬─────┘ └────┬─────┘ └────┬─────┘ ▼ ▼ ▼ claude zsh codexA session process per tab. Each session owns its program’s terminal and a full copy of the terminal’s state in libghostty. It does little else, so it rarely needs to change, and a crash takes down one session, not all of them.
The service holds nothing that can’t be rebuilt. It starts sessions, finds them again from small records on disk, and serves the command line, pairing and remote access. Clients on this computer talk to their session’s own socket directly; the service only passes remote clients through. It can restart or be replaced at any time without touching a running session.
Clients are interchangeable. The app, alto attach, a script and another computer all attach the same way: say hello, get a snapshot of the terminal’s state (the screen first, then the older scrollback), then live output, and send keys and resizes back. What happens only once, like a program copying to the clipboard, goes to the clients attached at the time and is never replayed. Each client runs libghostty itself, so it draws the real terminal state, not a copy of someone else’s drawing.
One small, versioned protocol over local sockets and TCP alike. Each side offers its newest version and they speak the older of the two, so sessions started by an older build keep working with a newer app and service.
Every client says whether it types for a person or an agent. The session holds an agent’s input while a person is typing, refuses it while paused, and says who typed last, so every window can mark it. Links from a conversation to its work panes are kept by the service, not the app, so an agent finds its pane with no window open.
Remote access is Tailscale’s, plus Alto’s own checks. The service listens only on this computer’s Tailscale addresses, never on the LAN or the internet. See Remote access with Tailscale.
A multiplexer without a second terminal
Section titled “A multiplexer without a second terminal”A multiplexer that runs inside your terminal is a second terminal emulator between the program and the screen: images, the Kitty keyboard protocol, links and scrollback all go through its copy, and a copy mode replaces native selection. And when one process holds every session, its crash or upgrade can take them all.
Alto keeps each session in its own process, and its window draws libghostty’s own state, so what the program sends is what you see. In another terminal, alto attach draws the session as it is, with Ctrl-\ the only key it takes. See Why Alto for the other alternatives.
The code
Section titled “The code”Rust, with GPUI for the window:
| Crate | What it is |
|---|---|
crates/term |
libghostty, behind plain types |
crates/session |
the session process and its clients |
crates/proto |
the messages |
crates/service |
the service |
crates/cli |
the alto command, which is also the service and the session process |
crates/app |
the window |