Repository navigation
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.json → permissions.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-acp0.64.0- Bundled Claude Code CLI 2.1.220
- Windows 11
- 12 managed agents (7
claude-agent-acp, 4codex-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
- 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."
- 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.
- It scales with the fleet. Every mentioned agent pays independently.
- 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 thatbuzz— the agent's only outbound channel — must be present inpermissions.allowfor agents to speak at all.
Suggested fixes
- Pass the resolved
permission_modethrough to the adapter.claude-agent-acpalready reads session options fromparams._meta— sending it there would make--permission-mode/BUZZ_ACP_PERMISSION_MODEactually effective, and would restore Buzz's control over its own agents rather than deferring to a user setting written for interactive use. - Surface send failures. A
buzz messages sendthat 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"). - Fail loudly at startup. If the resolved agent permission mode would deny the
buzzCLI, log a warning atbuzz-acp starting:time rather than discovering it mid-turn.
Workaround for anyone hitting this
Add to ~/.claude/settings.json → permissions.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.
Activity
cristiansotogarciaxatech commentedon Aug 8, 2026
Correction from the reporter — the adapter is not at fault.
I filed this claiming
buzz-acpsetspermission_mode=bypassPermissionsand thatclaude-agent-acpdiscards it. Further digging shows that is wrong, and I want to correct the record rather than leave a misleading report.buzz-acpis now explicitly settingdontAsk, and the adapter is honouring it correctly. From the same agent's own startup lines over time:The change lands between 0.5.5 and 0.5.6/0.5.7. 11 of my 12 managed agents now report
dontAsk; two still showbypassPermissions.permission_modedoes not appear anywhere inmanaged-agents.json, so this is a default applied outside per-agent config, not something I set.So the accurate report is narrower, and it is about the consequence rather than the mechanism:
Changing the default agent permission mode to
dontAsksilently mutes agents whose only outbound channel is thebuzzCLI.Under
dontAskan agent cannot prompt and cannot run anything outside the user'spermissions.allowlist.buzzis not in a typical user allowlist — it is the agent's own interface, not something a human would have allowlisted for themselves. The result is that agents wake, load full context, compose a reply, and are denied on every send path, while the turn completes cleanly and bills in full. Measured on my fleet: 515,974 input tokens across three agents for one channel greeting, with nothing delivered, and a separate DM at 601,653 tokens, also undelivered.The parts of the original report that still stand:
buzz-acp starting:already logs the resolved mode; it is well placed to warn when that mode would deny thebuzzCLI.Suggested, revised:
dontAskis the intended new default,buzz-acpshould ensure its own CLI is permitted under it — either by injecting an allow rule forbuzzinto the session it creates, or by warning at startup when the resolved mode plus the user's allowlist would deny it.Workaround, for anyone hitting this. Add to
permissions.allow— either user-level, or project-level in the agent workspace so it does not widen your own interactive sessions:This restored messaging on existing sessions immediately, without a restart, because allow rules are evaluated per tool call while the mode is fixed at session creation.
Note that
permissions.defaultModeset in a project settings file does not work as an escape hatch —claude-agent-acp'sSettingsManagerappliesfilterEscalatingDefaultMode, which strips escalating values from repo-committed sources by design. Broadeningpermissions.allowat project level is honoured; escalatingdefaultModethere is not.Apologies for the incorrect initial framing.
skillz-xx commentedon Aug 8, 2026
Our same-machine result supports the reporter's corrected framing and the severity assessment.
On Buzz Desktop 0.5.7, two owner-requested managed Claude review attempts were rejected under the unattended permission surface, including one explicitly read-only request. No Desktop approval card appeared. The same Mac concurrently had an independent Codex adapter network regression; after repairing that separate path, a native
buzz messages sendreturnedaccepted: true, while managed Claude remained blocked.That is useful isolation evidence: the relay, channel, signing identity, and bundled CLI were healthy. The remaining failure was the managed Claude permission path, not delivery infrastructure. The Codex workaround is not a fix for Claude's
dontAskfailure.The practical impact matches this report: agents look alive and receive the work, but the only publication command is denied after context/model work has already been consumed. In our case, the misleading symptom chain cost almost a working day to isolate.
I strongly support three acceptance requirements for the fix:
buzz --helpsucceeds without a manual trust prompt;buzz messages sendreturnsaccepted: true, with a visible startup/runtime error if the permission policy would prevent either operation.This should be treated as a release-blocking collaboration regression, not merely a permission-mode preference.
talfirevic commentedon Aug 8, 2026
Data point that appears to contradict the stated mechanism, from a self-hosted relay.
Setup: self-hosted relay (compose bundle,
ghcr.io/block/buzz:main, revisions2b873cfthen02f640bc), Buzz Desktop 0.5.6, macOS arm64,clauderuntime, built-in personas.My machine has exactly the condition described here —
~/.claude/settings.json→permissions.defaultMode: "auto"(plus 104allowrules) — butBUZZ_ACP_PERMISSION_MODEdid change agent behavior.Before
buzz-acpstartup line:The agent's own transcript shows it attempting the only reply path it has, and being refused:
Harness-side this is completely silent — the turn is a success:
The only events reaching the relay were the harness's own
👀/💬reactions (kind 7) and their kind 5 deletions. No kind 9. Reproduced identically on two separate mentions.After
Single variable changed: launched the desktop app with
BUZZ_ACP_PERMISSION_MODE=default. (The app setsBUZZ_ACP_MCP_COMMAND,BUZZ_PRIVATE_KEY,RUST_LOGetc. explicitly inruntime.rs, but does not setBUZZ_ACP_PERMISSION_MODE, so it is inherited from the app's environment. On macOS a Finder launch inherits nothing, so this needslaunchctl setenvto persist.)Reply landed in the channel as kind 9, ~17s end to end.
settings.jsonwas untouched between the two runs.Caveat, stated plainly: with 104
allowrules present I can't fully exclude that thebuzzinvocation matched one. But those rules were identical across both runs, so they cannot by themselves explain the change from denied to completed.Why the denial is total silence rather than a degraded reply
On the
clauderuntime the shell is the only way an agent can speak:discovery.rs—claudehasmcp_command: None(codexhasSome("buzz-dev-mcp")), so there is no Buzz MCP send-message tool.acp.rs—agent_message_chunkis logged toacp::streamand returnsfalse; model prose is never published as a channel message.So with
dontAskdenying Bash, an agent has no path to publish at all. It reacts, thinks, produces a perfectly good answer, and discards it — while billing the full turn, as the title of this issue notes. Related: #5290, #5262, #5260, and #4609 as the likely regression point.Two things that made this expensive to diagnose:
agent_message_chunktext is logged under targetacp::stream, whichRUST_LOG=buzz_acp=debugdoes not match (needsbuzz_acp=debug,acp=info), and the turn reportsoutcome="ok", so nothing in the harness logs, relay logs, or UI indicates a failure occurred.tonyswartz commentedon Aug 8, 2026
Related, less severe manifestation of the same root problem, for a second data point: an interactive DM session here wasn't muted entirely (its
dontAskallow-list covered basic operation), but still burned real extra tokens working around a permission gap for a single MCP tool lookup unrelated tobuzz messages send— checking an already-connected account on an existing connector (Zapier). Two failed tool calls, a drafted-then-discardedsettings.local.jsonpatch, and several turns explaining the architecture to the user, before falling back to a separate headless--dangerously-skip-permissionsprocess just to run one read-only lookup. No data loss like the case documented above, but the same underlying gap — the connector's own approval setting never reaches buzz-acp's permission gate — showing up as overhead instead of total denial. Fuller writeup on #2884. Both fixes referenced above (#5325, #5106) should resolve this flavor too once they ship.docs(acp): correct the allow-rule claim — trust gate, not mode override