fix(runtime): sweep node wrapper processes hosting managed agent shims#1296
Merged
Conversation
codex-acp and claude-agent-acp are npm shims — their OS process name is `node`, not the binary name. When the Buzz app restarts, buzz-acp dies and the node wrapper is reparented to launchd (PPID=1). The orphan reaper never killed it because `process_belongs_to_us()` checked the process name against `KNOWN_AGENT_BINARIES` — `"node"` was not in the list. The node wrapper kept the native codex-acp binary alive as its child, and that child had no `network_proxy` flags (spawned before the update), causing relay failures. Add `KNOWN_SCRIPT_INTERPRETERS = ["node"]` and `name_matches_interpreter()`. Extend both macOS and Linux `process_belongs_to_us()` to return `true` for interpreter names so the sweep proceeds to `process_has_buzz_marker()`, which gates on `BUZZ_MANAGED_AGENT` ownership. Unrelated node processes are never swept — zero false positives. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
process_belongs_to_us() now returns true for node processes (interpreter support added in the previous commit). Three call sites acted on that result without a subsequent process_has_buzz_marker() check: - kill_stale_tracked_processes: would kill any node process whose PID collided with a stale agent record - sync_managed_agent_processes: would skip clearing runtime_pid for a foreign node process, leaving a stale PID that blocks respawn - start_managed_agent_process: would skip respawning if a foreign node process happened to hold the recorded PID Add instance_id: &str to kill_stale_tracked_processes and sync_managed_agent_processes; thread current_instance_id(app) through all 11 call sites. Add process_has_buzz_marker() to all three check sites. The sweep paths (collect_same_instance_orphans, reap_dead_instance_agents) already gated on the marker — this brings the record-management paths to the same standard. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Import use-lists in agent_models.rs, agents.rs, lib.rs, and restore.rs were wrapped at slightly different column boundaries after the instance_id threading changes. No logic changes — pure formatting. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
interpreter-orphan reaper adds ~30 lines to runtime.rs (new constant, helper, and marker-guard threading); instance_id threading adds ~8 lines to lib.rs. Both files already had approved overrides; bumping to actual line count. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
tellaho
pushed a commit
that referenced
this pull request
Jun 25, 2026
…ebar * origin/main: fix(sidebar): non-selectable channel names + copy/leave context menu actions (#1260) fix(runtime): sweep node wrapper processes hosting managed agent shims (#1296) fix(buzz-agent): follow symlinks when discovering skill directories (#1295) chore: add grab-emoji.sh to register Slack emoji in Buzz (#1292) Fix cross-pod membership notification fanout (#1291) fix(buzz-acp): strengthen agent communication rules in base prompt (#1293) chore(release): release Buzz Desktop version 0.3.34 (#1289) feat(desktop): refresh Agents tab live on inbound relay sync (#1256) fix(buzz-acp): inject Codex network allowlist for relay hostname at spawn time (#1287) Co-authored-by: Taylor Ho <taylorkmho@gmail.com> Signed-off-by: Taylor Ho <taylorkmho@gmail.com> # Conflicts: # desktop/src-tauri/src/commands/agent_models.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
codex-acpandclaude-agent-acpare npm shims — their OS process name isnode, not the binary name. When the Buzz app restarts, buzz-acp dies and the node wrapper is reparented to launchd (PPID=1). The orphan reaper never killed it becauseprocess_belongs_to_us()checked the process name againstKNOWN_AGENT_BINARIES—"node"was not in the list.The node wrapper kept the native codex-acp binary alive as its child, and that child had no
network_proxyflags (spawned before the update), causing relay network failures for Thufir and any other codex-based agent after an app update.Fix
Commit 1 — interpreter recognition:
Add
KNOWN_SCRIPT_INTERPRETERS = ["node"]and aname_matches_interpreter()helper. Extend both macOS (proc_name()) and Linux (/proc/comm+/proc/exe) variants ofprocess_belongs_to_us()to returntruefor interpreter names, so the sweep proceeds toprocess_has_buzz_marker().Commit 2 — marker check at record-management paths:
Three call sites used
process_belongs_to_us()without a subsequentprocess_has_buzz_marker()check. Withnodenow returningtruefromprocess_belongs_to_us(), these sites could falsely act on unrelated node processes (dev servers, build tools) whose PID happened to collide with a stale agent record:kill_stale_tracked_processes: would kill the foreign processsync_managed_agent_processes: would skip clearingruntime_pid, blocking respawnstart_managed_agent_process: would skip respawning the agentAdd
instance_id: &strtokill_stale_tracked_processesandsync_managed_agent_processes; threadcurrent_instance_id(app)through all 11 call sites. Addprocess_has_buzz_marker()at all three check sites. The sweep paths already gated on the marker — this brings the record-management paths to the same standard.Why not add
"node"toKNOWN_AGENT_BINARIES? That would sweep all node processes on the machine regardless of ownership — catastrophic false positives.Future-proofing
KNOWN_SCRIPT_INTERPRETERSis a named constant. Addingpython3,deno, orbunsupport if those become harness runtimes is a one-liner.Tests
4 new unit tests in
runtime/tests.rs:name_matches_known_binary_rejects_node— guards against accidentally addingnodetoKNOWN_AGENT_BINARIESname_matches_interpreter_accepts_node—nodeis recognized as an interpretername_matches_interpreter_rejects_unknown—python3,deno,bundo not matchname_matches_interpreter_rejects_node_prefix—node_modules,nodejs,node-gypdo not match (exact equality required)All 40
managed_agents::runtimetests pass.