commit da8c8e643a347ad0719590ec922180e81db40b0b
parent c83dd63f61205357624a678b767d81acacd6d74a
Author: William Casarin <jb55@jb55.com>
Date: Wed, 28 Jan 2026 19:10:26 -0800
dave: auto-accept small edits (2 lines or less)
Reduces confirmation friction for trivial edits by automatically
approving Edit tool calls that modify 2 lines or less on both old
and new sides. Write operations always require manual approval.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat:
2 files changed, 27 insertions(+), 0 deletions(-)
diff --git a/crates/notedeck_dave/src/backend/claude.rs b/crates/notedeck_dave/src/backend/claude.rs
@@ -1,4 +1,5 @@
use crate::backend::traits::AiBackend;
+use crate::file_update::FileUpdate;
use crate::messages::{
CompactionInfo, DaveApiResponse, PendingPermission, PermissionRequest, PermissionResponse,
SessionInfo, SubagentInfo, SubagentStatus, ToolResult,
@@ -286,6 +287,16 @@ async fn session_actor(
// Handle permission requests (they're blocking the SDK)
Some(perm_req) = perm_rx.recv() => {
+ // Auto-accept small edits (2 lines or less)
+ const AUTO_ACCEPT_MAX_LINES: usize = 2;
+ if let Some(file_update) = FileUpdate::from_tool_call(&perm_req.tool_name, &perm_req.tool_input) {
+ if file_update.is_small_edit(AUTO_ACCEPT_MAX_LINES) {
+ tracing::debug!("Auto-accepting small edit ({} lines max): {}", AUTO_ACCEPT_MAX_LINES, file_update.file_path);
+ let _ = perm_req.response_tx.send(PermissionResult::Allow(PermissionResultAllow::default()));
+ continue;
+ }
+ }
+
// Forward permission request to UI
let request_id = Uuid::new_v4();
let (ui_resp_tx, ui_resp_rx) = oneshot::channel();
diff --git a/crates/notedeck_dave/src/file_update.rs b/crates/notedeck_dave/src/file_update.rs
@@ -75,6 +75,22 @@ impl FileUpdate {
}
}
+ /// Returns true if this is an Edit that changes at most `max_lines` lines
+ /// on both the old and new side. Never returns true for Write operations.
+ pub fn is_small_edit(&self, max_lines: usize) -> bool {
+ match &self.update_type {
+ FileUpdateType::Edit {
+ old_string,
+ new_string,
+ } => {
+ let old_lines = old_string.lines().count();
+ let new_lines = new_string.lines().count();
+ old_lines <= max_lines && new_lines <= max_lines
+ }
+ FileUpdateType::Write { .. } => false,
+ }
+ }
+
/// Compute the diff lines for this update
pub fn compute_diff(&self) -> Vec<DiffLine> {
match &self.update_type {