block / block/buzz

Proposal: headless relay-side agent-team supervisor for server-only deployments

Open
#5,529 1 comment 0 reactions 0 assignees View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.