Claude Code hooks: automate the steps you repeat
Claude Code hooks run shell commands at set lifecycle points. Set up three first: a desktop notification, Prettier after edits, and protected files.
Claude Code hooks are user-defined shell commands that Claude Code runs at specific points in its lifecycle, so certain actions always happen instead of depending on the model to choose to run them. Three are worth setting up first: a desktop notification, Prettier after every edit, and a block on protected files.
What we used: Claude Code with a user settings file and a project settings file, the macOS notification command from the docs, jq for reading JSON, and Prettier run through npx. The configuration blocks below are the ones in the Claude Code hooks guide, which also has the Linux and Windows notification commands.
What hooks are and when they run
A hook is a shell command attached to a lifecycle event, optionally filtered by a matcher. Because the command runs every time the event fires, hooks give you deterministic control, which a line in a prompt cannot.
Why not just tell Claude what to do? Because an instruction is something the model may or may not follow. For decisions that need judgment, prompt-based hooks and agent-based hooks use a Claude model to evaluate conditions. The rest of this post stays with plain shell commands.
| Event | Runs when | Use it for |
|---|---|---|
Notification | Claude is waiting for input or permission | Desktop alerts |
PreToolUse | Before a tool call, filtered by a matcher such as Edit|Write | Blocking edits |
PostToolUse | After file-editing tools when the matcher is Edit|Write | Formatting |
SessionStart | A session starts; the compact matcher covers re-injecting context after compaction | Reminders |
ConfigChange | An external process or editor modifies a configuration file | Audit logs |
CwdChanged | Claude changes directory | Reloading environment variables |
The docs point to a separate reference for the full list of hook events.
1. Add a notification hook
This hook alerts you when Claude is waiting, so you can leave the terminal.
- Open
~/.claude/settings.json, creating it if it does not exist, and add aNotificationhook. This is the macOS version:
{ "hooks": { "Notification": [ { "matcher": "", "hooks": [ { "type": "command", "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'" } ] } ] }}- If the file already has a
hookskey, addNotificationas a sibling of the existing event keys rather than replacing the whole object. - Type
/hooksat the Claude Code prompt. The hook should appear under Notification. - Press
Shift+Tabuntil the status bar shows manual mode, ask Claude for something that needs permission, then switch away from the terminal. A desktop notification should arrive.
The empty matcher fires on every notification type. To narrow it, use a value such as permission_prompt, which fires when Claude needs you to approve a tool use and the prompt has waited about six seconds, or idle_prompt, which fires when Claude finished responding about 60 seconds ago and you haven’t typed since.
If you hit usage limits often, the same event family has matchers for when Claude Code resumes after a pause. The usage limits post covers what spends your quota.
2. Format files after every edit
Prettier runs on each file Claude edits, so formatting stays consistent without you asking.
- Add this to
.claude/settings.jsonin your project root. TheEdit|Writematcher means it runs only after file-editing tools:
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" } ] } ] }}- Install
jqif it is missing. The docs givebrew install jqon macOS andapt-get install jqon Debian and Ubuntu. - Ask Claude to add a line with single-quoted strings to a JavaScript file, then open the file. With Prettier’s default settings, the hook rewrites them to double quotes.
A successful hook is silent, since Claude Code shows nothing in the conversation. Check the file, not the chat. If you need a file reformatted however it changes, including when a Bash command rewrites it, the docs recommend a FileChanged hook instead.
Give your build a human voice
Eleven v4 is ElevenLabs' most emotive voice model yet, for text to speech, voice agents and an API.
Hear Eleven v4Sponsored
Make AI video from inside Claude
Higgsfield has an MCP for Claude, plus Seedance 2.5 and Cinema Studio 4.0. New accounts get up to 50% off for their first 3 hours.
Get up to 50% offSponsored
3. Block edits to protected files
This hook stops Claude from touching .env, package-lock.json or anything in .git/. Claude receives feedback explaining why the edit was blocked, so it can adjust its approach.
- Save this script to
.claude/hooks/protect-files.sh:
#!/bin/bash# protect-files.sh (from the Claude Code docs; run inside your project)INPUT=$(cat)FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')# Normalize Windows backslash separators so the patterns below matchFILE_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 fidoneexit 0- Make it executable on macOS and Linux, because hook scripts must be executable for Claude Code to run them:
chmod +x .claude/hooks/protect-files.sh- Register it as a
PreToolUsehook in.claude/settings.json:
{ "hooks": { "PreToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh" } ] } ] }}- Ask Claude to add a comment to your
.envfile. The edit is blocked before it runs, and the script’sBlocked:message goes to Claude as feedback.
The rule that makes this work is the exit code. The script exits with code 2 to block the edit; exiting 0 lets it through.
exit 2 # block the editexit 0 # let it through4. Repeat it for the next hook
Every hook above follows the same five moves, so a new one takes a few minutes.
- Pick the event that matches the moment: before a tool call, after one, at session start, or when Claude waits.
- Set a matcher so the hook fires only on the tools or notification types you care about.
- Write the command, or point to a script that reads the JSON from standard input.
- Add it to the right settings file:
~/.claude/settings.jsonfor every project,.claude/settings.jsonfor one project. - Open
/hooksto confirm it is listed, then trigger it once on purpose.
Two good next candidates are already in the docs. A SessionStart hook with a compact matcher can re-inject critical context after every compaction, because compaction can lose important details. A ConfigChange hook can append each settings or skills change to an audit log. Hooks cover actions that must always happen; for extra instructions, skills are the other tool, and the shared skills repo post shows how to keep one set across Claude Code and Codex.
Verdict
Start with the notification, the Prettier hook and the protected-files block: each is a single settings entry, and each is confirmed by one test action. Use /hooks to check that a hook is registered, and expect the formatting hook to stay silent when it works. Move to compaction reminders or a config audit log once those three behave.
Try it today: read the Claude Code hooks guide
Sources:Claude Code docs: Automate actions with hooks.
Responses
Responses
Community guidelines
Write about the post. Be kind and be specific.
Responses are plain text. Spam, abuse and anything unlawful are removed, and the person who posted them may be blocked.
A response may wait for the owner to read it before it appears. Use Report on anything that should not be here.
Give your build a human voice
Eleven v4 is ElevenLabs' most emotive voice model yet, for text to speech, voice agents and an API.
Hear Eleven v4Sponsored
Make AI video from inside Claude
Higgsfield has an MCP for Claude, plus Seedance 2.5 and Cinema Studio 4.0. New accounts get up to 50% off for their first 3 hours.
Get up to 50% offSponsored
Get the next one
New posts by email, when they are ready. Confirm once and you are on the list.
Check your inbox
We sent a link to . Click it and you are on the list. Nothing is sent to an address that has not confirmed itself.
Keep reading


Claude Code headless: run it from a script
Claude Code headless means running claude -p with a prompt. Pick an output format, pre-approve tools with --allowedTools, and add --bare for CI.


Claude model training data: what the help article says
Anthropic's help article says commercial inputs are not used for training by default, but feedback can be. Here is what to check in Claude Code.


Generative UI agent instructions: 2,326 vs 12,720 tokens
Generative UI needs instructions that teach an agent to build cards. A short block cost 2326 tokens, a full guide 12,720, so keep the short block.

