259 lines
4.4 KiB
Markdown
259 lines
4.4 KiB
Markdown
|
|
# Complete Hook Examples
|
||
|
|
|
||
|
|
Working hook configurations for common scenarios.
|
||
|
|
|
||
|
|
## 1. Auto-Format on Save
|
||
|
|
|
||
|
|
Format files automatically after writing/editing:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"hooks": {
|
||
|
|
"PostToolUse": [
|
||
|
|
{
|
||
|
|
"matcher": "Write|Edit",
|
||
|
|
"hooks": [
|
||
|
|
{
|
||
|
|
"type": "command",
|
||
|
|
"command": "cd $CLAUDE_PROJECT_DIR && npx prettier --write $TOOL_ARGS && exit 0"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 2. Security Validation
|
||
|
|
|
||
|
|
Block writes containing secrets:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"hooks": {
|
||
|
|
"PreToolUse": [
|
||
|
|
{
|
||
|
|
"matcher": "Write|Edit",
|
||
|
|
"hooks": [
|
||
|
|
{
|
||
|
|
"type": "command",
|
||
|
|
"command": "if grep -qiE '(password|api[_-]?key|secret|sk-[a-zA-Z0-9]{48})' $TOOL_ARGS 2>/dev/null; then echo 'Error: Possible secret detected' >&2; exit 2; fi; exit 0",
|
||
|
|
"timeout": 30
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 3. Auto-Git on Changes
|
||
|
|
|
||
|
|
Automatically stage and commit changes:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"hooks": {
|
||
|
|
"PostToolUse": [
|
||
|
|
{
|
||
|
|
"matcher": "Write|Edit",
|
||
|
|
"hooks": [
|
||
|
|
{
|
||
|
|
"type": "command",
|
||
|
|
"command": "cd $CLAUDE_PROJECT_DIR && git add $TOOL_ARGS && git commit -m 'Auto-commit: Modified $TOOL_ARGS' && exit 0"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 4. Test Before Commit
|
||
|
|
|
||
|
|
Run tests before allowing file writes:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"hooks": {
|
||
|
|
"PreToolUse": [
|
||
|
|
{
|
||
|
|
"matcher": "Write|Edit",
|
||
|
|
"hooks": [
|
||
|
|
{
|
||
|
|
"type": "command",
|
||
|
|
"command": "cd $CLAUDE_PROJECT_DIR && npm test -- --silent || (echo 'Tests failed, cannot save' >&2; exit 2)",
|
||
|
|
"timeout": 120
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 5. Inject Project Context
|
||
|
|
|
||
|
|
Load project info at session start:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"hooks": {
|
||
|
|
"SessionStart": [
|
||
|
|
{
|
||
|
|
"matcher": "*",
|
||
|
|
"hooks": [
|
||
|
|
{
|
||
|
|
"type": "command",
|
||
|
|
"command": "cat << EOF\nProject: MyApp\nEnvironment: Production\nKey Files: src/config.js, .env.example\nCoding Standards: See CONTRIBUTING.md\nEOF"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 6. Log All Activity
|
||
|
|
|
||
|
|
Track all tool usage:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"hooks": {
|
||
|
|
"PreToolUse": [
|
||
|
|
{
|
||
|
|
"matcher": "*",
|
||
|
|
"hooks": [
|
||
|
|
{
|
||
|
|
"type": "command",
|
||
|
|
"command": "echo \"$(date '+%Y-%m-%d %H:%M:%S') - $TOOL_NAME - $TOOL_ARGS\" >> $CLAUDE_PROJECT_DIR/.claude/activity.log && exit 0"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 7. Multiple Hooks Sequence
|
||
|
|
|
||
|
|
Format, lint, then stage:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"hooks": {
|
||
|
|
"PostToolUse": [
|
||
|
|
{
|
||
|
|
"matcher": "Write|Edit",
|
||
|
|
"hooks": [
|
||
|
|
{
|
||
|
|
"type": "command",
|
||
|
|
"command": "npx prettier --write $TOOL_ARGS"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"type": "command",
|
||
|
|
"command": "npx eslint --fix $TOOL_ARGS"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"type": "command",
|
||
|
|
"command": "git add $TOOL_ARGS"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 8. Script-Based Hooks
|
||
|
|
|
||
|
|
Call external script for complex logic:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"hooks": {
|
||
|
|
"PreToolUse": [
|
||
|
|
{
|
||
|
|
"matcher": "Write",
|
||
|
|
"hooks": [
|
||
|
|
{
|
||
|
|
"type": "command",
|
||
|
|
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/validate-write.sh $TOOL_ARGS",
|
||
|
|
"timeout": 60
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**validate-write.sh**:
|
||
|
|
```bash
|
||
|
|
#!/bin/bash
|
||
|
|
file=$1
|
||
|
|
|
||
|
|
# Check file size
|
||
|
|
if [ -f "$file" ] && [ $(wc -c < "$file") -gt 1000000 ]; then
|
||
|
|
echo "Error: File too large" >&2
|
||
|
|
exit 2
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Check for secrets
|
||
|
|
if grep -qiE '(password|api[_-]?key)' "$file" 2>/dev/null; then
|
||
|
|
echo "Error: Possible secret detected" >&2
|
||
|
|
exit 2
|
||
|
|
fi
|
||
|
|
|
||
|
|
exit 0
|
||
|
|
```
|
||
|
|
|
||
|
|
## 9. Conditional by File Type
|
||
|
|
|
||
|
|
Only format JavaScript files:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"hooks": {
|
||
|
|
"PostToolUse": [
|
||
|
|
{
|
||
|
|
"matcher": "Write",
|
||
|
|
"hooks": [
|
||
|
|
{
|
||
|
|
"type": "command",
|
||
|
|
"command": "if [[ $TOOL_ARGS == *.js ]]; then npm run format $TOOL_ARGS; fi; exit 0"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 10. Desktop Notifications
|
||
|
|
|
||
|
|
Alert when Claude needs attention:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"hooks": {
|
||
|
|
"Notification": [
|
||
|
|
{
|
||
|
|
"matcher": "*",
|
||
|
|
"hooks": [
|
||
|
|
{
|
||
|
|
"type": "command",
|
||
|
|
"command": "osascript -e 'display notification \"Claude needs attention\" with title \"Claude Code\"' && exit 0"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
For advanced patterns, see [patterns.md](patterns.md)
|