Created
March 12, 2026 09:55
-
-
Save AlCalzone/8000c84e0b398cefee7ff8b208bba987 to your computer and use it in GitHub Desktop.
Prevent Claude from using bash commands over its built-in tools
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # ~/.claude/hooks/enforce-builtin-tools.sh | |
| # | |
| # PreToolUse hook: blocks file-inspection shell commands and redirects | |
| # Claude to use the appropriate built-in Claude Code tool instead. | |
| # | |
| # Install: | |
| # mkdir -p ~/.claude/hooks | |
| # cp enforce-builtin-tools.sh ~/.claude/hooks/ | |
| # chmod +x ~/.claude/hooks/enforce-builtin-tools.sh | |
| # | |
| # Then add the hook config to ~/.claude/settings.json (see settings.json). | |
| INPUT=$(cat) | |
| COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty') | |
| # Exit early if no command was found in the input | |
| if [[ -z "$COMMAND" ]]; then | |
| exit 0 | |
| fi | |
| # Strip leading whitespace and get the first token (the binary being called) | |
| TRIMMED=$(echo "$COMMAND" | sed 's/^[[:space:]]*//') | |
| BINARY=$(echo "$TRIMMED" | awk '{print $1}') | |
| # Helper: deny with a message sent back to Claude via stderr | |
| deny() { | |
| echo "$1" >&2 | |
| exit 2 | |
| } | |
| case "$BINARY" in | |
| find) | |
| deny "Use the Glob tool to find files by pattern (e.g. '**/*.ts'), or the Grep tool to search by content. Do not use the 'find' shell command." | |
| ;; | |
| grep|rg|ag|ack) | |
| deny "Use the Grep tool to search file contents. Do not use '${BINARY}' as a shell command." | |
| ;; | |
| ls|dir) | |
| deny "Use the LS tool to list directory contents. Do not use '${BINARY}' as a shell command." | |
| ;; | |
| cat) | |
| deny "Use the Read tool to read file contents. Do not use 'cat'." | |
| ;; | |
| head|tail) | |
| deny "Use the Read tool to read file contents (it supports line offsets). Do not use '${BINARY}'." | |
| ;; | |
| less|more|bat) | |
| deny "Use the Read tool to read file contents. Do not use '${BINARY}'." | |
| ;; | |
| sed) | |
| # Allow sed when used in a pipeline (likely transforming output, not reading files directly). | |
| # Block it when it's the first command and appears to be reading a file. | |
| if echo "$COMMAND" | grep -qE '(^|\|)\s*sed\s.+\s\S+\.[a-zA-Z]+'; then | |
| deny "Use the Read tool to read file contents, and the Edit or MultiEdit tool to make changes. Do not use 'sed' to read or modify files directly." | |
| fi | |
| ;; | |
| awk) | |
| # Same heuristic as sed: block when it looks like awk is reading a file directly. | |
| if echo "$COMMAND" | grep -qE '(^|\|)\s*awk\s.+\s\S+\.[a-zA-Z]+'; then | |
| deny "Use the Read tool to read file contents. Do not use 'awk' to read files directly." | |
| fi | |
| ;; | |
| wc) | |
| # wc -l on a file is often used as a substitute for knowing file size before reading. | |
| # Allow wc in pipelines, block direct file reads. | |
| if echo "$COMMAND" | grep -qE '^wc\s'; then | |
| deny "Use the Read tool to inspect file contents. Do not use 'wc' to read files directly." | |
| fi | |
| ;; | |
| esac | |
| # All other Bash commands are allowed | |
| exit 0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| // other settings | |
| "hooks": { | |
| "PreToolUse": [ | |
| { | |
| "matcher": "Bash", | |
| "hooks": [ | |
| { | |
| "type": "command", | |
| "command": "~/.claude/hooks/enforce-builtin-tools.sh" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment