commit 66b0899c939c475d09d85c51651a3e4e666d2e78
parent e9f56cf554c7434d4582d941033ce1ea58d5fe75
Author: William Casarin <jb55@jb55.com>
Date: Thu, 5 Feb 2026 09:49:28 -0800
feat(dave): expand auto-accept rules for read-only bash commands
Add common read-only commands (grep, rg, find, ls, cat, head, tail, etc.)
and git read-only commands (status, log, diff, show, branch) to auto-accept.
This reduces friction for exploratory operations while keeping write
operations requiring explicit approval.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat:
1 file changed, 110 insertions(+), 0 deletions(-)
diff --git a/crates/notedeck_dave/src/auto_accept.rs b/crates/notedeck_dave/src/auto_accept.rs
@@ -58,11 +58,58 @@ impl Default for AutoAcceptRules {
AutoAcceptRule::SmallEdit { max_lines: 2 },
AutoAcceptRule::BashCommand {
prefixes: vec![
+ // Cargo commands
"cargo build".into(),
"cargo check".into(),
"cargo test".into(),
"cargo fmt".into(),
"cargo clippy".into(),
+ "cargo run".into(),
+ "cargo doc".into(),
+ // Read-only bash commands
+ "grep ".into(),
+ "grep\t".into(),
+ "rg ".into(),
+ "rg\t".into(),
+ "find ".into(),
+ "find\t".into(),
+ "ls ".into(),
+ "ls\t".into(),
+ "ls\n".into(),
+ "cat ".into(),
+ "cat\t".into(),
+ "head ".into(),
+ "head\t".into(),
+ "tail ".into(),
+ "tail\t".into(),
+ "wc ".into(),
+ "wc\t".into(),
+ "file ".into(),
+ "file\t".into(),
+ "stat ".into(),
+ "stat\t".into(),
+ "which ".into(),
+ "which\t".into(),
+ "type ".into(),
+ "type\t".into(),
+ "pwd".into(),
+ "tree ".into(),
+ "tree\t".into(),
+ "tree\n".into(),
+ "du ".into(),
+ "du\t".into(),
+ "df ".into(),
+ "df\t".into(),
+ // Git read-only commands
+ "git status".into(),
+ "git log".into(),
+ "git diff".into(),
+ "git show".into(),
+ "git branch".into(),
+ "git remote".into(),
+ "git rev-parse".into(),
+ "git ls-files".into(),
+ "git describe".into(),
],
},
AutoAcceptRule::ReadOnlyTool {
@@ -206,4 +253,67 @@ mod tests {
let input = json!({ "command": " cargo build" });
assert!(rules.should_auto_accept("Bash", &input));
}
+
+ #[test]
+ fn test_grep_bash_auto_accept() {
+ let rules = default_rules();
+ let input = json!({ "command": "grep -rn \"pattern\" /path" });
+ assert!(rules.should_auto_accept("Bash", &input));
+ }
+
+ #[test]
+ fn test_rg_bash_auto_accept() {
+ let rules = default_rules();
+ let input = json!({ "command": "rg \"pattern\" /path" });
+ assert!(rules.should_auto_accept("Bash", &input));
+ }
+
+ #[test]
+ fn test_find_bash_auto_accept() {
+ let rules = default_rules();
+ let input = json!({ "command": "find . -name \"*.rs\"" });
+ assert!(rules.should_auto_accept("Bash", &input));
+ }
+
+ #[test]
+ fn test_git_status_auto_accept() {
+ let rules = default_rules();
+ let input = json!({ "command": "git status" });
+ assert!(rules.should_auto_accept("Bash", &input));
+ }
+
+ #[test]
+ fn test_git_log_auto_accept() {
+ let rules = default_rules();
+ let input = json!({ "command": "git log --oneline -10" });
+ assert!(rules.should_auto_accept("Bash", &input));
+ }
+
+ #[test]
+ fn test_git_push_not_auto_accept() {
+ let rules = default_rules();
+ let input = json!({ "command": "git push origin main" });
+ assert!(!rules.should_auto_accept("Bash", &input));
+ }
+
+ #[test]
+ fn test_git_commit_not_auto_accept() {
+ let rules = default_rules();
+ let input = json!({ "command": "git commit -m \"test\"" });
+ assert!(!rules.should_auto_accept("Bash", &input));
+ }
+
+ #[test]
+ fn test_ls_auto_accept() {
+ let rules = default_rules();
+ let input = json!({ "command": "ls -la /tmp" });
+ assert!(rules.should_auto_accept("Bash", &input));
+ }
+
+ #[test]
+ fn test_cat_auto_accept() {
+ let rules = default_rules();
+ let input = json!({ "command": "cat /path/to/file.txt" });
+ assert!(rules.should_auto_accept("Bash", &input));
+ }
}