Home › Rules › Claude Code hooks examples
Claude Code hooks examples: 7 beginner-safe hooks to copy (and how they work)
Short answer: a hook is a shell command Claude Code runs on its own at a set moment, like right after it edits a file or right before it runs a command. You add hooks to a "hooks" block in .claude/settings.json (one project) or ~/.claude/settings.json (all your projects). Anthropic's docs describe the point plainly: certain actions always happen, rather than relying on the AI to choose to run them. Type /hooks in Claude Code to see what's set up.
Hooks vs CLAUDE.md vs skills
| What it is | Use it for | |
|---|---|---|
| CLAUDE.md | Instructions Claude reads every session | How you want things done: style, commands, project notes |
| Skills | Extra instructions loaded when they fit, or when you type /name | Longer, repeatable step-by-step jobs |
| Hooks | Shell commands Claude Code runs automatically at fixed points | Things that must happen every time: formatting, blocking risky actions, alerts |
Rule of thumb: if you keep writing "always run Prettier" in CLAUDE.md and hoping, make it a hook instead. Anthropic's docs also say that for adding context on every session start, CLAUDE.md is the simpler choice.
Where hooks go
| File | Applies to | Shared with your team? |
|---|---|---|
~/.claude/settings.json | All your projects | No, only your computer |
.claude/settings.json | This project | Yes, you can commit it to git |
.claude/settings.local.json | This project | No (gitignored when Claude Code saves a setting there) |
Hooks can also come from plugins, from a skill's frontmatter (once the skill is used), or from a subagent's file while it runs.
Every hook has the same shape: an event name, an optional matcher that narrows it down (for tool events, the tool name, like Edit|Write or Bash; matchers are case-sensitive), and the command to run:
{
"hooks": {
"EventName": [
{
"matcher": "which tool or type it applies to",
"hooks": [
{ "type": "command", "command": "the shell command to run" }
]
}
]
}
}
Get a free starter kit: the Discord Bot Builder ($6)
The Discord Bot Builder kit ($6) free, plus all 137 rules files as a bonus. One email with your download links.
Free. No spam. Unsubscribe anytime. See our privacy note.
If your settings file already has a "hooks" block, add the new event next to the ones already there instead of replacing the whole block. The file must be valid JSON: no trailing commas, no comments.
The events you'll actually use
Claude Code has many more events (the full list is in the hooks reference). These cover most beginner needs:
| Event | When it fires | Good for |
|---|---|---|
SessionStart | When a session begins or resumes (matcher: startup, resume, clear, compact, fork) | Add reminders to Claude's context, load environment variables |
UserPromptSubmit | When you submit a prompt, before Claude processes it | Add extra context to every prompt (no matcher support) |
PreToolUse | Before a tool call runs. Can block it | Block risky commands or edits to protected files |
PermissionRequest | When a tool call needs a permission decision | Auto-approve one specific prompt you always allow |
PostToolUse | After a tool call succeeds | Format a file after Claude edits it, log commands |
Notification | When Claude Code sends a notification (waiting for input or permission) | Desktop alert so you don't have to watch the terminal |
Stop | When Claude finishes responding | Check the work is really done before it stops |
PreCompact / PostCompact | Before and after the context is summarized | Log or react when the chat gets summarized |
SessionEnd | When a session ends | Clean up temp files (these hooks get a short time budget) |
How a hook talks back: exit codes
When the event fires, Claude Code sends your command the details as JSON on stdin (for example tool_name and tool_input, where tool_input.file_path is the file being edited and tool_input.command is the shell command). Your command answers with its exit code:
- Exit 0: no objection. On
PreToolUse, this does not approve anything; the normal permission prompts still apply. - Exit 2: block it. Whatever you print to stderr (
>&2) goes back to Claude as the reason, so it can change course. Some events, likeSessionStart, can't be blocked. - Any other code: on most events the action goes ahead and you see a "hook error" notice.
Several examples below use jq to read that JSON. Install it with brew install jq on a Mac or apt-get install jq on Debian and Ubuntu.
7 hooks to copy
Examples 1 to 3 and 5 to 7 come straight from Anthropic's hooks guide, lightly trimmed. Example 4 uses the same pattern as the guide's blocking examples. Paste each block into the settings file named under it, merging with any hooks you already have.
1. Get a desktop alert when Claude needs you
Uses Notification, which fires when Claude is waiting for your input or permission. The empty matcher means every kind of notification.
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
}
]
}
]
}
}
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude Code' 'Claude Code needs your attention'"
}
]
}
]
}
}
On a Mac, if nothing shows up, run osascript -e 'display notification "test"' once in Terminal, then turn on notifications for Script Editor in System Settings, Notifications. On Linux, notify-send needs the libnotify-bin package and a desktop session. Windows has a PowerShell version in Anthropic's guide (linked below). To fire only on permission prompts, set the matcher to permission_prompt; for "finished and waiting about 60 seconds", use idle_prompt.
2. Format every file Claude edits
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}
Runs Prettier on the file after each Edit or Write. When it works, Claude Code shows nothing; you'll just see the file reformatted. Swap npx prettier --write for your project's formatter if you use something else.
3. Block edits to .env and other protected files
Save this script, then run chmod +x .claude/hooks/protect-files.sh on Mac or Linux so it can run:
#!/bin/bash
# protect-files.sh: stop Claude from editing secret or generated files
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# Normalize Windows backslash separators so the patterns below match
FILE_PATH="${FILE_PATH//\\//}"
PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")
for pattern in "${PROTECTED_PATTERNS[@]}"; do
if [[ "$FILE_PATH" == *"$pattern"* ]]; then
echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
exit 2
fi
done
exit 0
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
}
]
}
]
}
}
Test it by asking Claude to add a comment to your .env file. The edit is blocked and Claude gets the "Blocked:" message. Note: this only watches the Edit and Write tools. Claude can also change files with shell commands, which this matcher doesn't see, so treat it as a seatbelt, not a lock. Pairs with our vibe coding security checklist.
4. Block a few risky commands
#!/bin/bash
# block-risky-commands.sh: stop a few commands a beginner never wants run by surprise
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
BLOCKED=("rm -rf" "git push --force" "git reset --hard" "drop table" "DROP TABLE")
for pattern in "${BLOCKED[@]}"; do
if [[ "$COMMAND" == *"$pattern"* ]]; then
echo "Blocked: '$pattern' is not allowed here. Explain what you wanted to do and ask me first." >&2
exit 2
fi
done
exit 0
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-risky-commands.sh"
}
]
}
]
}
}
Same idea for the Bash tool: if the command contains one of the listed phrases, the hook exits 2 and Claude is told to ask you first. It's a plain text match, so a command written a different way can slip past. Add or remove phrases to fit your project. Anthropic's docs note that a PreToolUse block applies in every permission mode, even bypassPermissions.
5. Remind Claude of your rules after it compacts
{
"hooks": {
"SessionStart": [
{
"matcher": "compact",
"hooks": [
{
"type": "command",
"command": "echo 'Reminder: explain changes in plain English. Run the tests before saying a task is done. Never edit .env files.'"
}
]
}
]
}
}
When the context fills up, Claude Code summarizes the chat to free space, and details can get lost. A SessionStart hook with the compact matcher runs right after that, and whatever it prints is added to Claude's context. Put your two or three most important rules in the echo.
6. Keep a log of every command Claude runs
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.command' >> ~/.claude/command-log.txt"
}
]
}
]
}
}
After each Bash command, its text is added to ~/.claude/command-log.txt. Handy when something changed and you want to know what ran.
7. Don't let Claude stop until the job is done
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Check if all tasks are complete. If not, respond with {\"ok\": false, \"reason\": \"what remains to be done\"}."
}
]
}
]
}
}
This is a prompt hook: instead of running a script, Claude Code asks a Claude model to check, using your prompt. If the answer is "ok": false, Claude keeps working and uses the reason as its next step. If a Stop hook blocks eight times in a row with no tool call from Claude in between, Claude Code overrides it, so it can't loop forever.
Hooks in Cursor
Cursor has its own hooks, set in a hooks.json file: .cursor/hooks.json in a project, or ~/.cursor/hooks.json for everything. The format is a little different. Here's the formatter from example 2, Cursor-style:
{
"version": 1,
"hooks": {
"afterFileEdit": [{ "command": ".cursor/hooks/format.sh" }]
}
}
#!/bin/bash
# format.sh: run Prettier on the file the Agent just edited
FILE_PATH=$(jq -r '.file_path // empty')
if [ -n "$FILE_PATH" ]; then
npx prettier --write "$FILE_PATH" > /dev/null 2>&1
fi
exit 0
- Project hooks run from the project root, so use paths like
.cursor/hooks/format.sh, not./hooks/format.sh. - Cursor's event names are camelCase and partly different:
afterFileEdit,beforeShellExecution,beforeReadFile,preToolUse,stopand more. Exit code 2 blocks, like in Claude Code. - Cursor can run your Claude Code hooks too. With Include Third-Party Plugins, Skills, and Other Configs turned on (Cursor Settings, Agents, Third-Party Imports; on by default), Cursor loads hooks from
.claude/settings.json,.claude/settings.local.jsonand~/.claude/settings.json. Its docs list 8 events it maps across:PreToolUse,PostToolUse,UserPromptSubmit,Stop,SubagentStop,SessionStart,SessionEndandPreCompact. - Cursor watches
hooks.jsonand reloads it automatically.
Before you add a hook from the internet
Anthropic's docs are blunt about this: command hooks run with your full user permissions and can change, delete or read any file your account can. Read every command before you paste it. Their advice: quote shell variables ("$VAR", not $VAR), use full paths to scripts (like "$CLAUDE_PROJECT_DIR"/.claude/hooks/...), and skip sensitive files like .env and .git/. In a normal Claude Code session, hooks don't run until you accept the folder's workspace trust prompt.
You can also tell Claude about your hooks in CLAUDE.md, so a block doesn't confuse it:
## Hooks
- This project has hooks in .claude/settings.json. They format files after edits and block edits to .env.
- If a hook blocks you, read its message and ask me before trying another way.
Hook not working? Check these
- Not listed in
/hooks. Check the JSON is valid (no trailing commas or comments) and the file is in the right place:.claude/settings.jsonfor the project or~/.claude/settings.jsonfor all projects. Edits are usually picked up on their own; if not, restart the session. - Matcher doesn't match. Matchers are case-sensitive:
Edit|Write, notedit|write. - Wrong event.
PreToolUseruns before the tool,PostToolUseafter. APostToolUsehook can't undo what already happened. - Script never runs. Make it executable with
chmod +x, and use"$CLAUDE_PROJECT_DIR"or a full path if you see "command not found". - "jq: command not found". Install
jq, or read the JSON with Python or Node instead. - Test it by hand. Pipe in sample JSON and check the exit code:
echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh; echo $? - See what happened. Press
Ctrl+Ofor the transcript view, or start withclaude --debugfor the full hook output. - "Only hooks from managed settings run here". Your organization has limited hooks to managed settings, so your own hooks won't run.
Next step for Claude Code: Agent Skills
Skills are folders your AI coding agent loads only when the job comes up, and Claude Code, Cursor and OpenAI Codex all read the same SKILL.md format. The Vibe Coder Skills Pack ($9) is 6 ready-to-copy SKILL.md skills (fix-one-bug, stop-the-loop, leak-check, ship-check, explain-project, builder-handoff) for Claude Code, Cursor and OpenAI Codex. Also included in the 6-kit bundle.
Get the Skills Pack for $9 on Gumroad → See what's inside
One .zip of skill folders plus one markdown file. 7-day refund, no questions asked.
Best value
All 6 kits for $29 — or $20.30 with code WELCOME30 (through Nov 30)
Hooks keep Claude in line. The kits tell it what to build, step by step: a small game, a Discord bot, an email-triage agent, an MVP, or a cleanup of messy code.
Get all 6 kits for $29 → See what's in each kit
$29 instead of $48 for the six kits bought separately; WELCOME30 takes 30% off that at checkout ($20.30). Instant download from Gumroad. 7-day refund, no questions asked.
Related
- CLAUDE.md examples (copy-paste template)
- Claude Code skills examples (7 copy-paste SKILL.md files)
- Custom slash commands (Claude Code, Cursor, Codex, Copilot)
- Claude Code subagents examples (7 copy-paste subagents)
- Plan mode guide (6 tools + 6 plan prompts)
- AGENTS.md vs CLAUDE.md
- Vibe coding security checklist (12 checks before you launch)
Sources
- Claude Code docs: Automate actions with hooks (guide)
- Claude Code docs: Hooks reference
- Cursor docs: Hooks
- Cursor docs: Third-party hooks (Claude Code compatibility)
Checked Oct 25, 2026. These tools change often; if something here no longer matches, tell us at [email protected].