Skip to content

buzz-acp: --permission-mode is set but never reaches the agent; agents are silently muted while still billing full turns #5303

Description

Summary

buzz-acp resolves and logs permission_mode=bypassPermissions, but that value is never applied to the claude-agent-acp session. The adapter derives its permission mode solely from the user's ~/.claude/settings.jsonpermissions.defaultMode. On a machine where that is "auto", every managed agent runs headless in a mode that denies any non-allowlisted tool and cannot prompt — so buzz messages send is refused.

The failure is silent and expensive. Agents wake normally, load their full session, compose a reply, get denied on every send path, and end the turn. The channel stays empty, tokens are billed in full, and nothing is logged as an error at the Buzz layer.

Environment

  • Buzz Desktop 0.5.7 (also reproduced on 0.5.6)
  • @agentclientprotocol/claude-agent-acp 0.64.0
  • Bundled Claude Code CLI 2.1.220
  • Windows 11
  • 12 managed agents (7 claude-agent-acp, 4 codex-acp, 1 native)

Evidence

1. buzz-acp resolves the mode correctly. Every agent's startup line reports it:

buzz-acp starting: ... idle_timeout=900s max_turn=7200s agents=10 subscribe=Mentions
  context_limit=12 max_turns_per_session=0 memory=true permission_mode=bypassPermissions

2. The adapter ignores it. claude-agent-acp dist/acp-agent.js:

const permissionMode = resolvePermissionMode(
    settingsManager.getSettings().permissions?.defaultMode, this.logger);

The session's mode comes from settings.json. The ACP-side permission_mode is not consulted. PERMISSION_MODE_ALIASES maps auto → "auto", so a user with "defaultMode": "auto" gets auto regardless of what Buzz asked for.

3. Result at runtime. Three agents mentioned in one channel message, all denied on every path:

07:13:15  Bash: buzz messages get --channel f5c91c95-...
          → "Permission to use Bash has been denied because Claude Code is
             running in don't ask mode."
07:13:20  PowerShell: buzz messages get ...        → denied
07:13:34  PowerShell: (the composed reply)         → denied
07:13:42  agent: "I'm blocked from replying ... the `buzz` CLI is the only way
                  I can send channel messages."

A second agent independently tried Bash → PowerShell → buzz messages send directly, and was denied all three times.

4. Cost of the silent failure. One halo @AgentA @AgentB @AgentC in a channel:

Agent Requests Input tokens Output Delivered?
A 4 210,565 1,645 no
B 4 188,688 2,284 no
C (codex) 5 116,721 1,367 no
Total 13 515,974 5,296 none

A single DM to one agent cost 601,653 input tokens and also failed to deliver.

5. Timeline. Successful buzz messages send invocations per day, from the agents' own transcripts:

Aug 4: 229    Aug 5: 254    Aug 6: 7    Aug 7: 2    Aug 8: 4 (all denied)

No permission settings changed on this machine across that window (verified against a byte-identical backup: 536 allow rules, defaultMode: auto, zero deny). What changed underneath was the bundled CLI. The adapter carries this comment, which suggests mode semantics moved around then:

// Claude Code 2.1.200 renamed the "default" mode to "Manual" and accepts
// `"defaultMode": "manual"` in settings.json; honor the same alias here.

Why this is worse than a normal permission error

  1. It is invisible in Buzz. The turn completes cleanly. There is no error surfaced in the channel, no delivery failure, and nothing in the agent log to distinguish "had nothing to say" from "was forbidden to speak."
  2. It bills in full. Half a million tokens for one greeting, with zero output delivered. On a fixed subscription this consumes the plan allowance directly.
  3. It scales with the fleet. Every mentioned agent pays independently.
  4. The user's own config is a trap they cannot reasonably discover. permissions.defaultMode: "auto" is a sensible interactive setting. Nothing indicates it silently governs headless managed agents, or that buzz — the agent's only outbound channel — must be present in permissions.allow for agents to speak at all.

Suggested fixes

  1. Pass the resolved permission_mode through to the adapter. claude-agent-acp already reads session options from params._meta — sending it there would make --permission-mode / BUZZ_ACP_PERMISSION_MODE actually effective, and would restore Buzz's control over its own agents rather than deferring to a user setting written for interactive use.
  2. Surface send failures. A buzz messages send that is refused at the permission layer should produce a visible error in the channel or agent status, not a clean exit. This is closely related to [Bug] buzz-acp reply delivery is implicit — Sonnet-class agents answer in session text and every reply is silently dropped #2698 ("tokens are billed, chat stays empty").
  3. Fail loudly at startup. If the resolved agent permission mode would deny the buzz CLI, log a warning at buzz-acp starting: time rather than discovering it mid-turn.

Workaround for anyone hitting this

Add to ~/.claude/settings.jsonpermissions.allow:

"Bash(buzz:*)",
"PowerShell(buzz:*)"

Narrow, and it restores agent messaging without weakening permissions elsewhere. Setting defaultMode to bypassPermissions also works but applies to the user's own interactive Claude Code sessions on the same machine, which is a much larger blast radius.

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