Advanced

Mastering Claude Code Hooks: Auto-Format, Auto-Test, and More

Mastering Claude Code Hooks: Auto-Format, Auto-Test, and More. A practical guide with code examples.

What Are Hooks?

Claude Code hooks let you automatically run custom commands before or after specific actions. You can set up auto-formatting after file saves, auto-run tests after code changes, and much more.

Hooks are defined in .claude/settings.json and execute shell commands when Claude Code performs certain operations.

Hook Types

Claude Code supports hooks at the following event points:

Hook EventWhen It Fires
PreToolUseBefore a tool is executed
PostToolUseAfter a tool is executed
NotificationWhen a notification is sent
StopWhen Claude Code finishes responding

Basic Configuration

Hooks are defined in the hooks field of .claude/settings.json:

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

Configuration Structure

  • matcher: A regex pattern that matches the tool name triggering the hook
  • command: The shell command to execute

Use Case 1: Auto-Formatting

Automatically run Prettier after any file edit:

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

With this setup, every time Claude Code creates or edits a file, Prettier formats it automatically. Your team’s coding style stays consistent without any manual effort.

Use Case 2: Auto-Linting

Here’s how to integrate ESLint auto-fix:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "npx eslint --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
      }
    ]
  }
}

The || true suffix prevents lint errors from causing the hook to fail, allowing Claude Code to continue processing.

Use Case 3: Auto-Testing on Change

Automatically run related tests after file edits and feed back the results:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "npx vitest related \"$CLAUDE_FILE_PATH\" --run 2>&1 | tail -20"
      }
    ]
  }
}

Vitest’s related option runs only the tests relevant to the changed file, giving you much faster feedback than a full test suite.

Use Case 4: Auto Type-Checking

Run TypeScript type checking after file changes:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "npx tsc --noEmit 2>&1 | head -30"
      }
    ]
  }
}

Use Case 5: Blocking Dangerous Commands

A PreToolUse hook that prevents execution of risky commands:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "if echo \"$CLAUDE_TOOL_INPUT\" | grep -qE 'rm -rf|drop table|git push.*force'; then echo 'BLOCKED: Dangerous command detected' >&2; exit 1; fi"
      }
    ]
  }
}

When the hook exits with code 1, Claude Code skips the tool execution entirely.

Use Case 6: Completion Notifications

Send a notification when Claude Code finishes a task:

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "command": "notify-send 'Claude Code' 'Task completed' 2>/dev/null; echo 'Done'"
      }
    ]
  }
}

On macOS, you can use:

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "command": "osascript -e 'display notification \"Task completed\" with title \"Claude Code\"'"
      }
    ]
  }
}

Combining Multiple Hooks

In real projects, combining several hooks is the most effective approach:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "if echo \"$CLAUDE_TOOL_INPUT\" | grep -qE 'rm -rf /'; then exit 1; fi"
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
      },
      {
        "matcher": "Write|Edit",
        "command": "npx eslint --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
      }
    ],
    "Stop": [
      {
        "matcher": "",
        "command": "echo '✓ Task completed'"
      }
    ]
  }
}

Tips for Writing Hooks

1. Keep Execution Time Short

Hooks run synchronously, so heavy operations will slow down Claude Code’s responses. Use options like related to narrow test scope, and head or tail to trim output.

2. Handle Errors Gracefully

A hook that exits with an error can disrupt Claude Code’s workflow. Use || true and 2>/dev/null to keep things safe.

3. Use Environment Variables

Take advantage of the environment variables available in hooks. $CLAUDE_FILE_PATH gives you the path of the file being operated on.

Conclusion

Hooks let you heavily customize Claude Code’s workflow. The combination of auto-formatting and auto-testing is especially powerful for maintaining code quality. Start with Prettier auto-formatting and build from there.

#Claude Code #hooks #automation #formatting #testing
Free

Free PDF: Claude Code Cheatsheet in 5 Minutes

Just enter your email and we'll send you the single-page A4 cheatsheet right away.

We handle your data with care and never send spam.

Level up your Claude Code workflow

50 battle-tested prompt templates you can copy-paste into Claude Code right now.

Masa

About the Author

Masa

Engineer obsessed with Claude Code. Runs claudecode-lab.com, a 10-language tech media with 2,000+ pages.