CLAUDE LABJP
ULTRACODE — Claude Code renames its Dynamic Workflows trigger to ultracode, orchestrating tens to hundreds of agents (Jun)EFFORT — Claude Code now defaults to high effort, spending more reasoning on hard problems (Jun)GLASSWING — Project Glasswing expands to ~150 orgs; Claude Security scans codebases and suggests patches (Jun)SWE-BENCH — Claude Opus 4.8 scores 69.2% on SWE-Bench Pro, topping GPT-5.5 and Gemini 3.1 Pro (May)COPILOT — Claude Opus 4.8 is now generally available in GitHub Copilot (May)POLISH — Claude Code fixes Windows/WSL/voice/vim/IME issues and launches more quietly (Jun)ULTRACODE — Claude Code renames its Dynamic Workflows trigger to ultracode, orchestrating tens to hundreds of agents (Jun)EFFORT — Claude Code now defaults to high effort, spending more reasoning on hard problems (Jun)GLASSWING — Project Glasswing expands to ~150 orgs; Claude Security scans codebases and suggests patches (Jun)SWE-BENCH — Claude Opus 4.8 scores 69.2% on SWE-Bench Pro, topping GPT-5.5 and Gemini 3.1 Pro (May)COPILOT — Claude Opus 4.8 is now generally available in GitHub Copilot (May)POLISH — Claude Code fixes Windows/WSL/voice/vim/IME issues and launches more quietly (Jun)
Articles/Claude Code
Claude Code/2026-04-02Intermediate

Practical Guide to Claude Code Hooks: Building Automated Workflows in Practice

A systematic guide to Claude Code Hooks. Learn how to use PreToolUse, PostToolUse, Stop, and Notification hooks to automate code quality checks, logging, notifications, and more.

Claude Code239Hooks6Automation31Workflow15Developer Productivity5

Claude Code Hooks give you a precise way to weave your intentions into AI-assisted coding sessions. By injecting custom scripts before and after tool calls, you can automate repetitive tasks like code quality checks, activity logging, and external notifications — turning a good development flow into a great one.

What Are Claude Code Hooks?

Claude Code Hooks let you run shell commands or scripts at specific moments during a Claude Code session — before or after any tool is executed. Instead of the traditional loop of "AI works → human reviews → move on," Hooks enable a more refined cycle: "AI works → automated verification/notification → move on."

Here are a few scenarios where Hooks really shine:

Automatic code quality checks: Run a linter or formatter every time Claude edits a file and catch issues immediately.

Change history logging: Record which files were touched and when, making debugging and audits far easier.

External service notifications: Integrate with Slack or email to automatically alert team members when key tasks are completed.

Security guardrails: Detect access to sensitive files and block the operation if needed.

The Hooks Configuration File

Hooks are configured in ~/.claude/settings.json (global) or .claude/settings.json at the project root (project-specific). Here's a basic example:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo '🔧 Pre-Bash: $CLAUDE_TOOL_INPUT' >> /tmp/claude-hooks.log"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "cd $CLAUDE_PROJECT_DIR && npx eslint --fix $CLAUDE_TOOL_INPUT_FILE_PATH 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}

Each entry specifies a matcher (the tool name to target) and a command to run. The configuration is straightforward JSON — easy to version-control and share with your team.

The Four Hook Types

Claude Code supports four distinct timing points for running scripts. Understanding each one is the foundation of effective Hooks usage.

PreToolUse: Runs Before a Tool Executes

PreToolUse fires immediately before Claude calls a tool. Its standout feature is the ability to block the tool from running based on your script's exit code: exit 0 to allow the tool to proceed, or exit non-zero to stop it.

This makes PreToolUse ideal for access control and catching dangerous operations before they happen.

#!/bin/bash
# Example: Block direct production deployments
TOOL_INPUT="$CLAUDE_TOOL_INPUT"
if echo "$TOOL_INPUT" | grep -q "production" && echo "$TOOL_INPUT" | grep -q "deploy"; then
  echo "⚠️  Production deployments require a review step."
  exit 1  # Block the tool call
fi
exit 0  # Allow normally

PostToolUse: Runs After a Tool Completes

PostToolUse fires right after a tool finishes. Since you have access to the tool's output, it's perfect for post-processing and verification.

Auto-formatting after edits is one of the most popular uses:

#!/bin/bash
# Example: Auto-run Prettier after every Edit
FILE="$CLAUDE_TOOL_INPUT_FILE_PATH"
if [[ "$FILE" =~ \.(js|ts|jsx|tsx|json|css)$ ]]; then
  npx prettier --write "$FILE" 2>/dev/null
  echo "✅ Formatted: $FILE"
fi

Stop: Fires When Claude Code Finishes a Session

The Stop hook runs exactly once when Claude Code ends a session. It's a natural fit for completion notifications and generating final summaries.

#!/bin/bash
# Example: Send a Slack notification on session end
SESSION_ID="$CLAUDE_SESSION_ID"
curl -s -X POST "$SLACK_WEBHOOK_URL" \
  -H 'Content-type: application/json' \
  -d "{\"text\":\"✅ Claude Code session finished (ID: ${SESSION_ID})\"}"

Notification: Fires on Notification Events

The Notification hook runs when Claude Code emits a notification — for example, when it pauses waiting for user input. This is useful for relaying mid-session status updates to external systems during long-running tasks.

Environment Variables Available in Hooks

When a Hook script runs, Claude Code automatically sets several environment variables so your script has the context it needs:

| Variable | Description | |---|---| | CLAUDE_TOOL_NAME | Name of the tool being called (e.g., Bash, Edit) | | CLAUDE_TOOL_INPUT | Raw input passed to the tool (JSON) | | CLAUDE_TOOL_INPUT_FILE_PATH | File path when the Edit tool is used | | CLAUDE_PROJECT_DIR | Root directory of the current project | | CLAUDE_SESSION_ID | Unique identifier for the session | | CLAUDE_HOOK_EVENT_NAME | Name of the hook event that fired |

Combining these variables lets you write scripts that adapt to context — applying different logic depending on the tool, file type, or project.

Controlling Scope with the matcher Field

The matcher field determines which tools trigger a given hook. You can use exact tool names or regular expressions.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/auto-lint.sh"
          }
        ]
      }
    ]
  }
}

The example above triggers the lint script after both Edit and Write tool calls. Setting matcher to an empty string will match all tools.

Practical Recipes

Recipe 1: Automatic TypeScript Type Checking

#!/bin/bash
# auto-typecheck.sh
FILE="$CLAUDE_TOOL_INPUT_FILE_PATH"
if [[ "$FILE" =~ \.tsx?$ ]]; then
  cd "$CLAUDE_PROJECT_DIR"
  npx tsc --noEmit --skipLibCheck 2>&1 | head -20
fi
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [{ "type": "command", "command": "/path/to/auto-typecheck.sh" }]
      }
    ]
  }
}

Recipe 2: Secret Detection in Code

Prevent accidental commits of API keys, passwords, and other credentials:

#!/bin/bash
# secret-detector.sh
FILE="$CLAUDE_TOOL_INPUT_FILE_PATH"
PATTERNS="(API_KEY|SECRET|PASSWORD|TOKEN|PRIVATE_KEY)\s*=\s*['\"][^'\"]{8,}"
 
if [ -f "$FILE" ] && grep -qE "$PATTERNS" "$FILE"; then
  echo "🚨 Potential secret detected in: $FILE"
  grep -nE "$PATTERNS" "$FILE" | head -5
  exit 1  # Block the write
fi
exit 0

Recipe 3: Automatic Activity Logging

#!/bin/bash
# activity-logger.sh
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
TOOL="$CLAUDE_TOOL_NAME"
FILE="${CLAUDE_TOOL_INPUT_FILE_PATH:-N/A}"
LOG_FILE="$HOME/.claude/activity.log"
 
echo "[$TIMESTAMP] $TOOL$FILE" >> "$LOG_FILE"

Set this as a PostToolUse hook with an empty matcher, and every Claude Code action gets recorded to ~/.claude/activity.log automatically.

Recipe 4: Automatic Test Runs

#!/bin/bash
# auto-test.sh
FILE="$CLAUDE_TOOL_INPUT_FILE_PATH"
PROJECT_DIR="$CLAUDE_PROJECT_DIR"
 
if [[ "$FILE" =~ \.(test|spec)\.(js|ts)$ ]]; then
  cd "$PROJECT_DIR"
  npx jest "$FILE" --passWithNoTests 2>&1 | tail -10
fi

Tips for Safe and Reliable Hooks

Because Hooks execute shell commands directly, a misconfiguration can have unintended consequences. Keep these practices in mind:

Handle errors gracefully: Avoid set -e indiscriminately — use || true when you intentionally want a command to fail without stopping the Hook.

Set execute permissions: Don't forget chmod +x your-script.sh. If a Hook silently does nothing, missing permissions are often the culprit.

Use debug logging: While developing your scripts, write debug output to a log file (echo "debug info" >> /tmp/hooks-debug.log). It makes diagnosing issues much faster.

Design for idempotency: Hooks may run multiple times. Make sure running the same Hook twice in a row won't cause problems — especially for scripts that create files or modify state.

Closing Thoughts: Build a Smarter Development Environment

Once configured, Claude Code Hooks quietly do their job every session — enforcing quality, recording history, and keeping you in the loop without any extra effort. Start small with a simple activity log, then layer in auto-formatting and security checks as you go.

The goal is a virtuous cycle: "AI works → quality is automatically ensured → you focus on what matters most." With the right Hooks in place, that cycle becomes your everyday reality.


🌟 Go Deeper with Premium Content

Claude Lab offers premium articles that take Hooks even further:

  • Combining MCP servers with Hooks — building advanced workflows that talk to external APIs
  • Team-wide Hooks standardization — best practices for sharing Hook configs across an organization
  • Claude Code + CI/CD integration — practical recipes for connecting Claude Code to GitHub Actions

Premium membership (from ¥280/month) gives you full access to all of these deep-dive articles. If you want to get the most out of Claude AI in your daily development work, we'd love to have you on board.

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Claude Code2026-04-27
Claude Code Hooks: A Complete Field Guide to All 8 Hook Types and How to Pick the Right One
Claude Code hooks are powerful, but most people give up before figuring out which event does what. Here's the field guide I wish I had when I started — six months of running hooks in production, distilled.
Claude Code2026-05-05
Building a Zero-Touch Code Review Environment with Claude Code Hooks
Learn how to use Claude Code's hook system to automatically review code on every tool execution. Covers PostToolUse, Stop hooks, and the pitfalls to avoid when implementing PreToolUse blockers.
Claude Code2026-04-04
Design to Code with Stitch, Figma Make, and Claude Code
Learn a 3-stage workflow: generate design concepts with Stitch, refine them in Figma Make, then auto-implement with Claude Code and Figma MCP.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →