by RuneForge AI
A curated collection of 50+ production-ready hooks for Claude Code — organized by category, installable in seconds, and designed to make your AI-assisted development sessions safer, smarter, and more observable.
Claude Code hooks are shell commands that run automatically at defined points in Claude's workflow. They let you intercept tool calls — before or after Claude runs a bash command, writes a file, edits code, or finishes a task — and execute your own logic.
Why use hooks?
- Security — Block dangerous commands before they execute (e.g.,
rm -rf /, curl-pipe-bash, hardcoded secrets) - Quality — Auto-lint, format, and validate files the moment Claude touches them
- Observability — Log every tool call, file write, and bash command for a full audit trail
- Productivity — Automate repetitive tasks like
git add,.env.examplegeneration, and browser launching - Notifications — Get desktop alerts and Slack messages when long tasks complete or deploys run
Hooks are configured in ~/.claude/settings.json and run as local shell processes — no Claude API calls, no extra cost.
| Event | When it fires |
|---|---|
PreToolUse |
Before Claude invokes a tool (can block execution by exiting non-zero) |
PostToolUse |
After a tool completes successfully |
Stop |
When Claude finishes the current task |
SubagentStop |
When a subagent completes |
Notification |
On Claude system notifications |
- Claude Code installed
jqinstalled (brew install jq/apt install jq/choco install jq)- Bash (Git Bash on Windows works fine)
git clone https://github.com/CodyLunders/claude-code-hooks-library.git
cd claude-code-hooks-library
chmod +x install.sh
./install.sh --all./install.sh --category security
./install.sh --category quality
./install.sh --category gitRunning without arguments launches an interactive menu where you pick which categories to install:
./install.shThe installer merges hooks into ~/.claude/settings.json without overwriting your existing configuration. Hooks with the same id are deduplicated automatically.
| Category | Count | Description |
|---|---|---|
security |
12 | Block dangerous commands, scan for secrets, enforce safe patterns |
quality |
11 | Lint, format, type-check, and validate files automatically |
git |
9 | Enforce commit conventions, validate branches, and prevent mistakes |
productivity |
8 | Automate repetitive tasks and surface useful info at the right moment |
logging |
7 | Full audit trail of every tool call, file written, and session |
notifications |
8 | Desktop alerts, Slack webhooks, and sound cues on key events |
Total: 55 hooks
Prevents the most catastrophic possible bash command before it executes:
{
"id": "security-block-rm-rf-root",
"name": "Block rm -rf /",
"description": "Prevents execution of rm -rf / or rm -rf /* which would wipe the filesystem",
"category": "security",
"event": "PreToolUse",
"matcher": "Bash",
"command": "bash -c 'CMD=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r \".command // empty\"); if echo \"$CMD\" | grep -qE \"rm\\s+-[a-zA-Z]*r[a-zA-Z]*f\\s+/[\\s*]*$\"; then echo \"[SECURITY] Destructive rm -rf / blocked.\"; exit 2; fi'",
"enabled": true
}Scans every bash command for hardcoded AWS access key patterns:
{
"id": "security-scan-aws-keys",
"name": "Block AWS Key Exposure",
"event": "PreToolUse",
"matcher": "Bash",
"command": "bash -c 'CMD=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r \".command // empty\"); if echo \"$CMD\" | grep -qE \"AKIA[0-9A-Z]{16}\"; then echo \"[SECURITY] AWS Access Key detected in command. Aborting.\"; exit 2; fi'"
}Runs ESLint automatically on any JS/TS file the moment Claude edits it:
{
"id": "quality-eslint-on-edit",
"name": "ESLint After Edit",
"event": "PostToolUse",
"matcher": "Edit",
"command": "bash -c 'FILE=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r \".file_path // empty\"); if echo \"$FILE\" | grep -qE \"\\.(js|jsx|ts|tsx)$\"; then eslint \"$FILE\" 2>&1 | tail -20 || true; fi'"
}Validates commit message format before every git commit:
{
"id": "git-conventional-commit",
"name": "Enforce Conventional Commits",
"event": "PreToolUse",
"matcher": "Bash",
"command": "bash -c 'CMD=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r \".command // empty\"); if echo \"$CMD\" | grep -qE \"git\\s+commit\"; then MSG=$(echo \"$CMD\" | grep -oP \"(?<=-m[\\x27\\\"]).*?(?=[\\x27\\\"])\"); if [ -n \"$MSG\" ] && ! echo \"$MSG\" | grep -qE \"^(feat|fix|chore|docs|style|refactor|test|build|ci|perf|revert)\"; then echo \"[GIT] Commit does not follow Conventional Commits format.\"; fi; fi'"
}Runs git add automatically on every file Claude writes:
{
"id": "git-auto-stage-new-file",
"name": "Auto-Stage Newly Written Files",
"event": "PostToolUse",
"matcher": "Write",
"command": "bash -c 'FILE=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r \".file_path // empty\"); if [ -f \"$FILE\" ] && git rev-parse --git-dir &>/dev/null; then git add \"$FILE\" && echo \"[GIT] Auto-staged: $FILE\"; fi'"
}Sends a desktop notification (Linux or macOS) when Claude finishes a task:
{
"id": "notifications-desktop-task-complete",
"name": "Desktop Notification on Task Complete",
"event": "Stop",
"matcher": "Bash",
"command": "bash -c 'MSG=\"Claude Code task complete at $(date +%H:%M)\"; if command -v notify-send &>/dev/null; then notify-send \"Claude Code\" \"$MSG\"; elif command -v osascript &>/dev/null; then osascript -e \"display notification \\\"$MSG\\\" with title \\\"Claude Code\\\"\"; fi'"
}Logs every bash command Claude runs to a local file:
{
"id": "logging-bash-commands-history",
"name": "Log Bash Command History",
"event": "PostToolUse",
"matcher": "Bash",
"command": "bash -c 'CMD=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r \".command // empty\" | head -c 200); echo \"$(date -Iseconds) CMD: $CMD\" >> ~/.claude/command-history.log'"
}Add entries to ~/.claude/settings.json under the "hooks" key:
{
"hooks": [
{
"id": "my-custom-hook",
"name": "My Custom Hook",
"event": "PreToolUse",
"matcher": "Bash",
"command": "bash -c 'echo \"[HOOK] About to run a bash command\"'",
"enabled": true
}
]
}Tips:
- Use
exit 2inPreToolUsehooks to block the tool call - Read tool input via
$CLAUDE_TOOL_INPUT(JSON string) - Parse it with
jq:CMD=$(echo "$CLAUDE_TOOL_INPUT" | jq -r ".command // empty") - Keep hooks fast — they run synchronously before/after every tool call
- Use
|| trueat the end of non-blocking hooks to prevent false failures
Some hooks are no-ops unless you set these:
| Variable | Used by |
|---|---|
SLACK_WEBHOOK_URL |
notifications-slack-on-deploy |
NOTIFY_WEBHOOK |
notifications-webhook-on-write |
Set them in your shell profile (~/.bashrc, ~/.zshrc) or in your project's .env.
Logging hooks write to ~/.claude/:
| File | Contents |
|---|---|
tool-call.log |
All tool invocations with timestamps |
files-written.log |
Every file written by Claude |
files-edited.log |
Every file edited by Claude |
files-read.log |
Every file read by Claude |
command-history.log |
All bash commands run |
errors.log |
Commands that exited non-zero |
sessions.log |
Session start/end timestamps |
subagent.log |
Subagent completion events |
- Claude Command Center — A desktop GUI for managing Claude Code sessions, hooks, and settings visually. Available for $27 on Lemon Squeezy.
- Claude Code official docs
MIT — see LICENSE. Built by RuneForge AI.