Patch release. Two independent problems: Grok started the wrong model, and a session's startup cost was heavy enough to stop other sessions starting.
Fixed
Grok spawned the wrong model and failed (#34)
Two causes, and a policy change so it cannot recur.
- The model flag was wrong. Grok documents the short form only (
grok -p "Hello" -m my-model), but the harness inherited--model, which the CLI did not pick up. The requested model was silently ignored and the CLI ran its own default — nothing errored, which is why this was hard to spot. - The pinned default was not a real model id.
grok-build-0.1does not exist; per the xAI docs the model behind Grok Build isgrok-4.5. With the flag ignored, the fallback landed on an older model that not every account can use.
No harness pins a model any more. When the caller does not name one, Madrox passes no model flag and the CLI uses its own current default. A pinned id goes stale the moment a vendor ships a new model, and a stale id breaks spawning rather than degrading. An explicit model= is still forwarded verbatim, and a default can still be pinned deliberately via default: in config/models.yaml or MADROX_MODEL_<HARNESS>. This reverses the "defaults always applied" behaviour introduced in 1.9.0, and applies to Claude and Codex as well as Grok.
spawn_grok() -> grok --always-approve
spawn_grok(model="grok-4.5") -> grok --always-approve -m grok-4.5
spawn_codex() -> codex --dangerously-bypass-approvals-and-sandbox
spawn_codex(model="gpt-5.5") -> codex --dangerously-bypass-... --model gpt-5.5
Session startup no longer blocks other sessions (#33)
With many concurrent sessions, later launches died during the MCP handshake — leaving a log directory and session_ports.env but no backend.log and nothing on stderr to explain it.
- The dashboard starts on demand.
start_plugin.shlaunched a Next.js development server for every session whether or not the dashboard was ever opened. It now starts on the firstget_dashboard_urlcall, spawned as a child of the proxy so the existing tree-killing cleanup still reaps it. uv syncno longer blocks the handshake. Every session synced the samePLUGIN_ROOT, and uv takes a project lock, so concurrent launches serialised behind one another. The call was guarded against failure but not against blocking. It is now skipped entirely whenuv.lockandpyproject.tomlare unchanged since the last successful run, and bounded by a watchdog when it does run (MADROX_SYNC_TIMEOUT, default 20s — macOS ships notimeout(1)).- Spawning survives a deleted working directory. The spawn start method records
os.getcwd()for the child, so once the directory a session was launched from was removed — routine, since sessions run in throwaway worktrees — everymultiprocessing.Manager/Processspawn died withFileNotFoundErrorfromget_preparation_data.
Correction to v1.8.2
The "severe subprocess leak" described in the 1.8.2 notes overstates what was wrong. On investigation the cleanup trap and reap_orphans work correctly — the processes observed were live sessions' stacks, each parented by a live claude process, not orphans. The real problem was the weight of a per-session stack, which the dashboard and uv sync changes above address. The 1.8.2 hardening is still worth having; the diagnosis attached to it was wrong.
Upgrade
/plugin marketplace update barkain-plugins
/plugin update madrox
Note that the dashboard now starts on first use rather than at session start, so the first time you open it will be slower while next dev boots.
Known limitations
- Grok is still unverified end to end. Both the original harness and this fix rest on the published xAI docs — no
grokCLI was available to run it against. - Instances are still suspended after 30 minutes of no messages, even while actively working, because
last_activityonly advances on send/receive. Pre-existing; not addressed here.
Full changelog: https://github.com/barkain/madrox/blob/main/CHANGELOG.md