Command Center

One roster of every shell Sox knows about — local, remote, attached, detached — sorted by which one needs you. Running many agents at once stops being a tab-hunting problem and becomes a queue you work top-down.

Press ⌘I in any window to open it, click Command Center in the title bar, or use Command Center in the View menu. ⌘O opens the fleet switcher. In the roster, j/k move one row; g jumps to the top and G to the bottom (⌘↑ / ⌘↓ do the same).

The problem it solves

An agent working alone needs nothing from you. An agent that hit a permission prompt needs you now, and one that finished needs you soon. With a handful of sessions you find those by looking. Past that, you are polling windows — and the cost of missing a blocked agent is the whole time it sat there waiting.

The Command Center inverts it: instead of you checking each session, each session reports its own state, and the roster puts whoever needs you at the top.

What a row can say

Every surface — one shell, one pane — carries exactly one state. States group into tiers by how loudly they should interrupt you.

TierStateMeans
interruptblockedWaiting on you — a tool permission prompt, most often.
interrupterrorThe agent hit a terminal error.
reviewdoneThe turn finished. The agent is still running, waiting for input.
watchstaleWorking, but quiet for longer than expected.
ambientworkingActive. Nothing needed.
ambientidleAt a prompt. Manual shells rest here.

Rows sort blocked, error, done, stale, working, idle — then oldest first inside a tier, so the session that has been waiting longest is next. Working the list from the top is working it in priority order.

stale is derived, never reported: it is what working becomes after the agent goes quiet past a threshold. No agent has to know about it.

Dismissing is acknowledging

The x on a row acknowledges it. A done row drops to ambient so it stops competing for your attention, but the agent keeps running and the row stays an agent row — nothing is killed and nothing is cleared. New activity re-promotes it. A blocked row needs no dismissal at all: answering the agent makes its next update supersede the interrupt on its own.

It survives restarts

Attention lives on the host, in the daemon, not in the app. Quitting Sox, upgrading it, or restarting the daemon does not erase what your agents reported — reopening re-reads the same state. A detached session with no window open still accumulates attention, so an agent that blocks while you are away is still blocked, and still at the top, when you come back.

Turning it on

Shells appear in the roster with no setup. Agent state does not: blocked, error, and done come only from the Sox plugin running inside the agent, so a session without it renders working/idle and nothing else — present in the list, but flat.

Installing the plugin is per harness and per host. See Agent sessions, which also covers the statusline feed that adds token and cost figures to each row.

After the release-channel switch, the standard Claude Code and Codex Git marketplaces load plugin bytes from the newest fully published Sox release. Existing Git installs need a marketplace update; installs from a local checkout need the one-time, scope-preserving migration in Agent sessions. Statusline settings are user-owned and need their Sox script path changed once to the stable launcher under plugin data. sox-doctor reports the exact path and flags a checkout, marketplace-clone, or versioned-cache path.

Sox does not answer agents for you. The roster is a router: it tells you which session needs a human and takes you there. You act in the real terminal.