§03.03

How to Configure Hooks in Claude Code

Hooks run a shell command on Claude Code events. Note $CLAUDE_FILE_PATHS no longer exists — read the file path from the JSON on stdin instead.

published 10 Jun 2026 updated 06 Sept 2026 checked against docs 06 Sept 2026 4 min in Claude Code commands Markdown

Step 3 of 6 · Make Claude Code yours

On this page6 sections
  1. 1. Pick an event
  2. 2. Add it to settings.json
  3. 3. Read the path from stdin
  4. 4. Confirm it loaded
  5. 5. Block something
  6. If it fails

Hooks run a shell command automatically on Claude Code events — format after every edit, block edits to a protected path, log what ran. They live in your settings files and run as ordinary code, so they do what a prompt can only ask for.

Read this first if you’re porting an old hook: $CLAUDE_FILE_PATHS no longer exists. Hooks receive a JSON object on stdin, and the file path lives at .tool_input.file_path. The environment variable that does exist is ${CLAUDE_PROJECT_DIR}.

1. Pick an event

PreToolUse (before a tool runs, and able to block it), PostToolUse (after — format, lint, test), UserPromptSubmit, SessionStart, SessionEnd and Stop cover almost everything. The matcher filters by tool name.

2. Add it to settings.json

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/format.sh" }
        ]
      }
    ]
  }
}

What it does: runs one script after every Edit or Write. Put it in .claude/settings.json for the project or ~/.claude/settings.json for yourself — see which settings file wins.

3. Read the path from stdin

#!/bin/bash
# .claude/hooks/format.sh
file=$(jq -r '.tool_input.file_path')
[ -f "$file" ] && npx prettier --write "$file"

What it does: parses the hook’s stdin JSON with jq and formats the one file that changed. This is the modern replacement for the old $CLAUDE_FILE_PATHS one-liner.

4. Confirm it loaded

/hooks

What it does: opens a read-only browser of every configured hook, its matcher, its handler type and which settings file it came from. No restart is needed — direct edits to hooks in settings files are picked up by the file watcher.

5. Block something

A PreToolUse hook that exits with code 2 blocks the action and shows stderr as the reason. Any other non-zero code is a non-blocking error and the action proceeds.

If it fails

If /hooks doesn’t list it, the JSON is malformed — claude doctor names what it dropped. If it lists but never fires, the matcher doesn’t match the tool name. Hooks run without a controlling terminal, so anything interactive hangs until it times out.

Start with one harmless formatting hook before you write a blocking one: a bad matcher gets in your way all day. Hooks are real guardrails rather than instructions, which is what separates them from permissions prompts. They run unattended in headless CI too, so read one carefully.

Source: Claude Code hooks reference.

← All Claude Code commands plates · Search all guides

↑↓ move↵ openalt+↵ copy first command

Keyboard

⌘/ctrl+K or /
Search all guides
alt+↵
In search: copy the guide's first command
j / k
Move through a list of guides
c
On a guide: copy its first command
t
Toggle light / dark
?
This list