-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathauto-approve-safe.sh
More file actions
executable file
·85 lines (71 loc) · 3.38 KB
/
Copy pathauto-approve-safe.sh
File metadata and controls
executable file
·85 lines (71 loc) · 3.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#!/bin/bash
# PermissionRequest hook: Auto-approve safe operations
# - Bash commands: docker, make, yarn, git (all operations)
# - Read/Write in .claude/ directories (user global or project-local)
# - All MCP tools (if configured, they're trusted)
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
# ============================================================
# Auto-approve all MCP tools (configured = trusted)
# ============================================================
if [[ "$TOOL_NAME" == mcp__* ]]; then
echo '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}'
exit 0
fi
# ============================================================
# Auto-approve Read/Write/Edit in .claude directories
# ============================================================
if [[ "$TOOL_NAME" == "Read" || "$TOOL_NAME" == "Write" || "$TOOL_NAME" == "Edit" ]]; then
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# Match ~/.claude/ or any .claude/ in project paths (relative or absolute)
if [[ "$FILE_PATH" == *"/.claude/"* || "$FILE_PATH" == "$HOME/.claude/"* || "$FILE_PATH" == ".claude/"* ]]; then
echo '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}'
exit 0
fi
fi
# ============================================================
# Auto-approve safe Bash commands
# ============================================================
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
# Skip if no command (not a Bash tool call)
if [[ -z "$COMMAND" ]]; then
exit 0
fi
# Patterns considered safe to auto-approve
# Docker commands (compose, exec, build, logs, ps)
if echo "$COMMAND" | grep -qE '^(docker compose |docker-compose )'; then
echo '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}'
exit 0
fi
# Make targets
if echo "$COMMAND" | grep -qE '^make\b'; then
echo '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}'
exit 0
fi
# Yarn/npm run (not install/add)
if echo "$COMMAND" | grep -qE '^(yarn |npm )(run |test |lint |build |dev |start )'; then
echo '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}'
exit 0
fi
# All git/gh operations (workflow rules in CLAUDE.md control when to commit/push)
if echo "$COMMAND" | grep -qE '^(git|gh)\b'; then
echo '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}'
exit 0
fi
# Scripts in ~/.claude/scripts/ (trusted user scripts)
if echo "$COMMAND" | grep -qE "(^|&& )(\\.?~/?\\.claude/scripts/|bash .*/\\.claude/scripts/)"; then
echo '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}'
exit 0
fi
# Read-only commands (find, cat, head, tail, wc, tree, ls, stat, file)
if echo "$COMMAND" | grep -qE '^(find |cat |head |tail |wc |tree |ls |stat |file )'; then
echo '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}'
exit 0
fi
# Commands with cd prefix
if echo "$COMMAND" | grep -qE '^cd [^;|&]+ && (docker compose |make |yarn |npm run|git )'; then
echo '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}'
exit 0
fi
# No decision - let the normal permission dialog show
exit 0