Skillzwave

Claude Code Hooks: Making AI Deterministic

Updated
14 min read

One of the main challenges in AI development has been the struggle between AI's creative skills and its dependability. Hooks transform AI systems from probabilistic helpers into reliable tools with guaranteed actions.

Diagram showing how deterministic hooks transform AI from suggestions to guarantees
Deterministic hooks: from suggestions to guarantees in AI development

In This Guide

  • 1. The fundamental challenge: creativity vs determinism
  • 2. Understanding hooks: the building blocks of determinism
  • 3. Hook event types: PreToolUse, PostToolUse, Notification, Stop
  • 4. Real-world examples: code formatting and security guardrails

The Fundamental Challenge: Creativity vs Determinism

Large language models are fundamentally probabilistic. They're designed to predict the next best word, which is what makes them so incredibly creative. But what happens when you don't need creativity? What if you require a rock-solid, deterministic part of your workflow?

Here's the problem we've all faced: You can tell an LLM in a prompt, "Hey, always format the code using this style guide." But after a long and complex conversation, it might simply forget. Suddenly, its greatest strength becomes a real weakness. That creativity you loved? Now it causes inconsistency.

From Suggestions to Guarantees

Normal Prompt Instruction

A suggestion. A polite request that the AI might follow if it remembers.

Claude Code Hook

A command. A programmatic rule that the AI is absolutely required to execute every single time.

This is not a minor feature. It's a fundamental shift in how we control AI agents. We're moving beyond just prompting and crossing our fingers. We're now embedding rules directly into the AI's core operational loop. We're literally turning our suggestions into law.

Understanding Hooks: The Building Blocks of Determinism

A hook is a shell command you define that runs automatically and reliably at a very precise point in Claude's execution loop. The key words here are automatic and reliable.

Hook lifecycle diagram showing checkpoints in Claude's execution flow
The hook lifecycle: intercept and inject rules at precisely the right times

At its core, Claude's entire operation is event-driven. Think of it like a series of checkpoints in a video game:

  • The moment you submit a prompt? That's a checkpoint.
  • Right before Claude uses a tool? Another checkpoint.
  • After a tool completes successfully? Yet another checkpoint.

Hooks are how we insert our own custom logic into those checkpoints. We intercept the flow and add our rules at precisely the right times.

The Four Types of Hook Events

These checkpoints are perfect for different jobs. Claude Code provides four main hook event types:

PreToolUse

Your security guard. It runs before a tool is used, so you can inspect what's about to happen and even block it if it looks dangerous.

PostToolUse

The cleanup crew. It runs after a tool succeeds, allowing you to enforce standards, such as running a code formatter.

Notification

Your pager. It buzzes you when Claude needs your help or when something important happens.

Stop

Session bookend. It fires when Claude's session ends, perfect for final logging or cleanup.

Anatomy of a Hook: Three Simple Parts

Every hook consists of just three simple parts:

  1. Event - The trigger (like PostToolUse)
  2. Matcher - Your filter (like "only match files ending in .js" or tools like "Edit|Write")
  3. Command - The actual shell script that does the work

It's that easy. When, where, and what.

Example 1: Automatic Code Formatting

Let's start with a classic example. You want your code formatted perfectly every single time Claude touches it.

Directory Structure

~/.claude/
  settings.json
  hooks/
    format_code.sh

Hook Configuration

In your .claude/settings.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/hooks/format_code.sh"
          }
        ]
      }
    ]
  }
}

The Formatting Script

Create ~/.claude/hooks/format_code.sh:

#!/usr/bin/env bash
set -e

# Read JSON input from stdin
INPUT=$(cat)

# Extract the file path from the tool response
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_response.filePath // .tool_input.file_path // empty')

# Exit if no file path found
if [ -z "$FILE_PATH" ]; then
    exit 0
fi

# Check file extension and run appropriate formatter
if [[ "$FILE_PATH" == *.js || "$FILE_PATH" == *.jsx ]]; then
    echo "Formatting JavaScript file: $FILE_PATH"
    npx prettier --write "$FILE_PATH"
elif [[ "$FILE_PATH" == *.ts || "$FILE_PATH" == *.tsx ]]; then
    echo "Formatting TypeScript file: $FILE_PATH"
    npx prettier --write "$FILE_PATH"
elif [[ "$FILE_PATH" == *.py ]]; then
    echo "Formatting Python file: $FILE_PATH"
    black "$FILE_PATH" 2>/dev/null || true
elif [[ "$FILE_PATH" == *.go ]]; then
    echo "Formatting Go file: $FILE_PATH"
    gofmt -w "$FILE_PATH"
fi

Make it executable:

chmod +x ~/.claude/hooks/format_code.sh

The event is set to PostToolUse, which means this hook fires after Claude has finished writing to a file. The matcher targets any of the file editing tools. Now your code is automatically formatted based on file type.

Example 2: Security Guardrails

Now let's raise the stakes. This is a security guardrail hook that can save you from disaster.

Hook Configuration

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/hooks/security_check.sh"
          }
        ]
      }
    ]
  }
}

The Security Check Script

#!/usr/bin/env bash
set -e

# Read JSON input from stdin
INPUT=$(cat)

# Extract the command that's about to be run
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

# Define dangerous patterns
DANGEROUS_PATTERNS=(
    "rm -rf /"
    "rm -rf /*"
    "chmod 777"
    "curl.*\|.*bash"
    "wget.*\|.*bash"
)

# Check for dangerous patterns
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
    if echo "$COMMAND" | grep -qE "$pattern"; then
        # Block the command
        echo "{\"continue\": false, \"stopReason\": \"Blocked dangerous command: Pattern '$pattern' detected\"}"
        exit 0
    fi
done

# Check for sudo usage
if echo "$COMMAND" | grep -q "^sudo\|[[:space:]]sudo[[:space:]]"; then
    echo "{\"continue\": false, \"stopReason\": \"Sudo commands require manual approval\"}"
    exit 0
fi

# Allow the command to proceed
echo '{"continue": true}'

This hook shows the real power of PreToolUse. Before Claude can execute any bash command, this script checks against dangerous patterns and blocks them entirely. The command never even executes.

Key Insight: This isn't just a suggestion or a warning. It's a hard guardrail that makes your AI agent dramatically safer to use. You're preventing disasters before they happen.

Key Benefits of Hooks

Code Quality

  • Auto-format code on save
  • Run linters automatically
  • Enforce project conventions

Security

  • Block dangerous commands
  • Protect sensitive files
  • Require approval for sudo

Auditing

  • Log all AI actions
  • Track file changes
  • Enable compliance

Safety Considerations

This level of power is incredible, but it needs to be handled carefully. Hooks run automatically with your user privileges. They have access to your environment. That makes them unbelievably powerful, and it means you must treat them with the same care you'd give to any other executable code.

  • Treat hooks as code (because they are!)
  • Review them carefully before implementing
  • Know exactly what each command does
  • Never run a hook that you don't fully understand and trust

Getting Started

Ready to try hooks yourself? Getting started is easy:

/hooks add

That's it. Claude will launch an interactive editor that walks you through setting up your first hook. Start with something simple like code formatting and work your way up to more complex implementations.

Continue Your Journey

Now that you understand the fundamentals of hooks, you're ready to build a complete audit system:

The Transformation

Hooks give us something we've never really had before: serious, predictable, deterministic control over our AI assistants. This isn't wishful thinking anymore. This is guaranteed behavior.

Now that you can enforce the rules, what will you build?