A Claude Code PreToolUse hook that intercepts potentially destructive shell commands before they execute — giving you a safety net without slowing down normal workflows.
| Category | Commands caught |
|---|---|
| Git | push --force, reset --hard, clean -f, checkout ., restore ., branch -D |
| Filesystem | rm -rf, rm -fr |
| SQL | DROP TABLE, DROP DATABASE, TRUNCATE TABLE |
| Disk | dd if=..., mkfs.* |
When a match is found, Claude Code receives a block decision with a plain-English explanation. Claude will surface the message to the user, who can then run the command directly in a terminal if it was intentional.
No matches = zero overhead. The hook exits immediately for all non-Bash tool calls.
- bash 3+ (ships with macOS and all major Linux distros)
- python3 (for JSON parsing — also ships by default)
- No external packages, no network access
# 1. Copy the hook to your Claude Code hooks directory
mkdir -p ~/.claude/hooks
curl -o ~/.claude/hooks/git-guardian.sh \
https://raw.githubusercontent.com/sirhappy/git-guardian/main/git-guardian.sh
chmod +x ~/.claude/hooks/git-guardian.shThen add the hook to your ~/.claude/settings.json (global) or .claude/settings.json (per-project):
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/git-guardian.sh"
}
]
}
]
}
}Remove the hook entry from settings.json. Optionally delete the script:
rm ~/.claude/hooks/git-guardian.shClaude Code calls the hook before every Bash tool execution, passing a JSON payload on stdin:
{
"tool_name": "Bash",
"tool_input": { "command": "git push --force origin main" }
}The hook checks the command field against a list of ERE patterns. On a match it outputs:
{
"decision": "block",
"reason": "git-guardian blocked a potentially destructive command..."
}On no match it exits 0, which lets the command proceed normally.
Open git-guardian.sh and edit the PATTERNS array. Each entry is "REGEX|Label" — the label appears in the block message shown to the user.
This hook makes no network requests.
MIT