Claude Code hooks let you run scripts at key points in the agent's lifecycle: before tool use, after tool use, on stop, on error. Here are the 5 I reach for on every project.
What hooks actually do
Hooks are shell scripts (or any executable) that Claude Code calls at lifecycle events. They can:
- Block an action (non-zero exit code stops the tool call)
- Log what happened
- Run side effects (format code, send a notification)
- Inject context back into the agent
They live in .claude/settings.json under the hooks key.
Hook 1: Read before Edit enforcer
{
"PreToolUse": [{
"matcher": "Edit|Write",
"hooks": [{"type": "command", "command": "bash .claude/hooks/read-before-edit.sh"}]
}]
}
#!/bin/bash
# read-before-edit.sh
# Warn if Edit is called without a recent Read of the same file
echo "[hook] Make sure you've read this file before editing"
exit 0 # advisory only — doesn't block
Simple advisory hook. Reminds the agent to check current state. You can make it blocking for stricter enforcement.
Hook 2: Git safety net
#!/bin/bash
# pre-bash-git.sh — runs before any Bash tool call with git in it
# Block git add -A and git add .
if echo "$CLAUDE_TOOL_INPUT" | grep -qE 'git add (-A|\.)'; then
echo "ERROR: Use specific file paths with git add, not -A or ."
exit 1
fi
This one blocks. git add -A has caused real problems for me — accidentally staging .env files, large binaries, debug files. The hook catches it before it happens.
Hook 3: Rate limit guard
#!/bin/bash
# rate-limit-check.sh
# Track last call time per API, enforce minimum delay
API=$(echo "$CLAUDE_TOOL_INPUT" | grep -oP '(?<=curl -s )https://[^/]+' | head -1)
if [ -n "$API" ]; then
LAST_CALL_FILE="/tmp/last-api-call-$(echo $API | md5sum | cut -c1-8)"
if [ -f "$LAST_CALL_FILE" ]; then
LAST=$(cat "$LAST_CALL_FILE")
NOW=$(date +%s)
DIFF=$((NOW - LAST))
if [ $DIFF -lt 1 ]; then
sleep $((1 - DIFF))
fi
fi
date +%s > "$LAST_CALL_FILE"
fi
Rudimentary but effective for preventing rapid-fire API calls. Extend with per-API thresholds.
Hook 4: Context checkpoint reminder
#!/bin/bash
# context-checkpoint.sh — runs on Stop
# Remind agent to update task state before stopping
echo "Reminder: Update tasks/current-task.md with last_checkpoint before stopping"
exit 0
Simple reminder on the Stop event. Doesn't enforce anything — just puts the reminder where the agent will see it.
Hook 5: Secret scanner
#!/bin/bash
# secret-scan.sh — runs before Write
# Block writing files that look like they contain secrets
CONTENT="$CLAUDE_TOOL_INPUT"
if echo "$CONTENT" | grep -qiE '(api_key|secret|password|token)\s*=\s*["\x27][^"\x27]{8,}'; then
echo "ERROR: File content looks like it contains credentials. Use environment variables."
exit 1
fi
Catches the most obvious cases: hardcoded API keys, passwords, tokens. Not foolproof, but stops the easy mistakes.
Setting them up
In .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{"matcher": "Bash", "hooks": [{"type": "command", "command": ".claude/hooks/pre-bash-git.sh"}]},
{"matcher": "Write", "hooks": [{"type": "command", "command": ".claude/hooks/secret-scan.sh"}]}
],
"Stop": [
{"hooks": [{"type": "command", "command": ".claude/hooks/context-checkpoint.sh"}]}
]
}
}
All 5 hooks + documentation in the Agent Harness ($29), along with the CLAUDE.md templates and context management system.
Repo with templates: github.com/seankim-android/claude-md-templates
Top comments (0)