block / block/buzz

Bug Report: managed-agents.json corruption, duplicate entries, and empty model dropdown when using custom ACP harnesses

Open
#5,155 1 comment 0 reactions 0 assignees View on GitHub
bug
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

# Bug Report: managed-agents.json corruption, duplicate entries, and empty model dropdown when using custom ACP harnesses

## Environment
- **OS**: macOS 15.x (Apple Silicon, M3 Pro / M5 Pro)
- **Buzz Desktop**: latest (build from `xyz.block.buzz.app`)
- **ACP harness**: custom SSH wrapper pointing to `acp-claude-code` (v0.8.0) on remote VPS
- **ACP library**: `@zed-industries/agent-client-protocol@0.1.2`

## Issue 1: managed-agents.json gets corrupted when changing a harness

**Steps to reproduce:**
1. Open Buzz Desktop
2. Go to an agent's settings → change its harness (e.g., from `buzz-acp` to `acp-claude-wrapper`)
3. Close and reopen Buzz

**Expected:** Only the selected agent's `acp_command` field changes. All other agents and entries remain intact.

**Actual:** Buzz overwrites the entire `managed-agents.json` file. In practice, this causes:
- **Duplicate entries** — every harness change adds a new entry for the same agent without removing the old one. After a few changes, each agent appears twice (or more) in the JSON array.
- **Lost entries** — if the file is rewritten with incomplete data, agents vanish entirely. Buzz then dumps the file to `managed-agents.json.invalid` and all agents disappear.

**Evidence:** The file at `~/Library/Application Support/xyz.block.buzz.app/agents/managed-agents.json` accumulates duplicate entries. After switching harnesses on 4 agents, the file contained 32 entries for 16 unique agents. Each duplicate had a different `slug` UUID but the same `display_name`, causingBuzz to either pick the wrong one or reject the config.

**Root cause (likely):** Buzz's harness-switch handler rewrites the entire agent store on every change. It does not deduplicate by `display_name` or `slug`, and it does not validate that all existing entries are preserved. The write is also not atomic — if interrupted, the file can be truncated to 0 bytes.

**Workaround attempted:** Locking the file with `chflags uchg` prevents Buzz from overwriting it, but then Buzz can't write its own runtime state (PID tracking, last-started timestamps), which causes agents to fail to spawn with `commit managed-agents.json: Operation not permitted (os error 1)`.

---

## Issue 2: Empty model dropdown when using a custom ACP harness

**Steps to reproduce:**
1. Set an agent's harness to a custom ACP bridge (e.g., `acp-claude-wrapper` → `acp-claude-code` on VPS)
2. Open the agent's settings in Buzz Desktop
3. Click the model dropdown

**Expected:** The dropdown shows available models from the ACP bridge (e.g., Claude models via OpenRouter or Anthropic).

**Actual:** The dropdown is empty. No models are listed.

**Root cause:** The ACP library (`@zed-industries/agent-client-protocol@0.1.2`) has a hardcoded switch statement in `AgentSideConnection` that only recognizes 6 methods: `initialize`, `session/new`, `session/load`, `authenticate`, `session/prompt`, `session/cancel`. Any other method (including `claude/listModels` or `/models`) hits `default: throw RequestError.methodNotFound(method)`.

The compiled code at `node_modules/@zed-industries/agent-client-protocol/dist/acp.js` lines 57-60:
```javascript
case schema.AGENT_METHODS.session_cancel: {
const validatedParams = schema.cancelNotificationSchema.parse(params);
return agent.cancel(validatedParams);
}
default:
throw RequestError.methodNotFound(method);

There is no mechanism for agents to advertise or expose available models. The protocol schema (`schema.json`) has no `listModels` or `models` method defined. This is a protocol-level gap — the ACP spec doesn't define a model-listing endpoint, so no ACP agent can expose models to the client.

**Impact:** Any custom ACP harness (Claude Code, Codex, custom LLM bridges) cannot show models in Buzz Desktop. Users are forced to either:
- Use Buzz's built-in harnesses (which have their own model lists hardcoded)
- Manually configure model IDs in agent settings (if the field exists)

---

## Issue 3: Agents spawn and immediately die (~5 seconds) when using a custom ACP harness

**Steps to reproduce:**
1. Set an agent's harness to a custom ACP bridge
2. Click "Spawn" or send a message to the agent in Buzz Desktop
3. Watch the agent status

**Expected:** Agent spawns, connects to the ACP bridge, and stays alive until the conversation ends or is manually stopped.

**Actual:** Agent spawns, establishes the initial ACP handshake (initialize succeeds), then dies within ~5 seconds. The agent shows as "connected" briefly, then disappears from the sidebar.

**Evidence from logs** (`~/Library/Application Support/xyz.block.buzz.app/agents/logs/`):
- The `buzz-acp` process logs show `buzz-acp starting: ... agent_cmd= ...` then `connected to relay` then `presence set to online`
- After ~5 seconds, the agent process exits without any error message in the logs
- No `buzz-acp stopped` log line — the process is killed externally (by Buzz) after the ACP handshake fails on a subsequent request

**Root cause (likely):** After the `initialize` call succeeds, Buzz Desktop sends a follow-up request (possibly `claude/listModels`, `session/new`, or a heartbeat) that the ACP bridge doesn't handle. The bridge either:
- Returns `Method not found` (because the ACP library rejects unknown methods)
- Crashes because the request payload doesn't match expected schema
- Times out waiting for a response that never comes

Buzz interprets this as a connection failure and kills the agent process.

**Note:** This is partially caused by Issue 2 (no model listing) — if Buzz can't get the model list, it may send an invalid follow-up request that the bridge can't handle.

---

## Issue 4: managed-agents.json is not written atomically

**Steps to reproduce:**
1. Modify `managed-agents.json` while Buzz is running
2. Check the file size and content

**Expected:** Writes are atomic (write to temp file, then rename). No partial writes.

**Actual:** Buzz writes directly to the file. If the write is interrupted (crash, signal, disk full), the file is left in a partial state. In practice, the file has been observed truncated to 0 bytes after a harness switch, causing all agents to vanish.

**Evidence:** Backup files exist at:
- `managed-agents.json.bak` (32 entries, from before the corruption)
- `managed-agents.json.bak.0` through `.bak.2` (previous backups)
- `managed-agents.json.invalid` (Buzz's rejection of a bad config)
- `managed-agents.json.json` (another backup variant)

The presence of multiple backup variants suggests Buzz is trying to recover from write failures but the recovery mechanism is incomplete.

---

## Summary of Required Fixes

| Priority | Issue | Fix |
|----------|-------|-----|
| P0 | managed-agents.json corruption on harness change | Write atomically (temp file + rename). Deduplicate entries by `display_name`. Preserve existing entries on rewrite. Validate all entries have required fields (`relay_url`, `acp_command`, etc.) before writing. |
| P0 | Empty model dropdown | Add a protocol-level model listing mechanism. Either: (a) define a `listModels` method in the ACP schema, or (b) have Buzz query the agent's advertised capabilities and fall back to a configurable model list. |
| P1 | Agents die after ~5 seconds | Improve error handling in the ACP connection lifecycle. When a follow-up request fails, log the error and retry instead of killing the agent. Add a minimum connection timeout before declaring the agent dead. |
| P1 | File locking conflict | Remove the `uchg` lock workaround. Instead, use proper file locking (flock) or atomic writes so Buzz can manage its own state without external interference. |
| P2 | Duplicate entries accumulate | Add a deduplication step on config load. If duplicate `display_name` entries exist, keep the one with the most complete data (most fields populated) and remove the rest. |

---

## Additional Context

- The ACP protocol is designed for code editors (VS Code, JetBrains, Zed) connecting to coding agents. Buzz Desktop is using it as a general-purpose agent harness, which exposes gaps in the protocol (no model listing, no heartbeat, no graceful degradation on connection loss).
- The `@zed-industries/agent-client-protocol` package is deprecated (renamed to `@agentclientprotocol/sdk` v0.4.5). The current version (0.1.2) has known limitations that haven't been addressed.
- Users with custom ACP harnesses (especially Claude Code via subscription credits) are effectively locked out of model selection and reliable agent spawning. This is a significant usability barrier for the intended use case.

---

## Workarounds (for reference)

1. **Don't change harnesses after initial setup** — once configured, avoid UI harness switches to prevent config corruption.
2. **Use Telegram instead of Buzz when Mac is closed** — the VPS Telegram gateway runs independently and doesn't require the Mac to be awake.
3. **Manually fix managed-agents.json** — if it gets corrupted, restore from `managed-agents.json.bak` and re-apply harness mappings. (We have a Python script for this: `python3 /tmp/fix_sobel.py`.)

---

Paste that into the Buzz Desktop GitHub repo issues page. The repo URL is `https://github.com/block/buzz` — verify and adjust if it's different.

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.