Blog · Claude Code

Claude Code hooks: events, examples, and how they work

Claude Code hooks are commands that run automatically at fixed points in a session: before a tool runs, after a file is edited, when Claude finishes, when it needs your input. Unlike instructions in CLAUDE.md, which Claude usually follows, a hook always runs, so it's the way to enforce rules and automate chores. This guide covers the events, where hooks are configured, how exit codes and JSON control what happens, four ready-to-use examples, and the newer prompt, agent and HTTP hook types.

Claude Code hook events

The reference lists more than thirty events. These are the ones most hooks use; a matcher narrows a hook to certain tools, files or sources.

EventWhen it firesCommon use
SessionStartA session begins or resumesLoad context, check the environment
UserPromptSubmitYou submit a prompt, before Claude sees itAdd context, block sensitive prompts
PreToolUseBefore a tool call runs; can block itBlock dangerous commands, protect files
PermissionRequestA tool call needs a permission decisionAuto-approve or deny specific prompts
PostToolUseAfter a tool call succeedsFormat, lint or test edited files
NotificationClaude Code sends a notificationDesktop alerts when Claude needs you
SubagentStart, SubagentStopA subagent starts or finishesLog or check delegated work
StopClaude finishes respondingCheck the task is really done
PreCompact, PostCompactAround context compactionSave or re-inject key context
FileChanged, CwdChangedA watched file or the working directory changesReload environment, reformat files
SessionEndThe session endsClean up, write a log

Where to put hooks

LocationScopeShared
~/.claude/settings.jsonAll your projectsNo
.claude/settings.jsonOne projectYes, commit it
.claude/settings.local.jsonOne projectNo, gitignored
Managed policy settingsThe whole organizationAdmin-controlled
Plugin hooks/hooks.jsonWhile the plugin is enabledYes, with the plugin
Skill or subagent frontmatterOnce the skill is invoked, or while the subagent runsYes, in the file

Claude Code hook examples, step by step

Add each block under the hooks key of a settings file; if the file already has a hooks object, add the event as a sibling key rather than replacing it. Run /hooks to confirm Claude Code loaded it. You can also ask Claude to write the hook for you.

  1. Get a desktop notification when Claude needs you

    A Notification hook in ~/.claude/settings.json. This one uses osascript on macOS; use notify-send on Linux or PowerShell on Windows.

    {
      "hooks": {
        "Notification": [
          {
            "matcher": "",
            "hooks": [
              {
                "type": "command",
                "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
              }
            ]
          }
        ]
      }
    }
  2. Auto-format every file Claude edits

    A PostToolUse hook with an Edit|Write matcher reads the edited path from the JSON on stdin with jq and runs Prettier on it. Put it in .claude/settings.json so the team shares it.

    {
      "hooks": {
        "PostToolUse": [
          {
            "matcher": "Edit|Write",
            "hooks": [
              { "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }
            ]
          }
        ]
      }
    }
  3. Block a dangerous command

    A PreToolUse hook on Bash runs this script. Exit code 2 blocks the call, and what you write to stderr becomes Claude's feedback so it can change course. Exit 0 means no decision, so normal permissions still apply.

    #!/bin/bash
    # .claude/hooks/block-drop-table.sh, run as a PreToolUse hook on Bash
    INPUT=$(cat)
    COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')
    
    if echo "$COMMAND" | grep -q "drop table"; then
      echo "Blocked: dropping tables is not allowed" >&2  # becomes Claude's feedback
      exit 2                                               # 2 = block the action
    fi
    
    exit 0  # no decision: the normal permission flow applies
  4. Keep Claude working until the task is done

    A Stop hook of type prompt asks a model whether everything is finished. If it answers ok: false, Claude keeps working with the reason as its next instruction. This is the classic Stop hook example.

    {
      "hooks": {
        "Stop": [
          {
            "hooks": [
              {
                "type": "prompt",
                "prompt": "Check if all tasks are complete. If not, respond with {\"ok\": false, \"reason\": \"what remains to be done\"}."
              }
            ]
          }
        ]
      }
    }

Source: Claude Code docs, Automate actions with hooks

How hooks decide what happens

  • Input: each hook receives the event as JSON on stdin, such as the tool name and tool_input, the session ID and cwd.
  • Exit 0: no objection. For a few events, such as SessionStart and UserPromptSubmit, plain stdout is added to Claude's context.
  • Exit 2: block, where the event allows it. Stderr goes back to Claude or to you, depending on the event.
  • JSON on stdout: finer control, such as hookSpecificOutput with a permission decision, updatedInput to rewrite a tool's input, or additionalContext.
  • Other exit codes: usually a non-blocking error, unless the hook sets onFailure: "block".
  • Matching hooks for one event run in parallel.

Command, prompt, agent and HTTP hooks

TypeWhat runsDefault timeout
commandA shell command10 minutes
httpA POST of the event JSON to a URL; the response body works like command output10 minutes
mcp_toolA tool on a configured MCP server10 minutes
promptA single model call that answers ok or not30 seconds
agentA subagent that can read files and run tools before deciding (experimental)60 seconds

Hooks vs skills vs CLAUDE.md, and other gotchas

  • CLAUDE.md and skills are instructions Claude usually follows; hooks always run. Put anything that must never be skipped in a hook.
  • PostToolUse can't undo an action that already ran; use PreToolUse to stop it.
  • Stop fires whenever Claude finishes a response, not only at the end of a task, and not on user interrupts.
  • Hooks can't run slash commands or call tools themselves; they talk back only through exit codes, stdout, stderr or JSON.
  • "disableAllHooks": true turns hooks off; managed hooks still run unless the managed settings disable them too.
  • Hooks are local to your Claude Code setup. Organization-wide checks on every Claude product are a different feature: Claude inference hooks.
  • A PreToolUse hook that filters test output is also one of the best ways to reduce token usage.
With Crewmark

Hooks keep Claude Code in line. Crewmark keeps it working.

Hooks are what make an unattended agent safe: formatting, tests and guardrails run every time. Crewmark turns a Claude Code, Codex, DeepSeek Harness or OpenCode session into an AI employee with a role, a goal and working hours, and wakes it on a heartbeat to take the next issue from a board, with your project's hooks in place.

  1. Commit your hooks

    .claude/settings.json hooks load in the employee's session like in yours, so its edits get formatted and its risky commands blocked.

  2. Let the heartbeat start the work

    During working hours the employee wakes every 15, 30 or 60 minutes in the same conversation; see how to make Claude Code proactive.

  3. Answer only what needs you

    It comments on its issues and messages you when it needs a decision. Read what an AI employee is.

Claude Code hooks FAQ

What are Claude Code hooks?

User-defined commands, HTTP calls or model checks that Claude Code runs automatically at lifecycle events, such as before a tool runs or when Claude finishes. They give deterministic control instead of relying on Claude to remember an instruction.

Where do I configure Claude Code hooks?

Under hooks in ~/.claude/settings.json (all projects), .claude/settings.json (shared with the team) or .claude/settings.local.json (just you). Plugins, skills and subagents can carry hooks too. Run /hooks to see what's loaded.

How do I block a command with a hook?

Use a PreToolUse hook with a Bash matcher. Read the command from the JSON on stdin, and exit with code 2 and a reason on stderr to block it; Claude sees the reason and adjusts.

What is a Stop hook?

A hook on the Stop event, which fires when Claude finishes responding. A prompt-type Stop hook can check whether the task is complete and, if not, send Claude back to work with a reason.

Hooks vs skills: what's the difference?

Skills are instructions and files Claude loads when relevant and usually follows. Hooks are code Claude Code runs every time an event fires, whatever Claude decides.

Why isn't my hook firing?

Check it appears in /hooks, that the event name and matcher are spelled exactly, that the script is executable, and that shell profile output isn't corrupting its JSON. Start Claude Code with a debug log to see what each hook did.

Are Claude Code hooks the same as inference hooks?

No. Claude Code hooks run on your machine for your sessions. Inference hooks are a Claude Enterprise feature that sends every prompt in the organization to a security server before Claude runs.

Checked against the Claude Code docs (hooks guide and hooks reference) on November 6, 2026.

Guardrails in hooks, work from a board.

Crewmark turns Claude Code, Codex and DeepSeek Harness sessions into AI employees with roles, goals, working hours and a heartbeat.