Update the agent CLIs from Settings

An update button beside every agent’s version in Settings → General. It installs the latest release in place — no Space rebuild — and restarts the sessions running what it replaced, after saying which ones and what they are doing.

Screens rendered from the real SettingsView against a fake backend; the data is synthetic, the markup and CSS are the app’s.

The list, idle

One control per row, in its own column at the end. A circular arrow means this CLI can be installed from here; a struck-through one means it cannot, and says why on hover or focus. The column asks a single question — can this row be updated in place? — so it never collides with the ⓘ one column to its left, which is only ever about missing credentials. The covered set is derived from the CLI registry in server/src/config.js, so a CLI added later gets one of the two marks on its own.

Alignment. Both states now occupy the same 22px box, so the column is straight whichever mark a row shows. It was not: the live arrow was a button with a 22px hit area while the struck one was a bare 13px glyph that shrink-wrapped and sat flush right, putting its centre 4.5 CSS px (9 device px at 2×) further right. Measured off this screenshot the way the report was — dark-pixel bounding box per row — the seven x-centres are now identical at 1278.50 device px, spread 0.00. The SVGs were not touched; the containers were. The remaining vertical difference is 0.5 device px (a quarter of a CSS pixel) of ink, because the slash reaches 0.2 units lower in the viewBox than the arc does.

The list, idle

Why a row cannot be updated here

fx and Hermes did not arrive through npm — a prebuilt binary and a vendor install script onto its own Python venv. The struck arrow carries that reason and the thing to do instead, on hover and on keyboard focus; the mark kept its tabIndex and its explanation through the alignment change, which the screenshot run asserts rather than assumes. Note Hermes: it has no version at all, which is a different problem from not being updatable. hermes --version works (it reports 0.21.3 on the production Space); it is the slowest of the startup probes, and on a cold Python venv over the FUSE-mounted home it can miss the 30s boot-time pass and fill in on a later poll. Pre-existing, and untouched by this change.

Why a row cannot be updated here

The warning, attached to the row it is about

Pressing the arrow does not install anything — it opens this, under that row only. Updating Codex restarts the Codex sessions and nothing else, so the warning names them. Counting is not enough: a waiting pane costs nothing to restart, a working one loses whatever it is mid-way through, so the two are separated in the sentence and marked on each line. The confirm button repeats the number it is about to restart. A working session makes this louder; it does not block the update.

The warning, attached to the row it is about

While one is installing

The request that starts a run answers immediately and the panel polls; npm install -g is tens of seconds. Only one runs at a time — they share one npm prefix — so every other arrow is disabled rather than clickable into a race, and the row doing the work says what it is doing.

While one is installing

A finished row

The result stays under its own row: both versions, and every pane it restarted with the state that pane was in. Claude Code was run earlier and was already current — already the latest and updated are deliberately different words, and a CLI whose version did not move restarts nothing. Updating one row does not erase what another reported.

A finished row

Failures, reported as failures

Three ways this goes wrong, on three rows. Gemini: npm failed, and npm’s own words are shown. OpenClaw: npm reported success and the binary would not say its version — that is a broken install, not an update. Codex: installed fine, but one pane would not exit in time, so that restart is marked failed and the pane is named as still running the old binary. Nothing here can pass for a finished update.

Failures, reported as failures

At phone width

The row keeps its shape at 400px: dot, icon, name, version, state, and the update column. The warning and the buttons wrap; nothing overflows sideways.

At phone width