Hooks

All plans1 min read

Step 1: Claude Code prepares an action

For example, Claude Code is about to write to a file using the Edit tool

Step 2: PreToolUse hook runs

Your configured command executes. It can approve, block, or modify the action

Step 3: Action executes

If the hook approved it (or no PreToolUse hook exists), the tool call proceeds normally

Step 4: PostToolUse hook runs

After the action completes, your post-action command runs. Auto format, lint, notify, etc.

Start with auto formatting

The highest impact hook for most teams is a PostToolUse hook that runs your formatter (Prettier, Black, gofmt, etc.) after every file edit. This ensures Claude Code's output always matches your code style, eliminating formatting nits from code reviews. Add it to your project's .claude/settings.json so the whole team benefits.

Example: Auto-format TypeScript files after edits

In your .claude/settings.json, add a PostToolUse hook that runs Prettier whenever Claude Code edits a file:

{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Edit|Write",
      "command": "npx prettier --write $CLAUDE_FILE_PATH"
    }]
  }
}

Example: Block writes to generated files

A PreToolUse hook that prevents Claude Code from modifying auto-generated files:

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Edit|Write",
      "command": "echo $CLAUDE_FILE_PATH | grep -q 'generated/' && exit 1 || exit 0"
    }]
  }
}
Hook TypeWhen it runsCommon uses
PreToolUsePreToolUseBefore a tool call executesBlock writes to protected files, validate commands, require approval
PostToolUsePostToolUseAfter a tool call completesAuto format code, run linters, update lock files, log changes
NotificationNotificationWhen Claude Code sends a notificationDesktop alerts, Slack messages, sound effects, email notifications

Environment variables in hooks

Hooks receive context through environment variables. $CLAUDE_FILE_PATH contains the path of the file being modified. $CLAUDE_TOOL_NAME contains the name of the tool being called (Edit, Write, Bash, etc.). Your hook commands can use these to make targeted decisions, like only formatting TypeScript files or only validating Bash commands that match certain patterns.