Skip to main content
Hooks are event-driven automations that fire before or after Claude Code tool executions. They enforce code quality, catch mistakes early, and automate repetitive checks.

How Hooks Work

User request → Claude picks a tool → PreToolUse hook runs → Tool executes → PostToolUse hook runs
1

PreToolUse hooks

Run before the tool executes. They can block (exit code 2) or warn (stderr without blocking).
2

PostToolUse hooks

Run after the tool completes. They can analyze output but cannot block.
3

Stop hooks

Run after each Claude response.
4

SessionStart/SessionEnd hooks

Run at session lifecycle boundaries.
5

PreCompact hooks

Run before context compaction, useful for saving state.

Hook Types

PreToolUse Hooks

HookMatcherBehaviorExit Code
Dev server blockerBashBlocks npm run dev etc. outside tmux — ensures log access2 (blocks)
Tmux reminderBashSuggests tmux for long-running commands (npm test, cargo build, docker)0 (warns)
Git push reminderBashReminds to review changes before git push0 (warns)
Doc file warningWriteWarns about non-standard .md/.txt files0 (warns)
Strategic compactEdit|WriteSuggests manual /compact at logical intervals (every ~50 tool calls)0 (warns)

PostToolUse Hooks

HookMatcherWhat It Does
PR loggerBashLogs PR URL and review command after gh pr create
Build analysisBashBackground analysis after build commands (async, non-blocking)
Prettier formatEditAuto-formats JS/TS files with Prettier after edits
TypeScript checkEditRuns tsc --noEmit after editing .ts/.tsx files
console.log warningEditWarns about console.log statements in edited files

Lifecycle Hooks

HookEventWhat It Does
Session startSessionStartLoads previous context and detects package manager
Pre-compactPreCompactSaves state before context compaction
Console.log auditStopChecks all modified files for console.log after each response
Session endSessionEndPersists session state for next session
Pattern extractionSessionEndEvaluates session for extractable patterns (continuous learning)

Hook Configuration

Hooks are defined in hooks.json in your plugin directory. Here’s the complete configuration:
hooks.json
{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "node script.js"
          }
        ],
        "description": "Hook description"
      }
    ],
    "PostToolUse": [...],
    "SessionStart": [...],
    "SessionEnd": [...],
    "PreCompact": [...],
    "Stop": [...]
  }
}

Hook Input Schema

Hooks receive tool information as JSON on stdin:
interface HookInput {
  tool_name: string;          // "Bash", "Edit", "Write", "Read", etc.
  tool_input: {
    command?: string;         // Bash: the command being run
    file_path?: string;       // Edit/Write/Read: target file
    old_string?: string;      // Edit: text being replaced
    new_string?: string;      // Edit: replacement text
    content?: string;         // Write: file content
  };
  tool_output?: {             // PostToolUse only
    output?: string;          // Command/tool output
  };
}

Exit Codes

  • 0 — Success (continue execution)
  • 2 — Block the tool call (PreToolUse only)
  • Other non-zero — Error (logged but does not block)

Async Hooks

For hooks that should not block the main flow (e.g., background analysis):
{
  "type": "command",
  "command": "node my-slow-hook.js",
  "async": true,
  "timeout": 30
}
Async hooks run in the background and cannot block tool execution.

Cross-Platform Notes

All hooks in this plugin use Node.js (node -e or node script.js) for maximum compatibility across Windows, macOS, and Linux. Avoid bash-specific syntax in hooks.

Next Steps

Memory Persistence

Learn about session lifecycle hooks

Strategic Compact

Understand compaction suggestions

Custom Hooks

Create your own hooks