From bdfd18e5ab8cda83adbc4d27be4c5c6c7bc441a7 Mon Sep 17 00:00:00 2001 From: Skye Gill Date: Sat, 25 Jul 2026 20:48:29 +0100 Subject: [PATCH 1/2] feat(buzz-acp): add auto permission mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit claude-agent-acp advertises six values for the `mode` config option, with `auto` first in the list: auto | default | acceptEdits | plan | dontAsk | bypassPermissions `PermissionMode` omitted `auto`, so `BUZZ_ACP_PERMISSION_MODE=auto` failed clap validation at startup and the value could never reach the adapter. `auto` is the mode a headless harness actually wants. buzz-acp auto-approves every `session/request_permission` with `allow_once`, which is correct — there is no human at a terminal to answer one — but it means `default` and `acceptEdits` are indistinguishable from `bypassPermissions` in practice, and the only modes that constrain anything are `plan` and `dontAsk`, which are too restrictive for real work. `auto` keeps a classifier reviewing each tool call without requiring a prompt to be answered. Tests cover the wire string, `is_default`, and both the kebab-case and camelCase parse paths, matching the existing per-mode coverage. Signed-off-by: Skye Gill --- crates/buzz-acp/src/config.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/crates/buzz-acp/src/config.rs b/crates/buzz-acp/src/config.rs index a38d6faa14..4cfccbef8c 100644 --- a/crates/buzz-acp/src/config.rs +++ b/crates/buzz-acp/src/config.rs @@ -115,6 +115,7 @@ impl std::fmt::Display for RespondTo { /// `configId: "mode"` (e.g. `claude-agent-acp`). /// /// - `default` — agent's built-in behaviour (permission requests per tool call). +/// - `auto` — auto-approve with a classifier reviewing each tool call. /// - `acceptEdits` — auto-approve file edits, still ask for other tools. /// - `bypassPermissions` — skip the permission flow entirely. /// - `dontAsk` — never prompt; reject anything that would require permission. @@ -124,6 +125,13 @@ pub enum PermissionMode { /// Agent default — permission requests per tool call. #[value(alias = "default")] Default, + /// Auto-approve tool calls, with a classifier reviewing each one. + /// + /// Unlike `bypassPermissions`, which skips the permission flow outright, + /// `auto` keeps a safety check in the loop without needing a human to + /// answer a prompt — the shape a headless harness actually wants. + #[value(alias = "auto")] + Auto, /// Auto-approve file edits, still ask for other tools. #[value(alias = "acceptEdits")] AcceptEdits, @@ -144,6 +152,7 @@ impl PermissionMode { pub fn as_wire_str(&self) -> &'static str { match self { Self::Default => "default", + Self::Auto => "auto", Self::AcceptEdits => "acceptEdits", Self::BypassPermissions => "bypassPermissions", Self::DontAsk => "dontAsk", @@ -428,7 +437,8 @@ pub struct CliArgs { /// /// Defaults to `bypassPermissions` which skips the per-tool-call /// permission flow. Set to `default` to restore the agent's built-in - /// behaviour. + /// behaviour, or `auto` to keep a classifier reviewing each tool call + /// without requiring a human to answer a prompt. #[arg( long, env = "BUZZ_ACP_PERMISSION_MODE", @@ -2111,6 +2121,7 @@ channels = "ALL" #[test] fn test_permission_mode_wire_strings() { assert_eq!(PermissionMode::Default.as_wire_str(), "default"); + assert_eq!(PermissionMode::Auto.as_wire_str(), "auto"); assert_eq!(PermissionMode::AcceptEdits.as_wire_str(), "acceptEdits"); assert_eq!( PermissionMode::BypassPermissions.as_wire_str(), @@ -2123,6 +2134,7 @@ channels = "ALL" #[test] fn test_permission_mode_is_default() { assert!(PermissionMode::Default.is_default()); + assert!(!PermissionMode::Auto.is_default()); assert!(!PermissionMode::BypassPermissions.is_default()); assert!(!PermissionMode::AcceptEdits.is_default()); assert!(!PermissionMode::DontAsk.is_default()); @@ -2173,6 +2185,7 @@ channels = "ALL" use clap::ValueEnum; let cases = [ ("default", PermissionMode::Default), + ("auto", PermissionMode::Auto), ("accept-edits", PermissionMode::AcceptEdits), ("bypass-permissions", PermissionMode::BypassPermissions), ("dont-ask", PermissionMode::DontAsk), @@ -2195,6 +2208,7 @@ channels = "ALL" use clap::ValueEnum; let cases = [ ("default", PermissionMode::Default), + ("auto", PermissionMode::Auto), ("acceptEdits", PermissionMode::AcceptEdits), ("bypassPermissions", PermissionMode::BypassPermissions), ("dontAsk", PermissionMode::DontAsk), From 0cace0905b082e9e30799b9d35f06ca07bd168cb Mon Sep 17 00:00:00 2001 From: Skye Gill Date: Thu, 30 Jul 2026 09:31:07 +0100 Subject: [PATCH 2/2] ci: retrigger required checks Co-authored-by: Skye Gill Signed-off-by: Skye Gill