Sessions
A session is one process attached to one worktree: an agent or a shell. It is owned by a daemon rather than by the app, which is why it outlives almost everything you do to the window.
What you can run
| Session | How it starts |
|---|---|
| Claude | your login shell running claude |
| Codex | your login shell running codex |
| OpenCode | your login shell running opencode |
| Shell | your login shell, interactive |
OpenCode's entry in the add-session menu is disabled when the binary is not installed, with the reason on hover, rather than failing after you pick it.
Every session starts at the worktree's root. In a monorepo that is a real distinction: a repo can name a project subfolder, and the dev server runs inside it, but agent and shell sessions do not — they start at the top of the worktree regardless.
More than one of the same agent
A worktree can hold several sessions of the same agent. The first carries the agent's plain name and later ones are numbered: Claude, Claude 2, Claude 3.
Resume behaviour is not the same across the three, and this catches people out:
| Agent | Session 1 | Later sessions |
|---|---|---|
| Codex | resumes the directory's last conversation | starts fresh |
| OpenCode | continues the last conversation | starts fresh |
| Claude | started plainly, no resume flag | started plainly, no resume flag |
For Codex and OpenCode the split is deliberate: two tabs resuming the same thread would fight over it. Strado passes no resume flag to Claude at all, in either position.
Each session is told which one it is through STRADO_SESSION_ID, which is how
status from two Claude tabs in one worktree stays separate rather than
overwriting itself.
The sessions rail
⌘+L opens a rail on the right listing every live session in the workspace, grouped by repo and then by worktree. Each worktree line carries its own chips — one per session, colored by status — and clicking a chip jumps straight to that session in the hub.
There is a filter box at the top, and the rail's left edge drags to resize; the width is remembered.
How sessions survive
Terminals do not run inside the Strado server. They run in strado-ptyd, a
standalone daemon the server talks to over a Unix socket:
| Path | What |
|---|---|
~/.strado/ptyd/ptyd.sock | The socket. Mode 0600 — the file permission is the auth boundary. |
~/.strado/ptyd/bin/ | The installed daemon, at a stable path so a handoff can re-spawn itself. |
~/.strado/ptyd/ptyd.log | The daemon's own log. |
That buys two different kinds of survival:
- Server restart, app update, app quit. The daemon is not the server's child — it is spawned detached. A new server reconnects and resubscribes, replaying each session's recent output so your scrollback is still there.
- Daemon upgrade. The old daemon hands the live PTY file descriptors to its successor and passes a snapshot of ids, sizes and buffers with them. If any step fails it kills the successor and resumes; sessions are never put at risk to complete an upgrade.
Each session keeps a replay ring in the daemon's memory — 256 KiB by default. Past a megabyte of unwritten backlog the daemon pauses the PTY, so a runaway command throttles at the source instead of ballooning memory.
Note
STRADO_INPROC_PTY=1 forces the old in-process terminals instead of the
daemon. It exists for the test suite and as break-glass; sessions started
that way die with the server.
Ending a session
This is the one direction that does not survive: closing a session tab, with
the ✕ on its chip or with ⌘+W, kills the process.
Closing the app does not.
One exception, and it goes the other way: closing the tab of a session on a runner detaches from it. That process stays alive — see remote worktrees.
Deleting a worktree kills every session under its path as its first step.