Guide · Claude Code
Claude Code hooks: commands that run every time.
An instruction in CLAUDE.md is a request to the model. A hook is a command Claude Code runs itself at a fixed point, every time. This guide explains events, matchers and exit codes, shows a hook that blocks edits to .env files, and how Workban uses hooks.
- Claude Code
- With an example
- Codex too
- Updated October 30, 2026
Basics
What a hook is.
A hook is a command Claude Code starts on a given event: before a tool runs, after it ran, when a session begins or when Claude has finished its response. It gets the details of the event as JSON on standard input, such as the tool's name and its parameters.
The hook answers through its exit code and its output. That way it can allow an action, block it, trigger a confirmation or give Claude extra context. Because the hook runs outside the model, it applies even when Claude overlooks an instruction.
Locations
Where hooks live.
Hooks live in Claude Code's JSON settings. The location decides what they apply to. Entries from several locations add up instead of replacing each other.
- ~/.claude/settings.json
- For all your projects, on your machine only.
- .claude/settings.json
- For one project. It sits in the repository, so it applies to everyone who clones it.
- .claude/settings.local.json
- For one project, for you only, not in the repository.
- Plugins, skills, subagents
- A plugin brings hooks along while it is enabled. Skills and subagents can define hooks in their frontmatter.
- Managed settings
- For a whole organization, set by admins.
Events
The events you will need most.
Claude Code's reference lists more than 30 events. These carry most hooks.
- SessionStart
- When a session starts or resumes. What the hook prints as text, Claude reads as context.
- UserPromptSubmit
- Before Claude processes your prompt. Can add context or reject the prompt.
- PreToolUse
- Before every tool call. Can block it, allow it or trigger a confirmation.
- PostToolUse
- After a tool ran successfully, such as for formatters or checks.
- Stop
- When Claude has finished its response. Not after you interrupt it.
- SubagentStop
- When a subagent has finished.
- SessionEnd
- When the session ends.
Control
Matchers narrow it down, exit codes decide.
A matcher decides when a hook starts at all. Its exit code tells Claude Code what happens next.
- Matcher
- For tool events, the tool's name:
Bash,Edit|Writefor both,mcp__.*as a regular expression for every MCP tool. Empty or*means always. - Exit 0
- All good. If the hook prints a JSON object, Claude Code applies its fields.
- Exit 2
- Blocks the action, on events that can block. What the hook writes to stderr, Claude gets as the reason.
- Any other exit code
- An error that blocks nothing: the action goes ahead, and Claude Code shows a notice.
- permissionDecision
- Finer control through JSON on PreToolUse:
allowskips the confirmation,denyblocks,askasks you.
Example
No edits to .env files.
A PreToolUse hook for the Edit and Write tools, set in your user settings.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "~/.claude/hooks/protect-env.sh" }
]
}
]
}
}Example
Its script blocks with exit code 2.
It reads the file path from the input. If it is an .env file, such as .env or .env.local, it writes the reason to stderr and exits with 2.
#!/bin/bash
# No edits to .env files
file=$(jq -r '.tool_input.file_path // empty')
case "$file" in
*.env|*.env.*)
echo "No edits to $file" >&2
exit 2
;;
esac
exit 0The script needs jq and has to be executable (chmod +x). In Claude Code, /hooks lists every configured hook and where it comes from. With claude --debug, Claude Code writes to the debug log under ~/.claude/debug which hooks ran and what they returned.
In Workban
How Workban uses the hooks.
workban setup registers one command, workban hook run, for the events Workban needs. In repositories without .workban.toml it does nothing.
- SessionStart
- Shows what is running and what waits in the backlog, and keeps the CLI, rule and skill up to date.
- PreToolUse
- The gate: holds back changes in the repository as long as the session has not started a task of its own. Before a web search, it points to the team's knowledge.
- PostToolUse
- Which tool the session is using right now, for the Live page.
- UserPromptSubmit, PermissionRequest
- The phase on the card: whether the agent is working or waiting for you.
- Stop
- The turn's token usage, read from the session's log.
- SessionEnd, SubagentStop
- When a session or a subagent is done.
Codex
Codex has hooks of its own, with an approval.
Codex has hooks on the same pattern: event, matcher, command, among them SessionStart, PreToolUse, PostToolUse and Stop. They live in a hooks.json or as [hooks] in config.toml.
The main difference: Codex only runs a hook after you have reviewed and trusted it through /hooks. When the hook changes, Codex asks again.
Questions
What people often ask.
Hook or instruction in CLAUDE.md?
Are hooks a risk?
Why does my hook not run?
/hooks shows whether Claude Code knows the hook, and the debug log from claude --debug shows whether it ran and what it returned.Sources
Where the statements come from.
What this page says about other products comes from their own pages and announcements, as of the date above. Features and plans change; when in doubt, the source wins.
Get started
Try it with your next task.
Workban is free. Your workspace is ready in a minute, and the first task appears as soon as your agent gets going. The app itself speaks German for now.