Skip to main content
Module 3: Real Architecture 3 / 6
Advanced S15 Hooks Events Automation

Hooks System

Automate and enforce Claude Code lifecycle rules with the current nested hooks schema.

March 20, 2026 15 min read
Verified Curriculum reviewed: Jul 20, 2026

What You’ll Learn

Hooks run deterministic automation at defined points in the Claude Code lifecycle. They can audit activity, add context, format files, or block an action before it happens.

The current settings schema is nested:

hooks
└── event name
    └── matcher group
        └── hooks
            └── handler

Do not use the old flat event-to-command shape.

Configure a Hook

Put hooks in user, project, or local settings according to the scope you need. This project hook checks Bash commands before they run:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/check-command.sh",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

The outer key selects an event. A matcher group filters that event, and its nested hooks array contains one or more handlers. Handler types currently include command, http, mcp_tool, prompt, and experimental agent hooks.

Use /hooks to inspect the effective configuration and its source. The menu is read-only; edit the relevant settings file to change behavior.

Major Lifecycle Events

There are more than four events. Choose the event that matches the exact point at which a decision is still useful.

PhaseMain eventsTypical use
SessionSessionStart, SessionEndLoad context, initialize or archive
User turnUserPromptSubmit, Stop, StopFailureValidate input, enforce completion, record failures
Tool callPreToolUse, PermissionRequest, PostToolUse, PostToolUseFailureBlock, approve, audit, or react to tools
Workers and teamsSubagentStart, SubagentStop, TeammateIdle, TaskCreated, TaskCompletedObserve workers and enforce quality gates
Context and configurationPreCompact, PostCompact, ConfigChange, InstructionsLoadedProtect context transitions and configuration
WorktreesWorktreeCreate, WorktreeRemoveCustomize isolation setup and cleanup

The reference contains additional events and their exact matchers. Treat that list as versioned documentation, not an enum copied permanently into your own article or library.

Command Hook Input

Command hooks receive JSON on stdin. Common fields include session_id, cwd, and hook_event_name; each event adds its own fields. For example, PreToolUse includes tool_name, tool_input, and tool_use_id.

#!/usr/bin/env bash
set -euo pipefail

payload=$(< /dev/stdin)
command=$(jq -r '.tool_input.command // ""' <<< "$payload")

if [[ "$command" == rm\ * ]]; then
  echo "Blocked by project policy" >&2
  exit 2
fi

exit 0

Keep hook scripts small, deterministic, and fast. Validate missing fields because payloads differ by event.

Output and Blocking Rules

For command hooks:

  • exit 0: success; Claude Code may parse JSON written to stdout;
  • exit 2: blocking error for events that can still be blocked; feedback comes from stderr;
  • another non-zero code: non-blocking error for most events;
  • WorktreeCreate is the notable exception: any non-zero exit aborts creation.

The event determines what “block” means. PreToolUse can stop a tool before execution. PostToolUse cannot undo a tool that already ran. Stop can keep the agent working, while SessionEnd cannot prevent an already-ending session.

For structured PreToolUse control, return JSON on exit 0:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Database writes are not allowed"
  }
}

Decision fields are event-specific. Copy them from the event’s official reference instead of generalizing one event’s schema to every hook.

Safety Rules

  • Quote variables and parse JSON with a real parser.
  • Use absolute paths or ${CLAUDE_PROJECT_DIR} for project scripts.
  • Never print secrets or the full environment into hook output.
  • Prefer PreToolUse for prevention; post events are for observation and follow-up.
  • Remember that all matching hooks may run in parallel. Do not have multiple hooks race to rewrite the same input.
  • Test scripts with representative stdin JSON, then verify registration with /hooks.

Hooks can tighten policy even in permissive modes, but an allow response cannot override a stronger deny rule. Design hooks as an enforcement layer, not a permissions bypass.

Official Sources

Next Session

Next, manage session continuity through supported commands and IDs instead of parsing private transcript structures.