Hooks

Intro

In coding agents, hooks are lifecycle callbacks that run custom logic at defined execution points without modifying the agent core. They are the control layer for guardrails, formatting, compliance, and operational automation. Mechanically, the agent reaches a trigger point, pauses the main loop, passes event context as structured JSON to one or more registered handlers, and uses the handler result to continue, modify, or abort the operation. This is the same interceptor pattern as Git hooks and CI pipeline steps, adapted to the agent loop where the unit of work is a tool call rather than a commit.

flowchart LR
    A[Agent loop] --> B[Event fires]
    B --> C[Matcher checks]
    C --> D[Handler runs]
    D --> E{Decision}
    E -->|Allow| F[Agent resumes]
    E -->|Deny| G[Tool call blocked]

For reusable instruction bundles that shape agent behavior, see Skills. For MCP tool extensions, see Plugins.

How Hooks Work

The hook system has three layers: events define when hooks fire, matchers filter which firings are relevant, and handlers execute the logic.

Events are lifecycle moments grouped by purpose:

Category Examples Purpose
Tool events PreToolUse, PostToolUse, PostToolUseFailure Guardrails and quality gates on tool calls
Session events SessionStart, Stop, SessionEnd Setup, teardown, completion logic
Prompt events UserPromptSubmit, PreCompact Input validation, context management
Agent events SubagentStart, SubagentStop Orchestration and monitoring
Operational events Notification, ConfigChange, TaskCompleted Alerts, audit, workflow integration

Matchers are regex patterns that filter when a handler runs. For tool events, the matcher tests against the tool name — Edit|Write matches file-editing tools, mcp__.* matches any MCP tool. Some events like Stop fire unconditionally without matcher support.

Handlers come in four types (Claude Code, the most comprehensive implementation):

Exit code semantics for command hooks on block-capable events like PreToolUse: 0 allows execution, 2 denies and blocks the tool call, other non-zero codes signal an error. Post-execution events like PostToolUse cannot retroactively undo completed actions.

Hooks Across Tools

Claude Code has the most mature hook implementation: 17 event types, 4 handler types, regex matchers, async execution, and configuration at user, project, managed-policy, plugin, and skill scope. JSON config lives in settings.json files at each scope level.

Cursor introduced hooks in v1.7 (October 2025) with a similar event model: beforeShellExecution, afterFileEdit, beforeMCPExecution, sessionStart, sessionEnd, stop, and others. Command-only handlers. Config lives in .cursor/hooks.json at project or global scope.

Other agents (Windsurf, Cline, Aider) have no formal lifecycle hooks yet. These tools use rules, auto-approve settings, or git hooks as their enforcement boundary.

Git hooks are the foundational model. pre-commit and commit-msg enforce standards before history is written; post-commit and server-side hooks support notifications and policy checks. Agents without native hooks typically fall back to git hooks for quality gates.

Concrete Example

A two-stage Claude Code policy: block edits to protected files up front, then auto-format accepted writes immediately after execution.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs -I{} check-protected-files.sh \"{}\""
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs -I{} npx prettier --write \"{}\""
          }
        ]
      }
    ]
  }
}

Cursor uses a similar structure in .cursor/hooks.json with event names like afterFileEdit instead of PostToolUse.

Pitfalls

Slow Hooks Stall the Agent Loop

Silent Failures Pass Violations Through

Post-Hooks Race with Agent Edits

Tradeoffs

Choice Option A Option B Decision criteria
Validation posture Strict blocking via PreToolUse deny Advisory logging via PostToolUse warn Strict catches violations before damage but adds latency and can false-positive block valid operations. Start strict for destructive operations; use advisory for style and formatting.
Hook scope Broad checks on every tool call Targeted checks scoped by matcher Broad gives complete coverage but makes the agent slow and brittle. Default to targeted; broaden only when you find gaps in coverage.
Handler type Command via shell script Prompt or Agent via LLM evaluation Commands are fast, deterministic, and debuggable. LLM handlers evaluate nuance but add inference latency and non-determinism. Use commands for clear policy rules; use LLM hooks for subjective judgment calls on high-stakes decisions.

Questions

References


Whats next