Skip to content

feat(acp): host-wide session pool with fleet slot cap, idle close and DM auto-publish - #7273

Open
gruming wants to merge 2 commits into
block:mainfrom
gruming:feat/acp-session-pool
Open

feat(acp): host-wide session pool with fleet slot cap, idle close and DM auto-publish#7273
gruming wants to merge 2 commits into
block:mainfrom
gruming:feat/acp-session-pool

Conversation

@gruming

@gruming gruming commented Sep 3, 2026

Copy link
Copy Markdown

Summary

Memory on a host running many buzz-acp harnesses scales with live ACP sessions (for claude-agent-acp, one claude process plus its MCP servers each), not with harness count. This PR adds a connection-pool style cap and idle reclamation so a fleet of 25 harnesses fits on one 32 GB host, plus a DM safety net.

  • --fleet-slots N / --fleet-slot-dir (BUZZ_ACP_FLEET_SLOTS, BUZZ_ACP_FLEET_SLOT_DIR): host-wide cap on live sessions shared by every harness. One flock(2)ed file per slot, so the kernel releases a dead harness's slots. Work that finds every slot held waits in the channel queue rather than failing (crates/buzz-acp/src/fleet.rs, new).
  • --session-idle-close S (BUZZ_ACP_SESSION_IDLE_CLOSE): close a channel session, releasing its slot, after S seconds without a turn; the next event in that channel starts a fresh session.
  • --min-agents M (BUZZ_ACP_MIN_AGENTS): start only M subprocesses eagerly; the rest of --agents spawn on demand when every started agent is busy and channels are waiting, and shut down again after the idle bound.
  • --dm-autopublish (BUZZ_ACP_DM_AUTOPUBLISH, default false): in DM channels, when a turn ends without the agent having run buzz messages send, post the agent's trailing reply text as a top-level message so the human never gets silence. Skipped when the agent already posted in that turn (relay lookup, fails closed); channel turns are unaffected.

All new flags — the pool flags and --dm-autopublish — default off, so existing deployments are unchanged. README documents the flags and the fleet example (--agents 8 --min-agents 1 --fleet-slots 20 --session-idle-close 600).

Key decisions / trade-offs

  • Slots are flocked files rather than a shared counter so a crashed harness can never leak capacity. This is Unix-only; fleet.rs refuses to start with --fleet-slots > 0 where flock is unavailable.
  • Idle close is per channel session, not per agent, so a busy channel keeps its context while quiet ones return their slot.
  • DM auto-publish is deliberately fail-closed: any doubt (self-post lookup error/timeout, text empty, agent already sent) means no extra post.

Relation to #6732 (per-thread sessions)

  • Rebased onto current main (40220d5). A "live session" is keyed by SessionScope, so under the default --session-policy channel behavior is per channel; under thread policy fleet slots and idle close apply per thread session automatically (a busy thread keeps its context, quiet ones return their slot). On-demand sizing counts distinct pending scopes.
  • Nothing upstream was dropped or refactored; conflicts were resolved by re-keying our bookkeeping from channel Uuid to SessionScope.

Deferred / follow-up

  • Opening as a draft until the rebased build has run in our fleet for a while. Happy to split the DM auto-publish part into its own PR if preferred.
  • --session-idle-close / --fleet-slots help text still says "channel session"; accurate under the default policy, could be softened to "session" if thread policy becomes the default.

Related issue

Addresses the memory growth in #2961 (per-channel sessions never released) and #4577 (subprocesses never reaped) by bounding and reclaiming live sessions host-wide. No existing PR found for a fleet-wide session cap; #7173 and #5982 touch idle/rotation handling but not a shared cap.

Testing

  • cargo fmt -p buzz-acp --check, cargo clippy -p buzz-acp --all-targets -- -D warnings: clean.
  • cargo test -p buzz-acp: 924 passed, 0 failed (plus 9 integration tests in tests/pool_lifecycle_state.rs; doc-tests: 0), on the rebased commit (new unit tests for fleet slots, min-agents resolution, idle close and dm_autopublish_wanted). Note: CliArgs tests read BUZZ_ACP_* from the environment like the existing ones, so run them with those variables unset.
  • Not run: just ci (this host has no GTK/WebKitGTK toolchain for the desktop crates); only the buzz-acp crate was touched.
  • Production canary: 25 harnesses on one 32 GB Ubuntu 24.04 host with the flags above since 2026-09-03 (KST), on the pre-rebase build; the rebased build is being canaried next. live sessions capped at 20, idle sessions reclaimed after 10 min, on-demand agents spawn and retire as expected. DM auto-publish verified on one harness for the "agent already posted → skipped, no duplicate" path; the "trailing text posted" path is covered by unit tests only so far.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is 4b0744d7f3161d9f045dd67a73e014e4440c2b47...800e694b268500df00b6089e96c066315b28a4b3.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review 800e694b268500df00b6089e96c066315b28a4b3 to authorize a new review.
Any previous review applies only to its recorded range.

… DM auto-publish

Memory on a multi-harness host scales with live ACP sessions (each is a
`claude` process plus its MCP servers), not with harness count. This adds a
connection-pool style cap and idle reclamation so 25 harnesses fit on one host:

- `--fleet-slots N` / `--fleet-slot-dir`: host-wide cap on live sessions,
  shared by every harness via one flock(2)ed file per slot, so the kernel
  releases a dead harness's slots. Work that finds every slot held waits in
  the channel queue instead of failing.
- `--session-idle-close S`: close a channel session (releasing its slot)
  after S seconds without a turn; the next event starts a fresh session.
- `--min-agents M`: start only M subprocesses eagerly; the rest of `--agents`
  spawn on demand when every started agent is busy and shut down again
  after the idle bound.
- `--dm-autopublish` (default on): in DM channels, when a turn ends without
  the agent having published, post its trailing reply text so the human
  never gets silence. Skipped when the agent already posted in that turn;
  channel turns are unaffected.

All flags default off (autopublish on) so existing deployments are unchanged.
README documents the flags and a 25-harness / 32 GB example.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: gruming <tnalsl1984@naver.com>
@gruming
gruming force-pushed the feat/acp-session-pool branch from 2b5fd9b to 5727813 Compare September 3, 2026 06:38
Align the DM auto-publish flag with the pool flags: every new flag in this
change now defaults off, so a deployment that passes none of them behaves
exactly like upstream. Set BUZZ_ACP_DM_AUTOPUBLISH=true (or
--dm-autopublish true) to enable it. README default updated and the CLI
default test now covers the flag.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: gruming <tnalsl1984@naver.com>
@gruming
gruming marked this pull request as ready for review September 4, 2026 06:30
@gruming
gruming requested a review from a team as a code owner September 4, 2026 06:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant