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.
| Tier | State | Means |
|---|---|---|
| interrupt | blocked | Waiting on you — a tool permission prompt, most often. |
| interrupt | error | The agent hit a terminal error. |
| review | done | The turn finished. The agent is still running, waiting for input. |
| watch | stale | Working, but quiet for longer than expected. |
| ambient | working | Active. Nothing needed. |
| ambient | idle | At 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.