Claude Code Hooks: Every Event and How to Use Them for Memory (2026)

7 min read

The Claude Code hook events (SessionStart, UserPromptSubmit, Stop, PreCompact and 28 more: 33 in all), the four hook types, exit code rules, where hooks live in settings.json, and how hooks feed memory tools such as claude-mem and Hindsight.

What are Claude Code hooks?

Claude Code hooks are commands that run at fixed points in a session. You set them in a JSON settings file, and Claude Code runs them when the event fires, with no model choice involved. They are the only part of Claude Code’s setup that runs code on its own, which makes them the main way to save or reload memory automatically.

The Claude Code hooks reference lists 33 events. The ones that matter most for memory are SessionStart, UserPromptSubmit, Stop, PreCompact and SessionEnd.

Hook events and when they fire

Event names come from the Claude Code hooks reference, read 2026-11-11. The table lists the events in the order the docs give them. Memory events are first.

EventWhen it firesCan block it?
SessionStartWhen a session begins or resumesNo
UserPromptSubmitWhen a prompt is submitted, before Claude processes itYes
StopWhen Claude finishes respondingYes (exit 2 keeps Claude working)
PreCompactBefore context compaction (matcher: manual or auto)Yes (exit 2 blocks compaction)
PostCompactAfter context compaction completesNo
SessionEndWhen a session terminatesNo
SetupWith --init-only, or with --init or --maintenance in -p modeNo
UserPromptExpansionWhen a typed command expands into a promptYes
PreToolUseBefore a tool call runsYes
PermissionRequestWhen a tool call needs a permission decisionYes (exit 2 not honored)
PermissionDeniedWhen auto mode denies a tool callNo
PostToolUseAfter a tool call succeedsShows stderr to Claude only
PostToolUseFailureAfter a tool call failsNo
PostToolBatchAfter a batch of parallel tool calls, before the next model callYes (stops the loop before the next model call)
NotificationWhen Claude Code sends a notificationNo
MessageDisplayWhile assistant message text is displayedNo
SubagentStartWhen a subagent is spawnedNo
SubagentStopWhen a subagent finishesYes (exit 2 keeps it working)
TaskCreatedWhen a task is created with TaskCreateYes (rolls back the task)
TaskCompletedWhen a task is marked completedYes
StopFailureWhen the turn ends because of an API errorNo
TeammateIdleWhen an agent team teammate is about to go idleYes (keeps the teammate working)
InstructionsLoadedWhen a CLAUDE.md or .claude/rules/*.md file loadsNo
ConfigChangeWhen a configuration file changes during a sessionYes (except policy settings)
CwdChangedWhen the working directory changesNo
DirectoryAddedWhen a directory is added mid-session with /add-dirNo
FileChangedWhen a watched file changes on diskNo
WorktreeCreateWhen a worktree is being createdYes (any non-zero exit fails it)
WorktreeRemoveWhen a worktree made by a WorktreeCreate hook is removedYes (any non-zero exit fails it)
PreModelSwitchBefore a requested model switch appliesYes
PostModelSwitchAfter the session’s model changesNo
ElicitationWhen an MCP server asks the user for input during a tool callYes (declines the request)
ElicitationResultAfter the user answers an MCP elicitationYes (response becomes decline)

The four hook types

  • command: runs a shell command. The input arrives on stdin. The result comes back through the exit code and stdout.
  • http: POSTs the event’s JSON to a URL. The response uses the same JSON output format.
  • prompt: sends the input to a Claude model for one turn. The model returns a JSON decision. $ARGUMENTS holds the input.
  • agent: starts a subagent that can read files before it decides. The docs mark it experimental.

There is also mcp_tool, which calls a tool on a configured MCP server.

Exit codes for command hooks

  • 0: success. If stdout is one JSON object, Claude Code reads it as a decision. Otherwise plain stdout is text. On UserPromptSubmit, SessionStart and UserPromptExpansion, plain text on stdout is added to Claude’s context.
  • 2: a blocking error on the events that can block. The stderr text is the reason shown.
  • Any other code, including 1: a non-blocking error. The action goes ahead, and the transcript shows a hook error. The docs say exit 1 is not a policy block; use exit 2 for that.

To make a failed command or http hook stop the action, set "onFailure": "block". The docs say this needs Claude Code v2.1.295 or later.

Where hooks live in settings.json

Hooks sit under a "hooks" key. The keys are event names. Each event has matcher groups, and each group has handlers:

 1{
 2  "hooks": {
 3    "Stop": [
 4      {
 5        "hooks": [
 6          { "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/save-notes.sh" }
 7        ]
 8      }
 9    ]
10  }
11}

The file can be ~/.claude/settings.json (every project), .claude/settings.json (shared with the repo) or .claude/settings.local.json (yours only). Hooks also come from managed policy settings, plugin hooks/hooks.json files, and the frontmatter of skills and subagents. Hooks from all levels merge. Set "disableAllHooks": true to turn them all off.

Two fields are handy for memory work. Stop gets last_assistant_message, which the docs recommend over reading transcript_path, because the transcript can lag. SessionStart gets source, which is resume or fork in those cases, so a hook can tell a fresh start from a resumed one.

How hooks support memory

Claude Code has two built-in memory files, CLAUDE.md and auto memory. Hooks fill the gap between them: they run code when things happen, so the saved state does not depend on Claude remembering to write it.

Three patterns work with the events above:

  1. Load on start. A SessionStart hook reads your saved notes and prints them. Plain stdout from this event is added to Claude’s context. The docs warn that text passed this way is saved in the transcript and replayed on resume, so timestamps and commit hashes can go stale. Run the hook again on resume (it fires on resume) to refresh them.
  2. Save at the end. A Stop or SessionEnd hook writes the session’s key points to a file or a memory server.
  3. Save before compaction. A PreCompact hook writes what would be lost when Claude compacts the context. Its matcher says whether it was manual or auto.

Existing tools already do this. claude-mem uses lifecycle hooks (SessionStart, UserPromptSubmit, PostToolUse, Stop and SessionEnd) to capture each session and inject context back later. Everything Claude Code uses hooks to save and reload session state.

Where Hindsight fits

Hindsight is an MIT-licensed memory server from Vectorize. It has a native Claude Code plugin, so you can use it without writing your own hooks. The plugin stores what a session produces and answers later questions from it. Its reflect call reasons over stored memories, which helps with “why did we decide X?” questions across many sessions.

Hindsight’s numbers come from Vectorize and are not independent. On the BEAM benchmark for long histories, Hindsight scores 73.9 at 1M tokens against Mem0’s 64.1, and 64.1 at 10M against Mem0’s 48.6. Both Mem0 figures come from Mem0’s own comparison page.

The limits:

  • More text per recall. Hindsight returns more context than Mem0 by default, about 4x by Mem0’s measurement. Set a lower token budget if prompts get crowded.
  • Writes cost model calls. Hindsight calls an LLM when it stores memories, so a Stop hook that saves every session costs more than a plain text log.
  • Overkill for short projects. A few rules fit in CLAUDE.md. Use a memory server when the history is too long to read.

For a full comparison, see Claude Code memory and Claude Code settings.

Limits of hooks

  • Hooks run your code with your permissions. Read a hook before you add it, and do not paste hooks from strangers.
  • A hook that is slow blocks the session. Keep save hooks fast, or send their work to a background process.
  • Exit 1 does not stop anything. Use exit 2, or "onFailure": "block", when a rule has to hold.
  • CLAUDE.md is not enforcement. The docs say it is context. For a rule that must hold, use a PreToolUse hook or a permissions.deny rule.

Sources