Learn Claude Code: Hooks Deep Dive Hooks Fundamentals: Lifecycle Events in Claude Code

Hooks Fundamentals: Lifecycle Events in Claude Code

Advanced 🕐 10 min Lesson 1 of 12
What you'll learn
  • Explain what hooks are and how they differ from CLAUDE.md instructions and manual shell scripts
  • Identify the three firing cadences and the events that belong to each
  • Distinguish the five handler types and when each is the right choice

The Problem Hooks Solve

Every Claude Code session involves dozens of tool calls: editing files, running shell commands, fetching URLs, calling MCP tools. Most of the time you want Claude to proceed without interruption. But sometimes you need something to happen at an exact moment — before a dangerous command runs, after a file is modified, when Claude finishes a response.

CLAUDE.md instructions can ask Claude to be careful. Permission prompts can pause and ask you to approve each action. Neither is reliable at scale. Instructions depend on Claude reading and remembering them. Prompts require a human to be watching. Neither blocks automatically, neither logs automatically, and neither fires code you wrote.

Hooks solve this. A hook is a handler — a shell command, HTTP request, MCP tool call, or LLM prompt — that fires automatically at a defined lifecycle point. It does not ask Claude's opinion. It runs regardless of what Claude was doing, and depending on the event, it can block the action, modify the input, inject context, or simply observe and log.

If you have used Git hooks, the concept is identical. Claude Code applies the same pattern to every layer of its operation: session lifecycle, conversation turns, and individual tool calls.

The Three Firing Cadences

Every hook event falls into one of three cadences based on how often it fires.

Session cadence hooks fire once during the session lifecycle. SessionStart fires when a session begins or resumes. SessionEnd fires when it closes. Setup fires in non-interactive mode for CI initialization. These are the right place for environment setup, context loading, and cleanup tasks that should happen once per run.

Turn cadence hooks fire once per conversation turn. UserPromptSubmit fires before Claude processes your message — before it reads the content at all. Stop fires when Claude finishes a response. StopFailure fires when Claude cannot stop cleanly due to an API error. Turn hooks are the right place for prompt validation, test gates, and completion notifications.

Tool cadence hooks fire for each tool call. PreToolUse fires before execution and can block or modify the call. PostToolUse fires after success with the tool output available. PermissionRequest fires when a permission dialog would appear. These are the most granular hooks — they let you intercept individual operations rather than entire turns.

Beyond these core cadences, additional events cover file changes (FileChanged, CwdChanged), subagent lifecycle (SubagentStart, SubagentStop), context compaction (PreCompact, PostCompact), and worktree management. Each event fires at a precise moment, and you can attach zero, one, or many handlers to each.

Five Handler Types: A First Look

Claude Code supports five types of hook handlers, each suited to a different deployment context.

Command hooks run a shell command. The hook receives a JSON payload on stdin and returns decisions via exit codes and stdout. This is the most common handler type — any logic you can express in bash, Python, or any executable works here. Command hooks are fast, flexible, and require no external dependencies.

HTTP hooks POST to a URL and receive the decision as a JSON response. Use these when you already have infrastructure — a policy service, a security scanner, a logging endpoint — that you want to integrate without duplicating logic in shell scripts. The POST body is exactly the same JSON payload that command hooks receive on stdin.

MCP tool hooks call a tool on a connected MCP server. If you have an MCP server with capabilities you want to invoke at hook points — a database lookup, a custom validation tool, a notification sender — MCP tool hooks plug directly into that server without shelling out.

Prompt hooks send a prompt to an LLM for a yes/no decision. They are ideal when the judgment required is inherently linguistic — "Is this command risky?" or "Does this output contain sensitive data?" — and would be awkward to encode in regex or shell logic.

Agent hooks spawn a subagent with access to tools like Read, Grep, and Glob. They are the most powerful option for decisions that require inspecting multiple files or running a structured verification process. They are also the most expensive, and currently experimental.

The handler type is separate from the hook event. You can attach any handler type to any event, and you can attach multiple handlers of different types to the same event.

The /hooks Browser

Once hooks are configured, you can inspect them from inside any Claude Code session by typing /hooks. This opens a read-only browser showing every active hook organized by event. For each hook you can see its source (which settings file defines it), its matcher (which tool names or event types it targets), its handler type, and its configuration.

The browser is read-only — you cannot edit hooks from inside Claude Code. But it is invaluable for diagnosing unexpected behavior. If a tool call is being blocked and you are not sure why, /hooks will show you which PreToolUse handlers are active and where they are defined. If a session startup script is not running, you can verify the SessionStart hook is actually registered.

The source column shows which settings file defines each hook: user settings, project settings, local settings, or managed settings. In shared codebases where multiple contributors add hooks at different scopes, the browser reveals exactly what each scope has contributed.

Hooks vs CLAUDE.md vs Shell Scripts

There are three ways to influence Claude Code behavior: hooks, CLAUDE.md instructions, and running shell scripts yourself. They serve different purposes and should not be confused.

CLAUDE.md instructions are read by Claude and interpreted as context. They can suggest behavior but Claude can reason around them, forget them in long sessions, or interpret them differently than intended. They are excellent for communicating intent. They are not reliable for enforcement.

Running shell scripts yourself gives you full control but requires your presence. This is fine for one-off operations but does not help when Claude is running autonomously in a loop, as a Routine, or in a CI pipeline.

Hooks are for enforcement. They fire without your presence, without Claude's cooperation, and without depending on the right instructions being read at the right moment. A PreToolUse hook that blocks rm -rf will block it every time, in every session, regardless of what Claude was asked to do. A Stop hook that runs tests will run them after every turn, unconditionally.

The right mental model: CLAUDE.md shapes what Claude tries to do. Hooks shape what Claude is allowed to do. Use both — but do not use instructions to enforce things that hooks can guarantee.

Key takeaways
  • Hooks fire at defined lifecycle points regardless of Claude behavior — they cannot be reasoned away or forgotten the way CLAUDE.md instructions can
  • Three cadences organize every hook event — session cadence for environment setup, turn cadence for prompt and completion gates, tool cadence for per-call interception
  • Five handler types cover the full range of automation needs — command for shell logic, http for existing infrastructure, mcp_tool for MCP server capabilities, prompt for linguistic decisions, agent for multi-file verification
  • The /hooks browser provides a read-only view of all active hooks — inspect event, matcher, handler, and source file without touching configuration
  • Hooks enforce; CLAUDE.md instructs — use hooks when you need a guarantee, instructions when you need guidance