Workbranch › Guides
GuideHow to use hooks in Claude Code
You want something to happen every time, such as formatting a file after Claude edits it or a ping when Claude is waiting for you, without hoping Claude remembers. Hooks do exactly that. This guide explains what they are, walks through a first hook, and shows where to put them.
Quick answer: a hook is a shell command that Claude Code runs automatically at a fixed point, for example before a tool runs, after a file is edited, or when Claude needs your input. You add hooks under a hooks key in a settings file such as ~/.claude/settings.json (all projects) or .claude/settings.json (one project), then type /hooks to confirm Claude Code sees them.
Event names, file locations and behavior below come from Anthropic's Claude Code documentation as of October 2026. Claude Code updates often, so run claude update if something is missing.
What hooks are and why they help
Instructions in a prompt or a CLAUDE.md file are suggestions: Claude usually follows them, but it decides. A hook is different. Claude Code itself runs your command whenever the event fires, so the action is deterministic. Typical uses from Anthropic's guide:
- Notifications when Claude is waiting for a permission or your reply.
- Auto-formatting each file after Claude edits or writes it.
- Blocking edits to sensitive files such as
.envor anything in.git/. - Adding context, for example reminding Claude of project conventions after the conversation is compacted.
Some of the most used events are SessionStart (a session begins or resumes), UserPromptSubmit (you send a prompt), PreToolUse (before a tool call, and it can block it), PostToolUse (after a tool call succeeds), Notification, Stop (Claude finishes responding), PreCompact and SessionEnd. The full list in the hooks reference is much longer.
Set up your first hook: a desktop notification
This example, adapted from Anthropic's walkthrough, alerts you on macOS whenever Claude Code needs your attention.
- Open
~/.claude/settings.jsonin a text editor. Create the file if it doesn't exist. - Add a
hooksobject with aNotificationentry. Inside it goes a list of matcher groups; each has amatcher(leave it as an empty string to fire on every notification) and ahookslist with one item of"type": "command". - Set the command to
osascript -e 'display notification "Claude Code needs your attention" with title "Claude Code"'. On Linux, Anthropic's example usesnotify-sendinstead. Remember to escape the inner double quotes in JSON. - If the file already has a
hookskey, addNotificationnext to the existing events rather than replacing the whole object. - In Claude Code, type
/hooks. The hooks browser should list your new hook under Notification. Press Esc to go back. - Ask Claude for something that needs permission and switch to another window. A notification should appear.
To fire only on some notifications, set the matcher to a type such as permission_prompt (a permission prompt has been waiting for about six seconds) or idle_prompt (Claude finished and you haven't typed for about a minute).
A second example: format files after edits
For a project hook, put the configuration in .claude/settings.json at the project root. Use the PostToolUse event with the matcher Edit|Write, so it only runs after file-editing tools. Anthropic's example command reads the edited path from the JSON Claude Code passes on standard input and hands it to Prettier: jq -r '.tool_input.file_path' | xargs npx prettier --write. It needs jq installed. A successful hook shows nothing in the conversation; you'll just see the file reformatted.
Where hooks are configured
| Location | Applies to | Shared? |
|---|---|---|
~/.claude/settings.json | All your projects | No, only your machine |
.claude/settings.json | One project | Yes, can be committed |
.claude/settings.local.json | One project | No, kept out of git |
| Managed policy settings | Whole organization | Set by admins |
A plugin's hooks/hooks.json | While the plugin is enabled | Bundled with the plugin |
| Skill frontmatter | The rest of the session after the skill is invoked | In the skill file |
| Subagent frontmatter | While that subagent runs | In the subagent file |
To switch hooks off, set "disableAllHooks": true in a settings file. Hooks from managed settings keep running unless it is set there too.
How a hook talks back
When an event fires, Claude Code sends event details as JSON to your command's standard input. Your command answers with its exit code:
- Exit 0: carry on. For some events, such as
SessionStart, plain text printed to standard output is added to Claude's context. - Exit 2: block the action where the event allows it. Write the reason to standard error; for
PreToolUse, Claude receives it and can change course. - Other codes: usually treated as a non-blocking error; the action proceeds and the transcript shows a hook error.
For finer control, exit 0 and print a JSON object instead. Pick one approach per hook.
Good to know
- Command hooks can't run slash commands or call tools themselves.
- The default timeout for command hooks is 10 minutes, shorter for a few events; set
timeout(in seconds) per hook to change it. PostToolUsecan't undo anything, because the tool has already run. UsePreToolUseto prevent an action.Stopfires each time Claude finishes a response, not only when a task is done.
If it doesn't work
- The hook never fires: run
/hooksand check it is listed under the right event. Matchers are case-sensitive and must match the tool name exactly, for exampleEdit, notedit. - "/hooks" shows nothing: check the JSON is valid (no trailing commas or comments) and in the right file. Edits are normally picked up automatically; if not, restart the session.
- "hook error" in the transcript: test the script by piping sample JSON into it and checking
echo $?. Use absolute paths or$CLAUDE_PROJECT_DIRfor scripts, installjqif it's missing, and make scripts executable withchmod +x. - No macOS notification: run the
osascriptcommand once in Terminal, then turn on Allow Notifications for Script Editor in System Settings > Notifications.
Keep track of what each session leaves open
The Workbranch plugin for Claude Code uses a session-start recap: in a folder linked to a Workbranch project, it shows what is still open when a session begins, and saying "save this to Workbranch" files the session's tasks, decisions and open questions into that project. See Workbranch for Claude. New to Claude Code? Start with getting started with Claude Code.
Sources
- Use Claude Code with your Pro or Max plan (Claude Help Center, checked 30 October 2026)
- Automate actions with hooks (Claude Code docs, checked 30 October 2026)
Frequently asked questions
Can Claude write a hook for me?
Yes. Anthropic's guide says you can describe the hook you want at the Claude Code prompt and ask Claude to add it to your settings. Check the result with /hooks afterwards.
Can a hook stop Claude even in bypass mode?
A PreToolUse hook that returns a deny decision blocks the tool in every permission mode, including bypassPermissions. That is what makes hooks useful for rules people can't switch off by changing modes.
Are there hooks that use a model instead of a script?
Yes. Besides shell commands, a hook can be an HTTP request, an MCP tool call, a single prompt evaluated by a Claude model, or an experimental agent hook with tool access.