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|Write for 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: allow skips the confirmation, deny blocks, ask asks you.

Example

No edits to .env files.

A PreToolUse hook for the Edit and Write tools, set in your user settings.

~/.claude/settings.json
{
  "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.

~/.claude/hooks/protect-env.sh
#!/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 0

The 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?
Both have their place. An instruction explains a workflow and why it is that way, and the model follows it most of the time. A hook runs every time. Whatever must always apply, such as a block, belongs in a hook. Workban uses both: a rule for the workflow, hooks for the gate and the measuring.
Are hooks a risk?
A hook runs with your permissions and can do anything your user account can. Read every hook before you add it, especially from repositories you did not write. In an interactive session, Claude Code only runs hooks once you trust the folder.
Why does my hook not run?
Usually the matcher does not match, the script is not executable or it prints invalid JSON. /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.