← All posts

May 23, 2026 · 6 min read

A Practical Guide to Claude Code Hooks

What Claude Code hooks are, the events you can hook into (PreToolUse, PostToolUse, Notification, Stop), and how to wire them up in settings.json with examples.


Hooks are one of Claude Code's most underrated features. They let you run your own shell command whenever something happens in a session — a tool is about to run, a task finishes, Claude needs your input. That's the building block behind notifications, logging, guardrails, and tools like ClaudeNotch.

The events you can hook into

  • PreToolUse — fires before a tool runs. It can even return a decision to allow or block the call, which makes it the hook for permission flows.
  • PostToolUse — fires after a tool completes. Great for logging or reacting to results.
  • UserPromptSubmit — fires when you send a message.
  • Notification— fires when Claude wants your attention (e.g. it's waiting for input).
  • Stop — fires when Claude finishes responding.

Where hooks live

Hooks are configured in your Claude Code settings file at ~/.claude/settings.json. Each event takes a list of matchers (which tools to match) and the command to run:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "~/scripts/log-cmd.sh" }
        ]
      }
    ]
  }
}

The matcher selects which tools trigger the hook (here, only Bash). Leave it broad or target specific tools like Write or Edit.

A simple example: log every shell command

Your hook script receives the event payload as JSON on stdin. A tiny logger might look like this:

#!/bin/bash
# ~/scripts/log-cmd.sh
cmd=$(jq -r '.tool_input.command' )
echo "$(date)  $cmd" >> ~/claude-commands.log

Make it executable (chmod +x), point your PreToolUse hook at it, and every Bash command Claude runs gets logged with a timestamp.

PreToolUse can gate permissions

The powerful part: a PreToolUse hook can print JSON to stdout that tells Claude Code whether to allow the call. By returning a permission decision, your hook becomes the approval gate — which is how an external UI can drive the allow/deny choice instead of the built-in terminal prompt.

Real-world: ClaudeNotch is built on hooks

ClaudeNotch is essentially a thin, well-designed layer over these hooks. A PreToolUsehook forwards each permission request to a tiny local app, which shows it in your Mac's notch and waits for your click; Notification and Stophooks surface "waiting for input" and "task done" cards. If the app isn't running, the hooks safely fall back to Claude Code's normal prompts — so there's no way to get stuck.

If you want to see what's possible with hooks without writing any yourself, it's a good place to start.

Handle every Claude Code prompt from your notch

ClaudeNotch puts permissions, questions, and notifications in a Dynamic Island-style overlay — approve with one key and stay in your editor.

Download ClaudeNotch for macOS