Reports › Contract docs › release-channels

RobotDiagnostics' Stable / Preview channels

2026-10-23 (Zach: "Please add the stable preview switch"). The channels come from the shared runtime, ~/stable_preview_switcher (its docs/CONTRACT.md is the interface; its skill/SKILL.md is how to use it). This file holds the WHY for stable-preview.json, which JSON cannot carry.

What there is

Where What it runs
Stable http://127.0.0.1:8820/ the runtime's Stable server: a pinned copy of io_diagnostics/web/ from the last Make Stable, /api/ forwarded to the release's own cli.py tray --port 8822 — the dashboard backend AND the top-bar chip, one process
Preview http://127.0.0.1:8821/ cli.py serve straight from the main checkout (main as it is now), restarted by the runtime whenever its Python or a plugin declaration changes
Agent lanes sps dev in a worktree the same serve from that worktree, on a lane port (5400–5499)

Operate it from anywhere (the dock and the chip do the same):

sps --root ~/io-diagnostics status
sps --root ~/io-diagnostics promote

sps --root ~/io-diagnostics rollback (press again to roll forward) and sps --root ~/io-diagnostics stop --all change what Zach uses: Zach's calls, never an agent's.

stable-preview.json, key by key

The login service

The tray used to be the whole service (cli.py tray --port 8820 from a pinned detached worktree). Now the runtime owns Stable, tray included, and the service only brings Stable up at login:

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStartPre=/bin/sh -c 'while ss -ltnH "sport = :8820" | grep -q . && ! curl -sf -o /dev/null http://127.0.0.1:8820/__sps/health; do sleep 15; done'
ExecStart=/usr/bin/python3 ~/.local/share/stable-preview-switcher/runtime/sps.py --root ~/io-diagnostics open --no-open
ExecStop=/usr/bin/python3 ~/.local/share/stable-preview-switcher/runtime/sps.py --root ~/io-diagnostics stop
TimeoutStartSec=infinity
Restart=on-failure
RestartSec=15

Proof (2026-10-23)

In a scratch clone (passive plugins only, SPS_STATE_HOME / SPS_PORTS scratch, SPS_NO_WINDOW=1, the tray on a private Xvfb display and session bus): headless Chrome read the chip in its shadow root on Stable (match, grey Open Preview), committed on main (behind, blue Open Preview), pressed Open Preview (this window moved to Preview: Make Stable), pressed Make Stable (match), pressed Roll Stable Back ("Stable was rolled back", Reload, then behind); the app's API answered through Stable's /api/ proxy (26 devices) and a page write passed the page gate there; a watched .py edit restarted Preview; sps dev served a lane with the chip. Server side: tests/test_release_channels.py.