Skip to content

ACP bridge subprocesses are never reaped after an agent turn completes, leaking memory across all harnesses #4577

Description

@adroitandroid

Describe the bug
When an agent (regardless of which ACP-compatible harness backs it) completes a turn and replies in a channel, the subprocess pool spawned to service that turn is not terminated or reaped. Each single message-to-agent interaction leaves behind roughly 10 idle child processes under the corresponding buzz-acp bridge, permanently, with no cleanup even minutes after the agent has finished responding and gone idle (confirmed via CPU dropping to ~0% and staying there).

This is harness-agnostic — reproduced identically with two different backing harnesses (a Claude-based agent and an opencode-based agent) in the same session. In each case, exactly one message produced exactly 10 leftover subprocesses that never exited.

Because this leak is per-message rather than per-session, it compounds continuously during normal use. Over roughly an hour of typical activity (multiple messages across multiple agents), leaked subprocess count reached ~88 processes consuming ~2.2GB RSS and ~2,100 open file descriptors. In a smaller two-message controlled test, 20 leaked processes alone accounted for ~3.78GB RSS and 627 open FDs — the two harnesses differ substantially in per-process footprint (~43MB/process for one harness's subprocesses vs. ~330MB/process for the other's), but both leak at the same ~10-processes-per-turn rate.

The resulting memory/FD pressure correlates with (and is the most likely cause of) several user-visible symptoms during sustained use:

  • The relay WebSocket connection intermittently dropping, prompting a manual reconnect
  • Sent/received messages failing to render in the UI
  • Agents appearing unresponsive to new messages

Steps to reproduce

  1. Launch Buzz desktop and note the baseline set of buzz-acp bridge child processes (e.g. ps -eo pid,ppid,command | awk '$2==<buzz-desktop-pid>') — this is a stable pool with no further children yet.
  2. Send a single message to any agent and wait for its reply to appear in the channel.
  3. Inspect the children of that agent's buzz-acp bridge process (pgrep -P <bridge-pid>) — observe ~10 new subprocesses spawned.
  4. Wait several minutes after the agent's reply is visible in the UI. Observe via ps -o pid,%cpu,stat,etime that these subprocesses drop to near-0% CPU (idle) but remain alive indefinitely — they are never terminated.
  5. Repeat with a different backing harness for a different agent — same ~10-subprocess leak pattern occurs.
  6. Repeat step 2 across multiple agents/messages over an extended session — leaked process count, RSS, and FD usage grow linearly and without bound.

Expected behavior
Once an agent turn completes and the reply has been delivered, all subprocesses spawned to service that turn should be terminated and reaped by their parent buzz-acp bridge. Steady-state process/memory/FD usage should return close to baseline between turns, regardless of which ACP harness backs the agent, and regardless of how many messages are sent over a session's lifetime.

Version and platform

  • Buzz version: 0.5.3 (0.5.3)
  • OS: macOS

Logs / additional context
Quantified from a controlled two-message test (one message per harness, one harness-A agent + one harness-B agent):

  • 20 leaked subprocesses total (10 per harness), all confirmed idle (~0% CPU) for 10+ minutes after their agent's reply was posted
  • ~3.78GB combined RSS across just these 20 processes
  • 627 open file descriptors across just these 20 processes
  • System-wide memory compressor usage rose to 9.6GB with under 1GB "unused" RAM remaining, from this test alone

From the original (uncontrolled) session that surfaced the symptom: ~88 leaked processes, ~2.2GB RSS, ~2,100 FDs, accumulated over roughly an hour of normal multi-agent usage, including at least one process that became a <defunct> zombie never reaped by its parent. Fully quitting and relaunching the Buzz desktop app clears all leaked processes and temporarily resolves the disconnects/unresponsive-agent symptoms — until the leak reaccumulates with continued use.


Filed by Claude on behalf of the reporter.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions