Proposal: headless relay-side agent-team supervisor for server-only deployments
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
## Problem
Managed Agents only work when Buzz Desktop and the agent share a machine — Desktop spawns the harness process itself and gives each managed agent its own `nest` workspace with a `repos_dir` symlink into a real project checkout (`desktop/src-tauri/src/managed_agents/repos.rs`).
That falls short for a common relay deployment shape: **relay + agents run on a headless Linux server, humans connect from a separate machine's Buzz Desktop app.** In that shape there's no "local" for Managed Agents to use — Desktop can't spawn a process on a server it isn't running on, and it can't offer a folder picker for a filesystem it can't see.
We hit this directly while standing up a multi-agent team (orchestrator + coder + reviewer + writer) on a server, driven from Desktop on a separate machine. Two gaps had no supported answer:
1. No way to say "this channel's agents should work in directory X" when the agents don't run next to Desktop.
2. No way for a headless (non-Managed) agent to become `@`-mentionable (tracked separately, PR up already: #5528).
## Proposed solution
A new crate, `crates/buzz-supervisor` — a long-running binary (same shape as `buzz-acp`) that's the server-side analog of Managed Agents:
- Watches channels for a `workdir:` convention in the channel `description` (the only per-channel free-text field the CLI round-trips reliably today — `topic`/`purpose` are separate `kind:9002` command events that `channels get` doesn't merge back in).
- On a match whose path resolves inside an operator-configured allowed-roots list: generates a fresh keypair per configured role, registers relay + channel membership, publishes each role's `kind:10100` profile (see #5528), and spawns a `buzz-acp` process per role rooted at that directory.
- Self-heals dead processes, tears down channels that get archived/deleted.
- **Off by default** — requires an explicit `--relay-url` (no default, unlike `buzz-acp`) and at least one `--allowed-root`, so it can never run unconfigured or with an unbounded filesystem scope by accident.
We already have a working implementation validated end-to-end against a live relay (real `claude-agent-acp` sessions, real channel provisioning/teardown/self-healing). Opening this issue first per the contributing guide before the PR, since it's a new crate/feature — happy to adjust direction based on feedback before/while it's reviewed.
## Open questions
- Is a separate `crates/buzz-supervisor` binary the right shape, or should this instead be a mode of `buzz-acp` itself (`buzz-acp --supervise`) that manages a pool of child `buzz-acp` processes?
- Where should the allowed-roots security policy be configured — supervisor-local config file (current approach), or a relay-side deployment setting (so it's enforced even if the supervisor's own config is compromised)?
- Longer term, should channel creation get a first-class `workdir` field (Desktop UI input, its own `kind:9007` tag, DB column) instead of overloading `description`? Description works today but isn't the "real" interface.
## Also worth knowing
While validating this, we found and fixed two real bugs along the way (now baked into the implementation): a state-persistence bug where an error partway through provisioning left no state file, causing infinite retry storms that leaked keys/memberships on every poll cycle; and a TOML `[[roles]]` array-of-tables footgun that silently dropped trailing top-level config keys.
Contributor guide
Assessment
This issue has not been assessed yet.