the navigator
Every terminal, at a glance.
The dock is the canonical live-terminal navigator down the left edge of the canvas. Where the canvas is spatial — tiles wherever you dragged them — the dock is a single ordered list, so a glance answers “what do I have open, and which one needs me?” without hunting across the plane.

Two levels of detail
The dock has two densities. Rail is a narrow strip of one chip per terminal.
Cards (the default) groups rows by repo, each row reading
indicator · branch · pips · time. Toggle between them with
Cmd/Ctrl + Shift + B.
Rows are grouped by repo, and each repo is a card: a continuous repo-coloured spine down its left edge, a solid monogram tile (first letter of the repo) plus the uppercase name on a tinted header that stays pinned while you scroll that repo’s rows, and a little air between cards so a busy fleet stays scannable. Which repo a terminal belongs to is obvious without reading a label that has scrolled away. Per-branch row colours still tell branches apart within a repo.
In maximized mode the cards dock is a real sidebar beside the canvas, and you can drag its right edge to resize it — just like the right panel. Drag to the width you want (it reflows live), or double-click the edge to reset to the default. The width is remembered per device. The narrow rail is a fixed-width strip, and the floating dock in tiled mode keeps its default width.
One indicator per row
The first-column status indicator folds identity, state, activity, and obligation into one mark, so a sweep down the dock reads overall activity without separate dots fighting for space:
- identity (shape) — who is driving: a real agent brand mark (Claude, Codex,
OpenCode, Grok), or a shell
#when there is no agent; - state (colour) — what that driver is doing:
- busy orange while the machine is in flight (thinking / tools / background
work, and a plain shell with live output such as
btop); - full violet when it is blocked on you, and a dimmed violet for the brief post-turn lull — two strengths of one hue, so “answer me” never reads as quietly as “just finished”;
- moonlit when sleeping — and the whole row recedes (~55% opacity);
- busy orange while the machine is in flight (thinking / tools / background
work, and a plain shell with live output such as
- activity (motion) — the glyph spins (2.8s continuous) while the terminal is effectively active, glows when it is blocked on you, and holds still when quiet. Under reduced motion, animations freeze. Active rows hide the “Xs ago” recency (it would only say “just now”);
- attention (row wash) — the whole row tints, its 3px leading stripe lights up, and the title goes bold. Violet when an agent is blocked on you, and a violet chip replaces the timestamp with how long it has been waiting — so a question left overnight reads “14h”, not a quiet dot. Amber for a background ping you have not opened yet, with an amber corner badge on the pip carrying the same fact precisely. Blocked beats unopened when both apply.
The row, not a dot on it, is what carries attention. A mark you catch at the edge of vision survives on area: the dock’s corner badge already pulsed and unread threads still went unnoticed, because motion on a 7px object doesn’t buy attention.
The same StatePip leads the tile title bar, so dock and title never disagree.
Every repo section header carries the same three counts the host tab does — active, needs you, unread. The two you can act on are pills, and clicking one jumps to the next terminal it counts; the plain number beside the repo name is just how many terminals it holds. The counts include rows a filter is currently hiding: an agent that has been blocked long enough to fall out of the activity window is exactly the one whose count must still reach you.
The dock does not rearrange itself. Rows are ordered by structure — repo, then branch, then the order you created them — so a terminal stays exactly where you last saw it until you close it, and a new one appends at the bottom. Nothing moves because an agent somewhere finished a turn. That is what makes Cmd/Ctrl + 1..9 (which walks this same list) worth committing to memory: the third row is still the third row tomorrow.
Recency has not gone anywhere — it just stopped deciding positions. Each row still shows how long ago it moved, still pulses while its agent is working, and still falls out of the dock when it ages past the activity window. If you want a list ordered by what is warm, that is what the switcher’s Recent band is for; the dock answers where things are.
Clicking a row centres its tile on the canvas.
Every split is an indented sub-entry directly beneath its parent row — its real
parent, which may itself be a split: a split of a split sits one notch further
in, under the split it belongs to, rather than flattening up to the tile the way
the canvas tab strip does. Clicking
one lands in that pane, and both the parent row and the split stay highlighted:
the parent names the active tile, while the sub-entry names where the keyboard
is inside it. Every sub-entry carries the same status indicator as a top-level
row — the shell # identity glyph and activity motion for a plain shell, the
agent brand mark and violet/amber attention wash when an agent is present — so
shell and agent splits cannot drift. The entries are the inventory, so there is
no separate split-count chip on the parent row.
The Needs-you strip
When an agent is genuinely blocked on your input, it appears in a small Needs you strip pinned to the top of the dock, showing how long it has been waiting. The strip is a mirror, not a move: the row itself stays in its section, keeps its number, and nothing below it shifts. An empty strip renders nothing at all, so the dock only grows this band when there is something in it.
Only an agent genuinely awaiting you earns the strip — a just-finished agent does not, it merely dims to its lingering colour. Clicking an entry jumps to that terminal. Nothing dismisses the strip except the agent no longer needing you.
The strip reaches past the dock’s own filters, exactly as the section counts do. An agent blocked since yesterday has aged out of a 12h activity window and a slept terminal can still be the one asking — so a filter that hides a row from the list below does not hide it here. Those entries sit slightly faded, and clicking one still takes you straight to the terminal. Waiting the longest is the one thing that must never cost you your place in the strip.
If the blocked agent is a split, the entry shows that split’s colour and its wait, and clicking it lands on the tile that holds it.
The Filters row — keep it to what matters
The dock’s footer carries a Filters row with two independent chips over the same list:
- an activity window (
All / 4h / 12h / 24h / 48h) hides rows you haven’t touched inside the cutoff. It defaults to All — nothing is hidden until you narrow it — and the choice persists per device. A hidden terminal stops counting toward the app badge, but a fresh agent transition surfaces it again, so nothing important stays buried. - a ☾ sleeping chip hides terminals you deliberately put to sleep. The window filters by staleness, the ☾ chip by dormancy — and the activity window also compresses away old sleeping tiles, timed from when you slept them.
A single N hidden · show all reports what both filters hide together and
clears them in one click.