What You’ll Learn

  • How Claude Code hooks work in real projects
  • Ready-to-use hook examples for linting, tests, and deploy checks
  • Which hook events map best to which automation tasks
  • How to keep hook automation useful without making it slow or annoying
  • What to commit at project scope versus what to keep local

If you are searching for real Claude Code hooks examples, the main thing to understand is that hooks are not just “extra config.” They are the deterministic layer around Claude Code.

That matters because prompts are suggestions. Hooks are behavior.

Claude Code’s official docs show that hooks can run at key lifecycle points like PreToolUse, PostToolUse, Stop, Notification, and SessionStart. That means you can automatically run commands, block risky actions, and enforce project rules without relying on the model to remember every instruction perfectly.

This guide focuses on the most useful hook examples for engineering workflows:

  • lint after edits
  • run tests before a turn finishes
  • block risky deploy commands
  • send notifications when long tasks end

Where Claude Code Hooks Live

Claude Code supports hook configuration in settings files.

The most practical locations are:

  • ~/.claude/settings.json for your personal machine-wide hooks
  • .claude/settings.json for project-scoped hooks shared with the repo

If a team should benefit from the automation, I prefer project scope.

Example 1: Run Linting After File Edits

This is the first hook I would add to many repos.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "npm run lint"
          }
        ]
      }
    ]
  }
}

Why it works well:

  • it maps directly to file modification events
  • it catches issues immediately
  • it removes one repetitive manual step

If your lint command is heavy, replace it with a more targeted script that checks only changed files.

Example 2: Run Typecheck or Tests on Stop

The Stop event is a good fit for cheap validation that should happen before the turn ends.

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "npm run typecheck"
          }
        ]
      }
    ]
  }
}

If your project has a fast targeted test suite, you can use that instead:

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "npm test -- --runInBand"
          }
        ]
      }
    ]
  }
}

The key is to keep the hook fast enough that it stays part of the workflow instead of becoming a source of drag.

Example 3: Block Dangerous Deploy or Shell Commands

If you want Claude Code to avoid specific deploy commands or destructive shell patterns, use PreToolUse on Bash.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/block-deploy-risks.sh"
          }
        ]
      }
    ]
  }
}

And a simple script:

#!/bin/bash

COMMAND=$(jq -r '.tool_input.command')

if echo "$COMMAND" | grep -Eq 'vercel --prod|git push --force|rm -rf'; then
  jq -n '{
    decision: "block",
    reason: "Blocked risky deploy or destructive command by project hook."
  }'
  exit 0
fi

exit 0

This is one of the most useful Claude Code hook examples because it turns “please be careful” into something enforceable.

Example 4: Send Notifications When Claude Needs You

The Notification hook is useful for longer tasks or background-like waits.

For example, on macOS you might trigger a notification command when Claude needs input or finishes work. The official docs use this kind of example to demonstrate hook setup.

The specific command varies by OS, but the important point is that hooks can make Claude Code much easier to use in longer sessions.

Example 5: Run a Deploy Checklist Instead of Auto-Deploying

A common temptation is to use hooks to trigger production deploys automatically.

I usually prefer a guardrail step instead.

For example, before allowing a deploy command, run a script that checks:

  • current branch
  • test status
  • presence of required environment variables
  • whether the repo is clean enough for release

This is safer than turning hooks into a blind deployment robot.

Best Practices for Claude Code Hooks

If you want your hooks to stay useful, these are the habits that matter most:

Keep commands fast

Hooks that are too slow become friction.

Use hooks for rules, not judgment

Run formatters, tests, and blockers in hooks. Leave architectural judgment to human review.

Prefer project scope for shared workflows

If the automation is part of the team’s process, put it in .claude/settings.json.

Avoid over-automating deployments

Deploy guardrails are good. Blind deploy automation is much riskier.

Final Thought

The best Claude Code hooks examples are not flashy. They are the ones that remove repetitive steps and enforce deterministic rules that matter to the team.

Lint after edits. Typecheck on stop. Block dangerous commands before they run. That small layer of hook automation can make Claude Code feel much more reliable in real engineering workflows.

If you need help designing Claude Code hook systems, AI workflow guardrails, or automation around developer tooling, take a look at my portfolio: voidcraft-site.vercel.app.