architecture

Hooks Setup: From Zero to Production

Step-by-step setup of the 6 hooks every serious Claude Code user needs. settings.json schema, hook lifecycle, and debugging tips.

11 min read·
Day 6 Resource · 30-Day Series

Hooks Setup: From Zero to Production

Claude Code can run shell commands, edit files, and interact with git on your behalf. That power is useful until it touches something it should not. Hooks are your guardrails: shell scripts that fire automatically before or after Claude acts, blocking dangerous operations and logging everything silently in the background.

6 hooks
total scripts
30 min
setup time
set once
forget it

The 6 hooks

Activate all hooks: settings.json

Add this configuration to ~/.claude/settings.json to wire up all six hooks. Each entry maps a hook lifecycle event to the script that handles it. Once saved, hooks activate immediately on the next Claude Code session.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "~/.claude/hooks/bash-safety.sh" }
        ]
      },
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "~/.claude/hooks/file-protection.sh" }
        ]
      },
      {
        "matcher": "Edit",
        "hooks": [
          { "type": "command", "command": "~/.claude/hooks/file-backup.sh" }
        ]
      },
      {
        "matcher": "WebSearch",
        "hooks": [
          { "type": "command", "command": "~/.claude/hooks/search-year.sh" }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          { "type": "command", "command": "~/.claude/hooks/file-logger.sh" }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          { "type": "command", "command": "~/.claude/hooks/stop-notify.sh" }
        ]
      }
    ]
  }
}

After saving, run: chmod +x ~/.claude/hooks/*.sh

Hook lifecycle

Understanding when each hook fires helps you choose the right event for your use case. PreToolUse hooks can block an action by returning exit code 2. PostToolUse hooks run after the fact and are observation-only. The Stop hook fires once at the end of every turn.

Claude receives your message
        │
        ▼
┌───────────────────────┐
│   PreToolUse hooks    │  ← bash-safety, file-protection, file-backup, search-year
│   (can block action)  │
└──────────┬────────────┘
           │  approved
           ▼
┌───────────────────────┐
│   Tool executes       │  Bash / Edit / Write / WebSearch / …
└──────────┬────────────┘
           │  done
           ▼
┌───────────────────────┐
│   PostToolUse hooks   │  ← file-logger
│   (observe only)      │
└──────────┬────────────┘
           │
           ▼
     (repeat per tool call)
           │
           ▼
┌───────────────────────┐
│   Stop hook           │  ← stop-notify  (fires once at end of turn)
└───────────────────────┘

Debugging cheatsheet

Hook never fires

Check settings.json syntax (valid JSON?). Verify the matcher string matches the exact tool name Claude Code uses. Run: cat ~/.claude/settings.json | python3 -m json.tool

Permission denied

The script is not executable. Run: chmod +x ~/.claude/hooks/*.sh

exit 2 not blocking

Only exit code 2 triggers a block in PreToolUse. exit 1 is treated as an error but may not block. Make sure your block path returns exactly exit 2.

Hook fires but CLAUDE_FILE_PATH is empty

The env var name differs per tool. Edit uses CLAUDE_FILE_PATH. Bash uses CLAUDE_TOOL_INPUT. Log all env vars with: env | grep CLAUDE_ >> /tmp/hook-debug.log

Backups directory growing too large

file-backup.sh prunes to 10 per file, but many distinct files accumulate. Run: du -sh ~/.claude/backups and periodically: rm ~/.claude/backups/*

stop-notify.sh not showing on macOS

Check System Settings > Notifications > Terminal (or iTerm2) and make sure notifications are allowed. The afplay line runs in background so sound should still play.

Want this running in your stack?

AY Automate builds agent systems, RAG pipelines, and Claude Code setups for production teams.