← back to knowledge-hub

Claude Code Hooks: Event-Driven Automation in Your Agent

A hook in Claude Code is a shell command the harness runs in response to a session event. Unlike slash commands (which Claude triggers) or skills (which the model invokes), hooks fire deterministically — they do not depend on the model deciding to call them. That makes them the right tool for anything that must happen: linting, formatting, blocking dangerous commands, sending desktop notifications, logging tool calls.

Hook Events

The harness exposes several events you can hook:

  • SessionStart — Fires when a session starts. Useful for printing a welcome banner, loading project state, or seeding context.
  • UserPromptSubmit — Fires every time you submit a prompt. Can inject extra context or block the prompt entirely.
  • PreToolUse — Fires before any tool call. Can approve, deny, or modify the call. The right place to block rm -rf or enforce a permission policy.
  • PostToolUse — Fires after a tool returns. Use for formatters (run Prettier after every Edit) or audit logs.
  • Stop — Fires when Claude finishes its turn. Common use: a desktop notification so you can switch away while waiting.
  • SubagentStop — Same as Stop but for subagent completion.
  • Notification — Fires when Claude sends a notification (waiting for input, permission request).

Defining Hooks

Hooks live in .claude/settings.json (project) or ~/.claude/settings.json (user). The schema:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write \"$CLAUDE_FILE_PATHS\""
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "powershell -c \"[console]::beep(800,200)\""
          }
        ]
      }
    ]
  }
}

The matcher field is a regex against the tool name. Omit it to match every event of that type. Hook commands receive event metadata via environment variables (CLAUDE_FILE_PATHS, CLAUDE_TOOL_NAME, CLAUDE_PROJECT_DIR, etc.) and through stdin as JSON.

Real Patterns That Pay Off

Auto-format on every edit. The Prettier example above is the highest-ROI hook. You stop caring whether Claude got the indentation right because it gets fixed automatically.

Block dangerous commands. A PreToolUse hook that scans for rm -rf /, git push --force to main, or DROP TABLE and exits non-zero will refuse the call. The harness honors the exit code.

1
2
3
4
5
6
7
8
9
{
  "PreToolUse": [{
    "matcher": "Bash",
    "hooks": [{
      "type": "command",
      "command": "node ./scripts/guard-bash.js"
    }]
  }]
}

Desktop notification on stop. On Windows, a one-liner using BurntToast or PowerShell’s beep keeps long agent runs ergonomic — start the task, switch tabs, get pulled back when done.

Inject project state. A SessionStart hook that runs git status --short and prints the result seeds Claude with the current working tree without waiting for it to ask.

Audit log. A PostToolUse hook that appends {tool, args, timestamp} to a JSONL file gives you a forensic record of what the agent did, which is invaluable when something goes sideways.

Exit Codes Matter

For PreToolUse and UserPromptSubmit, the hook’s exit code controls whether the action proceeds:

  • 0 — Allow.
  • 2 — Block, and feed the hook’s stderr back to Claude as a reason. Claude will see the message and adjust.
  • Anything else — Treated as an error, but the action proceeds.

This is what makes hooks a real policy layer rather than just notifications.

A Note on Trust

Hooks run with your user permissions. They execute every event, every session, often without confirmation. Treat .claude/settings.json like any other code — review it before pulling someone else’s project, and never paste hook configs from untrusted sources.

Used well, hooks turn Claude Code from a smart REPL into a disciplined collaborator that respects the rules of your codebase whether the model remembers to or not.

graph cloud Password Playground Speed Reader Lead Manager Job Copilot Universe Explorer Surya Siddhanta SettleUp