Fixed
Severe subprocess leak — orphaned orchestrator stacks (#30)
Every plugin session leaked its entire stack (HTTP backend, multiprocessing.Manager daemon, resource_tracker, frontend) to launchd. Over many sessions these accumulated into the hundreds, exhausting RAM and pinning swap (40+ GB observed), causing system-wide freezes. Fixed at the source in start_plugin.sh and the backend:
- No more
execof the STDIO proxy — it now runs as a child, so the launcher shell and its cleanuptrapstay alive to tear the backend/frontend down on session end (with explicit0<&0so the MCP protocol still reads stdin). - Process-tree teardown —
cleanup()terminates each managed tree (TERM → grace → KILL), reaching themultiprocessingchildren thatuv runindirection previously hid. - Startup reaping —
reap_orphansreclaims processes left by previous sessions that died uncleanly (e.g. SIGKILL), scoped across all installed versions, so updating the plugin also cleans up orphans left by the version it replaced. Usesps -wwto avoid Linux command-column truncation. - Direct venv launch — the venv is synced up front (
uv sync) and the backend/proxy run.venv/bin/pythondirectly, so the launcher shell is their parent. - Parent-death watchdog — if the backend is orphaned to PID 1 (hard kill where no trap can run), it self-terminates, running the lifespan teardown that shuts down the Manager daemon.
Upgrade note
On first launch after updating to 1.8.2, the plugin automatically reaps any orphaned processes left by older versions — no manual pkill needed.
Tests
- Unit tests for the bash helpers (
kill_tree,reap_orphans, including cross-version reaping). - Integration tests booting the real backend and asserting zero orphans under both SIGTERM and SIGKILL.
Full changelog: https://github.com/barkain/madrox/blob/main/CHANGELOG.md