|
|
4 days ago | |
|---|---|---|
| .. | ||
| README.md | 1 month ago | |
| check-mail.sh | 4 days ago | |
| dangerous-cmd-warn.sh | 1 month ago | |
| post-edit-format.sh | 1 month ago | |
| pre-commit-lint.sh | 1 month ago | |
Claude Code hooks allow you to run custom scripts at key workflow points.
| Hook Script | Type | Purpose |
|---|---|---|
pre-commit-lint.sh |
PreToolUse | Auto-lint staged files before commit (JS/TS, Python, Go, Rust, PHP) |
post-edit-format.sh |
PostToolUse | Auto-format files after Write/Edit (Prettier, Ruff, gofmt, rustfmt) |
dangerous-cmd-warn.sh |
PreToolUse | Block destructive commands (force push, rm -rf, DROP TABLE, etc.) |
Add hooks to .claude/settings.json or .claude/settings.local.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
"bash hooks/dangerous-cmd-warn.sh $TOOL_INPUT",
"bash hooks/pre-commit-lint.sh $TOOL_INPUT"
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": ["bash hooks/post-edit-format.sh $FILE_PATH"]
}
]
}
}
| Hook | Trigger | Use Case |
|---|---|---|
PreToolUse |
Before tool execution | Validate inputs, security checks |
PostToolUse |
After tool execution | Run tests, linting, notifications |
Notification |
On specific events | Alerts, logging |
Stop |
When Claude stops | Cleanup, summaries |
Detect dangerous patterns before execution:
#!/bin/bash
# hooks/security-check.sh
# Detects: eval, exec, os.system, pickle, SQL injection patterns
INPUT="$1"
PATTERNS=(
"eval("
"exec("
"os.system("
"subprocess.call.*shell=True"
"pickle.loads"
"__import__"
"rm -rf /"
"DROP TABLE"
"; DROP"
)
for pattern in "${PATTERNS[@]}"; do
if echo "$INPUT" | grep -q "$pattern"; then
echo "SECURITY WARNING: Detected potentially dangerous pattern: $pattern"
exit 1
fi
done
exit 0
Run linter after file edits:
#!/bin/bash
# hooks/post-edit.sh
FILE="$1"
EXT="${FILE##*.}"
case "$EXT" in
ts|tsx|js|jsx)
npx eslint --fix "$FILE" 2>/dev/null
;;
py)
ruff check --fix "$FILE" 2>/dev/null
;;
md)
# Optional: markdown lint
;;
esac
Run tests after code changes:
#!/bin/bash
# hooks/post-test.sh
FILE="$1"
# Only run for source files
if [[ "$FILE" == *"/src/"* ]]; then
# Find and run related test
TEST_FILE="${FILE/src/tests}"
TEST_FILE="${TEST_FILE/.ts/.test.ts}"
if [[ -f "$TEST_FILE" ]]; then
npm test -- "$TEST_FILE" --passWithNoTests
fi
fi
Ensure commit messages follow convention:
#!/bin/bash
# hooks/commit-msg.sh
MSG="$1"
# Conventional commits pattern
PATTERN="^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .{1,50}"
if ! echo "$MSG" | grep -qE "$PATTERN"; then
echo "ERROR: Commit message doesn't follow conventional commits format"
echo "Expected: type(scope): description"
echo "Example: feat(auth): add login endpoint"
exit 1
fi
Full hooks configuration:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": ["bash hooks/security-check.sh $TOOL_INPUT"]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
"bash hooks/post-edit.sh $FILE_PATH",
"bash hooks/post-test.sh $FILE_PATH"
]
}
]
}
}
| Variable | Description |
|---|---|
$TOOL_INPUT |
Full input to the tool |
$TOOL_OUTPUT |
Output from tool (PostToolUse only) |
$FILE_PATH |
Path to file being modified |
$TOOL_NAME |
Name of tool being called |
From Anthropic's security-guidance plugin:
| Pattern | Risk |
|---|---|
eval(, exec( |
Code injection |
os.system(, subprocess.call.*shell=True |
Command injection |
pickle.loads |
Deserialization attack |
__import__ |
Dynamic import abuse |
innerHTML, document.write |
XSS |
DROP TABLE, ; DROP |
SQL injection |
rm -rf / |
Destructive commands |