DEV Community

Vikas Sah
Vikas Sah

Posted on

TIL: One Claude Code Hook That Auto-Approves Safe Commands and Kills the 'Yes' Fatigue

You know the drill. Claude Code wants to read a file. You click Yes. It wants to grep something. Yes. List a directory. Yes. Check git status. Yes. Forty-seven times a day, you're a human rubber stamp.

Here's a hook that auto-approves read-only operations. In my testing, it cuts daily approval prompts by roughly 60%.

The Hook

Add this to .claude/settings.json in your project root:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Read|Grep|Glob",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/approve-readonly.sh"
          }
        ]
      },
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/approve-safe-bash.sh"
          }
        ]
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Create .claude/hooks/approve-readonly.sh:

#!/bin/bash
# Auto-approve all read-only tools (Read, Grep, Glob)
# These tools cannot modify files — safe to skip the prompt

jq -n '{
  hookSpecificOutput: {
    hookEventName: "PreToolUse",
    permissionDecision: "allow",
    permissionDecisionReason: "Read-only operation auto-approved"
  }
}'
Enter fullscreen mode Exit fullscreen mode

Create .claude/hooks/approve-safe-bash.sh:

#!/bin/bash
# Auto-approve safe bash commands, prompt for everything else

INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')

# Safe read-only commands — extend this list as needed
SAFE_PATTERNS="^(ls|cat|head|tail|grep|rg|find|wc|git status|git log|git diff|git branch|pwd|echo|which|type|file|stat)( |$)"

if echo "$COMMAND" | grep -qE "$SAFE_PATTERNS"; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "allow",
      permissionDecisionReason: "Safe read-only bash command"
    }
  }'
else
  # Fall through to normal permission prompt
  exit 0
fi
Enter fullscreen mode Exit fullscreen mode

Make them executable:

chmod +x .claude/hooks/approve-readonly.sh .claude/hooks/approve-safe-bash.sh
Enter fullscreen mode Exit fullscreen mode

Why It Works

Claude Code fires a PreToolUse event before every tool invocation. Your hook intercepts it, inspects the tool name and input, and returns a JSON decision: "allow", "deny", or nothing (falls through to the normal prompt).

The matcher field is a regex. "Read|Grep|Glob" catches all three read-only tools. The Bash hook checks the actual command against a safe-command regex — ls, cat, git status, etc. The ( |$) at the end matches commands both with arguments (ls -la) and without (ls). Anything not on the list still triggers the normal approval prompt.

Bonus: Share It With Your Team

Commit .claude/settings.json and the hooks directory to your repo. Every developer who clones the project gets the same auto-approve behavior. No per-machine setup.

If you want these hooks globally (all projects), put the config in ~/.claude/settings.json instead. For personal tweaks that won't affect teammates, use .claude/settings.local.json — same format, automatically gitignored.

Gotcha: The regex uses ( |$) to avoid partial matches — so rm in rmarkdown won't accidentally match a rm safe-pattern. Keep destructive commands (rm, mv, chmod, docker) off the list.

Top comments (0)