CLAUDE LABJP
SWE-BENCH — Claude Opus 4.8 scores 69.2% on SWE-Bench Pro, topping GPT-5.5 and Gemini 3.1 Pro (May)TOKYO — Code with Claude heads to Tokyo on June 10, its first Asia stop after SF and London (Jun)LIMITS — Claude Code raises weekly limits by 50% for all Pro/Max/Team/Enterprise users through July 13 (Jun)EFFORT — claude.ai now lets users control how much effort Claude puts into a task (Jun)SPEED — Opus 4.8's fast mode runs 2.5x faster at the same price as Opus 4.7 (May)WORKFLOW — Claude Code's Dynamic Workflows distribute work across hundreds of parallel subagents (May)SWE-BENCH — Claude Opus 4.8 scores 69.2% on SWE-Bench Pro, topping GPT-5.5 and Gemini 3.1 Pro (May)TOKYO — Code with Claude heads to Tokyo on June 10, its first Asia stop after SF and London (Jun)LIMITS — Claude Code raises weekly limits by 50% for all Pro/Max/Team/Enterprise users through July 13 (Jun)EFFORT — claude.ai now lets users control how much effort Claude puts into a task (Jun)SPEED — Opus 4.8's fast mode runs 2.5x faster at the same price as Opus 4.7 (May)WORKFLOW — Claude Code's Dynamic Workflows distribute work across hundreds of parallel subagents (May)
Articles/Claude Code
Claude Code/2026-04-10Advanced

Claude Code Hooks Master Guide — 18 Events and Production Workflow Automation

A practical guide to Claude Code Hooks covering all 4 hook types and 18 events. Includes 5 production-ready automation recipes and safe error handling with StopFailure.

claude-code174hooks20automation98workflow47productivity26

Claude Code Hooks are user-defined shell commands that run automatically at specific points in the Claude Code lifecycle. Rather than hoping the AI "decides" to do something, hooks guarantee it happens every single time. That shift from probabilistic to deterministic control is what makes hooks so powerful for production workflows.

The March 2026 update brought major expansions: MCP elicitation support, StopFailure for hard blocks, transcript search, additional hook events, subprocess credential scrubbing, and more. With these additions, hooks have matured into a full-featured automation layer that belongs in every serious Claude Code setup.

The Core Concept — Why Deterministic Control Matters

When Claude Code works autonomously—writing files, running commands, editing code—it's remarkably capable. But capability isn't the same as predictability. "Please always run the formatter" works most of the time, but "most of the time" isn't good enough when you're protecting production databases or enforcing team coding standards.

Hooks solve this by intercepting actions at precisely the right moment. They're lifecycle event listeners that let you attach custom logic to Claude Code's execution pipeline. The AI still makes creative decisions about what code to write, but the rules around that code—formatting, validation, security checks—are enforced mechanically.

Think of it this way: the AI handles the "what" while hooks handle the "always." That combination of creativity and reliability is what makes Claude Code genuinely production-ready.

Understanding the Four Hook Types

Claude Code Hooks are organized into four types, each corresponding to a different phase of the execution lifecycle.

PreToolUse — Intercepting Before Execution

PreToolUse fires just before a tool runs. It acts as a gatekeeper: you can block dangerous operations, validate inputs, or inject warnings. The hook receives the tool name and input as environment variables, and its exit code determines what happens next.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "python3 /scripts/validate-command.py \"$TOOL_INPUT\"",
        "description": "Block dangerous command execution"
      }
    ]
  }
}

If the hook exits with code 0, execution proceeds normally. Any stdout output gets passed to Claude as context. Exit code 2 triggers a StopFailure, which we'll cover in detail later.

PostToolUse — Automating After Completion

PostToolUse fires immediately after a tool completes successfully. This is where you put automatic formatting, linting, test execution, notifications—anything that should happen as a consequence of a tool's action.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "npx prettier --write \"$FILEPATH\" 2>/dev/null || true",
        "description": "Auto-format files after editing"
      }
    ]
  }
}

SessionStart — Initializing Context

SessionStart fires when a Claude Code session begins. It's perfect for injecting project-specific context, loading team conventions, or setting up environment variables that Claude should know about.

{
  "hooks": {
    "SessionStart": [
      {
        "command": "cat /project/.context/team-rules.md",
        "description": "Auto-load project rules on session start"
      }
    ]
  }
}

Stop — Wrapping Up

Stop fires when Claude finishes a response or the session ends. Use it for logging, cleanup, or sending notifications when Claude needs human input.

{
  "hooks": {
    "Stop": [
      {
        "command": "echo \"[$(date)] Session ended\" >> /project/.logs/claude-sessions.log",
        "description": "Log session completion"
      }
    ]
  }
}

The Complete Event Catalog — All 18 Events

The March 2026 update expanded the event catalog to 18 distinct events. You don't need to memorize all of them, but understanding the categories helps you quickly find the right hook for your use case.

File Operation Events (5)

Write, Edit, MultiEdit, FileRead, and DirectoryRead. These are the most frequently used events for quality control. Write and Edit are essential for auto-formatting and linting; FileRead and DirectoryRead are useful for access control and audit logging.

Command Execution Events (3)

Bash, BashStreaming, and SubProcess. Bash is the workhorse for blocking dangerous commands. SubProcess, added in March 2026, fires during subprocess creation and supports credential scrubbing to prevent secret leakage in logs.

Search and Analysis Events (4)

Grep, Glob, WebSearch, and TranscriptSearch. TranscriptSearch is a new March 2026 addition that fires when searching past session transcripts. You can use it to filter results or log search patterns for team insights.

Communication Events (3)

UserMessage, AssistantMessage, and MCPElicitation. MCPElicitation handles additional information requests from MCP servers, giving you control over how external tools interact with Claude during a session.

Session Management Events (3)

SessionStart, SessionResume, and Stop. SessionResume fires when a paused session is resumed, letting you automatically restore the previous working context. This is particularly useful for long-running development tasks that span multiple sittings.

Configuration Files and Priority

Hooks are defined in JSON and can be set at three levels, with a clear priority hierarchy.

Project Level (.claude/settings.json)

This lives in your project root and gets committed to Git, ensuring every team member runs the same hooks. It's the right place for formatting rules, security blocks, and CI integration.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "bash /scripts/block-dangerous-commands.sh \"$TOOL_INPUT\"",
        "description": "Prevent direct production operations"
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "npx eslint --fix \"$FILEPATH\" 2>/dev/null; npx prettier --write \"$FILEPATH\" 2>/dev/null || true",
        "description": "Auto-run ESLint + Prettier"
      }
    ]
  }
}

User Level (~/.claude/settings.json)

Personal preferences that don't need to be shared: notification endpoints, local tool paths, personal productivity scripts.

Session Level

Temporary overrides for a specific session—useful for enabling verbose logging during a debugging session, for example.

Priority flows from most specific to least: Session > User > Project. When multiple hooks are defined for the same event, they all execute in sequence. However, a single StopFailure in a PreToolUse chain halts the entire tool execution immediately.

Five Production-Ready Automation Recipes

Let's get practical. These are battle-tested patterns that deliver immediate value in real projects.

Recipe 1: Auto-Format and Lint on Every File Change

The single most impactful automation. Every file Claude edits gets automatically formatted and linted, with language-appropriate tools selected by file extension.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "command": "bash -c 'FILE=\"$FILEPATH\"; EXT=\"${FILE##*.}\"; case \"$EXT\" in ts|tsx|js|jsx) npx prettier --write \"$FILE\" && npx eslint --fix \"$FILE\" 2>/dev/null;; py) black \"$FILE\" 2>/dev/null && ruff check --fix \"$FILE\" 2>/dev/null;; rs) rustfmt \"$FILE\" 2>/dev/null;; esac; exit 0'",
        "description": "Language-aware auto-formatting"
      }
    ]
  }
}

The key insight is matching the formatter to the file type. TypeScript gets Prettier plus ESLint, Python gets Black plus Ruff, Rust gets rustfmt. The exit 0 at the end ensures formatting errors don't block Claude's workflow.

Recipe 2: Dangerous Command Blocking

A critical safety net for any team that values their production environment.

#!/bin/bash
# /scripts/block-dangerous-commands.sh
INPUT="$1"
 
# Define dangerous patterns
DANGEROUS_PATTERNS=(
  "rm -rf /"
  "git push.*--force"
  "git push.*-f"
  "DROP TABLE"
  "DROP DATABASE"
  "chmod 777"
  "> /dev/sda"
  "mkfs"
  ":(){:|:&};:"
)
 
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
  if echo "$INPUT" | grep -qiE "$pattern"; then
    echo "BLOCKED: Dangerous command detected: $pattern"
    echo "This command has been blocked for safety."
    exit 2  # Trigger StopFailure
  fi
done
 
exit 0

Exit code 2 triggers StopFailure, which completely prevents the tool from executing. Exit code 1 logs an error but may allow continued execution. Exit code 2 is an explicit "no, absolutely not."

Recipe 3: Slack and Discord Notifications

Keep developers in the loop without requiring them to watch the terminal. Send a notification when Claude needs input or finishes a long task.

{
  "hooks": {
    "Stop": [
      {
        "command": "bash -c 'if [ \"$STOP_REASON\" = \"needs_input\" ]; then curl -s -X POST \"$SLACK_WEBHOOK_URL\" -H \"Content-Type: application/json\" -d \"{\\\"text\\\": \\\"Claude Code is waiting for input: $SESSION_NAME\\\"}\"; fi'",
        "description": "Notify Slack when waiting for input"
      }
    ]
  }
}

Recipe 4: Automatic Context Injection at Session Start

Load project conventions, recent changes, and team guidelines automatically so Claude starts every session with full context.

{
  "hooks": {
    "SessionStart": [
      {
        "command": "bash -c 'echo \"=== Project Context ===\"; cat .claude/CONTEXT.md 2>/dev/null; echo \"\\n=== Recent Changes ===\"; git log --oneline -10 2>/dev/null; echo \"\\n=== Active Branch ===\"; git branch --show-current 2>/dev/null'",
        "description": "Auto-inject project context"
      }
    ]
  }
}

Recipe 5: CI Pipeline Integration

Automatically run relevant tests after file changes. Test failures get fed back to Claude, creating a tight quality feedback loop.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "bash -c 'FILE=\"$FILEPATH\"; if [[ \"$FILE\" == *.test.* ]] || [[ \"$FILE\" == *__tests__* ]]; then npx jest --testPathPattern=\"$FILE\" --no-coverage 2>&1 | tail -20; elif [[ \"$FILE\" == *.ts ]] || [[ \"$FILE\" == *.tsx ]]; then npx tsc --noEmit 2>&1 | head -20; fi; exit 0'",
        "description": "Auto-run tests on test file changes"
      }
    ]
  }
}

StopFailure — The Hard Block You Need

StopFailure, introduced in March 2026, is arguably the most important safety feature in the hooks system. When a PreToolUse hook returns exit code 2, the tool execution is immediately and unconditionally halted. Claude receives the error message as feedback and can suggest alternatives.

Before StopFailure, the only options were exit 0 (proceed) and exit 1 (error, but potentially continue). This left a gap: there was no way to absolutely guarantee that a dangerous operation would be prevented. StopFailure closes that gap.

#!/bin/bash
# StopFailure usage patterns
# exit 0 — Success. Tool execution proceeds
# exit 1 — Error logged, but execution may continue
# exit 2 — StopFailure. Tool execution halted immediately
 
# Example: Block production database connections
if echo "$TOOL_INPUT" | grep -q "production-db"; then
  echo "ERROR: Direct connections to production database are blocked."
  echo "Please use the staging environment (staging-db) instead."
  exit 2  # StopFailure — absolutely no execution
fi
 
# Example: Warn about deprecated APIs (but don't block)
if echo "$TOOL_INPUT" | grep -q "deprecated-api"; then
  echo "WARNING: This API is deprecated. Consider migrating to the new API."
  exit 0  # Warning only. Execution continues
fi

A best practice: always include a specific, actionable reason in your StopFailure messages. Claude reads the error output and uses it to suggest alternatives, which creates a productive feedback loop for the developer.

MCP Elicitation Integration

MCP elicitation support means hooks can now control the interaction flow between Claude and external MCP servers. When an MCP server requests additional information, the MCPElicitation event fires, and your hook can intercept and respond.

A practical example: automatically providing authentication credentials when an MCP server requests them, pulling from environment variables or a secret manager rather than prompting the user.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "MCPElicitation",
        "command": "bash -c 'if echo \"$TOOL_INPUT\" | grep -q \"auth_required\"; then echo \"{\\\"token\\\": \\\"$(cat ~/.secrets/mcp-token)\\\"}\"; fi'",
        "description": "Auto-respond to MCP authentication requests"
      }
    ]
  }
}

Combined with the SubProcess event, you can also ensure that credentials are scrubbed from subprocess logs—an essential security measure for teams handling sensitive data.

Operational Best Practices and Troubleshooting

A few important considerations for running hooks in production.

Testing Your Hooks

Hook commands are regular shell scripts, so you can test them independently. Mock the environment variables ($TOOL_INPUT, $FILEPATH, $STOP_REASON) and verify the expected exit codes and output.

# Test a blocking hook
TOOL_INPUT='{"command": "rm -rf /"}' bash /scripts/block-dangerous-commands.sh "$TOOL_INPUT"
echo "Exit code: $?"  # Should be 2 for a successful block

Performance Considerations

PostToolUse hooks run frequently, so keep them fast. Heavy operations should run in the background or target only changed files. A slow formatter that adds 3 seconds to every edit will quickly become frustrating.

Debugging Tips

If a hook isn't firing as expected, check the matcher first. Matchers use pipe-delimited string matching, not regex. Write|Edit means "Write or Edit," but Write.* won't work—it's not a regular expression.

Team Governance

Project-level hooks affect everyone on the team, so treat .claude/settings.json like any other piece of shared infrastructure. Use pull requests for changes, require code review, and document the purpose of each hook clearly.

Wrapping Up

Claude Code Hooks bridge the gap between AI flexibility and deterministic reliability. With four hook types and eighteen events at your disposal, you can automate virtually any aspect of your development workflow while maintaining strict quality and security guarantees.

Start with the highest-impact automations—auto-formatting and dangerous command blocking—then gradually add project-specific hooks as your needs evolve. Once you've experienced the peace of mind that comes from deterministic control, you won't want to go back to hoping the AI remembers to run the formatter.

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-03-24
Claude Code Hooks— Practical Techniques to Automate Your Dev Workflow
Learn how to automate your development workflow with Claude Code Hooks. From PreToolUse and PostToolUse configuration to automated code review, security checks, and deployment pipeline integration.
Claude Code2026-05-06
Parallel Development with Claude Code Across Multiple Repos — What Three Simultaneous Projects Taught Me
Claude Code gets messy with multiple repos. Here are the CLAUDE.md strategies, session habits, and cost tips from three months of real parallel development.
Claude Code2026-05-01
/clear vs /compact in Claude Code: Choosing the Right Reset for Long Sessions
When should you use /clear, and when should you reach for /compact in Claude Code? Three decision criteria from real long-session experience, with the pitfalls that hit me before I figured it out.
📚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 →