Download Beam

Claude Code Hooks: 15 Automations Every Developer Should Set Up

February 2026 • 12 min read

Claude Code hooks let you run custom scripts at specific points in the agent’s workflow — before a tool runs, after a tool completes, or when a session starts. They are the difference between an AI agent that needs constant supervision and one that enforces your standards automatically.

Most developers ignore hooks. They should not. A well-configured hook system catches dangerous commands before they execute, formats code automatically, runs tests after every change, and logs everything the agent does. Here are 15 hooks worth setting up, organized by category.

How Hooks Work

Claude Code supports three hook types, each firing at a different point in the agent’s execution cycle:

Hook Types

  • PreToolUse — runs before the agent executes a tool. Can block the tool call by returning a non-zero exit code. Use for safety gates and validation.
  • PostToolUse — runs after a tool completes successfully. Use for formatting, testing, logging, and notifications.
  • SessionStart — runs once when a new Claude Code session begins. Use for environment setup, context loading, and verification checks.

Hooks are configured in .claude/settings.json in your project directory or in ~/.claude/settings.json for global hooks. Each hook specifies the event type, a matcher (which tools or patterns trigger it), and a command to run.

// .claude/settings.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "bash",
        "command": "/path/to/your/script.sh"
      }
    ]
  }
}

The hook receives context about the tool call as JSON via stdin, including the tool name, parameters, and session metadata. Your script can read this, make decisions, and either allow or block the operation.

Safety Hooks (1-5)

1. Block Dangerous Shell Commands

The most important hook you will ever configure. Prevents the agent from running destructive commands like rm -rf, git push --force, or DROP TABLE.

#!/bin/bash
# hooks/block-dangerous.sh
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

BLOCKED_PATTERNS=(
  "rm -rf /"
  "rm -rf ~"
  "rm -rf \."
  "git push.*--force"
  "git reset --hard"
  "DROP TABLE"
  "DROP DATABASE"
  "chmod 777"
  "curl.*| bash"
  "wget.*| sh"
)

for pattern in "${BLOCKED_PATTERNS[@]}"; do
  if echo "$COMMAND" | grep -qiE "$pattern"; then
    echo "BLOCKED: Command matches dangerous pattern: $pattern"
    exit 1
  fi
done

exit 0
This is not optional. Without this hook, a single hallucinated rm -rf can destroy your project. The agent is powerful. Guardrails are essential.

2. Prevent Writes to Protected Files

Some files should never be modified by the agent: CI configurations, lock files, production environment configs. A PreToolUse hook on write_file can enforce this.

#!/bin/bash
# hooks/protect-files.sh
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

PROTECTED=(
  ".github/workflows/"
  ".env.production"
  "package-lock.json"
  "yarn.lock"
  "Dockerfile.production"
)

for protected in "${PROTECTED[@]}"; do
  if [[ "$FILE_PATH" == *"$protected"* ]]; then
    echo "BLOCKED: $FILE_PATH is a protected file"
    exit 1
  fi
done

exit 0

3. Require Confirmation for Destructive Git Operations

Let the agent read git status and log freely, but block any operation that could destroy history or push code without review.

#!/bin/bash
# hooks/git-safety.sh
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

if echo "$COMMAND" | grep -qE "^git (push|rebase|merge|reset|checkout --)"; then
  echo "BLOCKED: Git write operation requires manual execution"
  echo "Command was: $COMMAND"
  exit 1
fi

exit 0

4. Block Network Requests to Unknown Hosts

If the agent tries to curl or wget an unknown URL, block it. This prevents data exfiltration and supply chain attacks from compromised dependencies.

#!/bin/bash
# hooks/network-allowlist.sh
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

ALLOWED_HOSTS=(
  "github.com"
  "registry.npmjs.org"
  "api.anthropic.com"
)

if echo "$COMMAND" | grep -qE "(curl|wget|fetch|http)"; then
  ALLOWED=false
  for host in "${ALLOWED_HOSTS[@]}"; do
    if echo "$COMMAND" | grep -q "$host"; then
      ALLOWED=true
      break
    fi
  done
  if [ "$ALLOWED" = false ]; then
    echo "BLOCKED: Network request to unapproved host"
    exit 1
  fi
fi

exit 0

5. Limit File Size on Writes

Prevent the agent from generating massive files that could exhaust disk space or indicate something went wrong (like dumping a database into a source file).

#!/bin/bash
# hooks/file-size-limit.sh
INPUT=$(cat)
CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // empty')
MAX_LINES=500

LINE_COUNT=$(echo "$CONTENT" | wc -l)

if [ "$LINE_COUNT" -gt "$MAX_LINES" ]; then
  echo "BLOCKED: File write exceeds $MAX_LINES lines ($LINE_COUNT lines)"
  echo "Consider splitting into multiple files"
  exit 1
fi

exit 0

Quality Hooks (6-10)

6. Auto-Format After File Writes

Run Prettier (or your formatter of choice) every time the agent writes a file. The agent’s output is good but not always perfectly formatted. This hook ensures consistency.

#!/bin/bash
# hooks/auto-format.sh
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

if [[ "$FILE_PATH" =~ \.(ts|tsx|js|jsx|json|css|md)$ ]]; then
  npx prettier --write "$FILE_PATH" 2>/dev/null
fi

exit 0

7. Run Lint After Code Changes

Catch lint errors immediately after the agent writes code, rather than discovering them during the next build.

#!/bin/bash
# hooks/auto-lint.sh
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

if [[ "$FILE_PATH" =~ \.(ts|tsx|js|jsx)$ ]]; then
  npx eslint "$FILE_PATH" --fix 2>/dev/null
  if [ $? -ne 0 ]; then
    echo "WARNING: Lint errors found in $FILE_PATH"
  fi
fi

exit 0

8. Run Related Tests After Code Changes

When the agent modifies a source file, automatically run the corresponding test file. This gives the agent immediate feedback on whether its changes break anything.

#!/bin/bash
# hooks/auto-test.sh
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

# Skip if the modified file is itself a test
if [[ "$FILE_PATH" =~ \.(test|spec)\.(ts|tsx|js|jsx)$ ]]; then
  exit 0
fi

# Find corresponding test file
TEST_FILE="${FILE_PATH%.*}.test.${FILE_PATH##*.}"

if [ -f "$TEST_FILE" ]; then
  npx jest "$TEST_FILE" --no-coverage 2>&1
fi

exit 0

9. Type Check After TypeScript Changes

Run tsc --noEmit on modified TypeScript files to catch type errors before they accumulate.

#!/bin/bash
# hooks/type-check.sh
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

if [[ "$FILE_PATH" =~ \.(ts|tsx)$ ]]; then
  npx tsc --noEmit 2>&1 | head -20
fi

exit 0

10. Git Snapshot Before Major Changes

Create an automatic git stash or commit before the agent starts making changes. This gives you a clean rollback point if things go wrong.

#!/bin/bash
# hooks/git-snapshot.sh
# Run as a SessionStart hook
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# Only snapshot if there are changes
if ! git diff --quiet 2>/dev/null; then
  git stash push -m "pre-agent-snapshot-$TIMESTAMP" 2>/dev/null
  git stash pop 2>/dev/null
fi

# Create a WIP commit as a checkpoint
git add -A 2>/dev/null
git commit -m "WIP: pre-agent checkpoint $TIMESTAMP" --no-verify 2>/dev/null

exit 0

Monitoring Hooks (11-15)

11. Log All Tool Calls

Keep a complete audit trail of every tool the agent calls, with timestamps and parameters. Invaluable for debugging and understanding agent behavior.

#!/bin/bash
# hooks/audit-log.sh
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // "unknown"')
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
LOG_FILE=".claude/audit.log"

echo "$INPUT" | jq -c "{timestamp: \"$TIMESTAMP\", tool: .tool_name, input: .tool_input}" \
  >> "$LOG_FILE"

exit 0

12. Track Token Usage Per Session

Log token consumption so you can track costs and identify sessions that are burning through your budget.

#!/bin/bash
# hooks/token-tracker.sh
INPUT=$(cat)
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

echo "$TIMESTAMP,$SESSION_ID,tool_call" >> ".claude/token-usage.csv"

exit 0

13. Desktop Notification on Session Complete

When running long agent tasks, get a native desktop notification so you do not have to keep checking the terminal.

#!/bin/bash
# hooks/notify-complete.sh
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // "unknown"')

# Only notify on the final tool call of a task
if echo "$INPUT" | jq -e '.is_final_tool' > /dev/null 2>&1; then
  osascript -e "display notification \"Agent task completed\" with title \"Claude Code\""
fi

exit 0

14. Auto-Compact on Context Window Threshold

Monitor context window usage and trigger a compaction when it gets too high, preventing the agent from losing context mid-task.

#!/bin/bash
# hooks/auto-compact.sh
INPUT=$(cat)
CONTEXT_USED=$(echo "$INPUT" | jq -r '.context_window_usage // 0')

if (( $(echo "$CONTEXT_USED > 0.8" | bc -l) )); then
  echo "Context window at ${CONTEXT_USED}. Consider running /compact."
fi

exit 0

15. Session Environment Verification

On session start, verify that all required tools and dependencies are available. Catch missing prerequisites before the agent wastes time hitting errors.

#!/bin/bash
# hooks/verify-env.sh
ERRORS=0

# Check Node.js
if ! command -v node &> /dev/null; then
  echo "ERROR: Node.js not found"
  ERRORS=$((ERRORS + 1))
fi

# Check project dependencies
if [ ! -d "node_modules" ]; then
  echo "WARNING: node_modules not found, running npm install..."
  npm install
fi

# Check required env vars
for var in DATABASE_URL API_KEY; do
  if [ -z "${!var}" ]; then
    echo "WARNING: $var not set"
  fi
done

# Check git status
if ! git rev-parse --is-inside-work-tree &> /dev/null 2>&1; then
  echo "WARNING: Not inside a git repository"
fi

exit $ERRORS

Putting It All Together

Here is a complete .claude/settings.json configuration using these hooks:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "bash",
        "command": ".claude/hooks/block-dangerous.sh"
      },
      {
        "matcher": "bash",
        "command": ".claude/hooks/git-safety.sh"
      },
      {
        "matcher": "bash",
        "command": ".claude/hooks/network-allowlist.sh"
      },
      {
        "matcher": "write_file",
        "command": ".claude/hooks/protect-files.sh"
      },
      {
        "matcher": "write_file",
        "command": ".claude/hooks/file-size-limit.sh"
      }
    ],
    "PostToolUse": [
      {
        "matcher": "write_file",
        "command": ".claude/hooks/auto-format.sh"
      },
      {
        "matcher": "write_file",
        "command": ".claude/hooks/auto-lint.sh"
      },
      {
        "matcher": "write_file",
        "command": ".claude/hooks/auto-test.sh"
      },
      {
        "matcher": "*",
        "command": ".claude/hooks/audit-log.sh"
      }
    ],
    "SessionStart": [
      {
        "command": ".claude/hooks/verify-env.sh"
      },
      {
        "command": ".claude/hooks/git-snapshot.sh"
      }
    ]
  }
}
Start small: Do not install all 15 hooks at once. Start with the safety hooks (1-3), add the quality hooks after a week, and then layer in monitoring. Each hook adds a small amount of latency to every tool call, so find the balance between automation and speed.

Monitoring Hooks Across Multiple Agents in Beam

Hooks become even more powerful when you run multiple agent sessions. But they also become harder to monitor — 15 hooks across 3 agents means dozens of log files and notification streams.

Beam solves this by giving you a side-by-side view of all your agent sessions. When a hook blocks a dangerous command in one pane, you see it immediately without switching windows. When the auto-test hook reports a failure in another pane, you catch it in real time. The audit logs from all sessions are visible in their respective terminals, giving you a unified view of what every agent is doing.

This is the operational advantage of running agents in a proper workspace. Hooks automate the guardrails. Beam gives you the visibility to know the guardrails are working.

Monitor Your Hook Output Across Every Agent

Beam’s side-by-side terminals let you see hook output from multiple Claude Code sessions simultaneously. Catch blocked commands, test failures, and audit events in real time.

Download Beam Free

Summary

Claude Code hooks transform the agent from a powerful but unsupervised tool into a controlled, automated workflow. The 15 hooks in this guide cover three critical areas:

  1. Safety (hooks 1-5) — prevent destructive commands, protect critical files, and enforce security boundaries
  2. Quality (hooks 6-10) — auto-format, lint, test, and type-check after every change
  3. Monitoring (hooks 11-15) — log everything, track usage, get notifications, and verify the environment

Set up the safety hooks today. Add quality hooks this week. Layer in monitoring as your workflow matures. The investment is small — a few shell scripts — and the payoff is an agent that enforces your standards automatically, every time, without exception.