Work in progressUnder active development — not tested as ready for use. Breaking changes land without notice, stored data may need to be discarded between revisions, and there is no auth or security model.
<!-- GENERATED from the blueprint (@claude-transcripts/shared) by scripts/gen-hook-events.ts. Do NOT edit by hand — run bun run gen:hook-events. Edit the blueprint: packages/shared/src/blueprint/hooks.ts (events/order/summaries) and actions.ts (the "What we do" bindings). -->
Claude Code hook events — when they fire, payloads & fixtures
The authoritative catalogue of every Claude Code hook event, projected from the app blueprint (@claude-transcripts/shared HOOK_TYPES): the one-line trigger for each, a link to the official documentation, links to example payload fixtures under tests/mock/claude-code/hooks/ (the inputs Claude Code sends a hook on stdin — used for both these docs and test automation), and the action(s) we run.
This table is the payload/fixture reference. actions.md narrates the hook → action model, and hook.md covers the writer mechanics. A per-version list (which events each Claude Code version exposes) is planned as compatibility.json (compatibility.md, ADR 0025); its generator is still a stub, so until then the official reference below is the authority when this table and a given CC version disagree.
- Official reference: <https://code.claude.com/docs/en/hooks>
- Guide: <https://code.claude.com/docs/en/hooks-guide>
How to read this table
- Fires when — one-line trigger + what the event is for.
- Docs — deep link into the official hooks reference for that event.
- Examples — folder of example payload fixtures for that event (one or several JSON files; see the fixtures README for the naming/variety convention). Many are placeholders today — synthetic but shape-faithful — to be supplemented with real captures over time.
- What we do — for wired events, the action handlers bound to it (projected from the blueprint's BINDINGS; actions.md lists what each does). For ignored events, why we intentionally don't handle it. Both come from the blueprint (
hooks.ts + actions.ts) — wire an ignored event by adding a binding and regenerating.
Events are ordered by session lifecycle: a session begins at the top and ends (or crashes) at the bottom.
Common payload fields
Every hook receives these on stdin; per-event fields are layered on top.
| Field | Type | Meaning |
|---|
session_id | string | Claude Code's own session UUID — our stable key. |
transcript_path | string | Absolute path to the session transcript (JSONL) on disk. |
cwd | string | Working directory at the time the event fired. |
hook_event_name | string | The event name (e.g. PostToolUse) — mirrors the row. |
permission_mode | string? | Present on tool-related events (default, plan, …). |
effort | object? | `{ "level": "low\ | medium\ | high\ | …" }` when applicable. |
Session start & setup
| Hook | Fires when | Docs | Examples | What we do |
|---|
SessionStart | A session begins, resumes, is cleared, or restarts after compaction — source ∈ startup/resume/clear/compact. The per-session entry point. | ref | session-start/ | seed-session-start · write-event-marker · announce-recording · inject-recall-policy |
Setup | The CLI runs in init/maintenance mode (e.g. --init-only) — one-time environment setup. | ref | setup/ | ignored — Env/setup signal, not session activity. |
InstructionsLoaded | CLAUDE.md / .claude/rules/*.md instruction files are loaded — load_reason records why. Observability of which instructions applied. | ref | instructions-loaded/ | ignored — Instruction-load audit — out of Tier-1 scope. |
| Hook | Fires when | Docs | Examples | What we do |
|---|
UserPromptSubmit | The user submits a prompt, before Claude sees it. Can block or inject context. | ref | user-prompt-submit/ | write-event-marker · update-counts · flush-transcript-chunk |
UserPromptExpansion | A slash command / skill prompt is expanded/templated before use. | ref | user-prompt-expansion/ | ignored — Slash-command expansion — redundant with UserPromptSubmit. |
| Hook | Fires when | Docs | Examples | What we do |
|---|
PreToolUse | Before a tool executes — tool_name + tool_input available. Can block or modify the input. | ref | pre-tool-use/ | ignored — Blocking pre-hook; an observe-only writer gains nothing — PostToolUse captures the outcome. |
PermissionRequest | A permission dialog is about to be shown for a tool call. | ref | permission-request/ | ignored — Permission-dialog control hook, not session history. |
PermissionDenied | A tool call was denied (auto-classifier or user). | ref | permission-denied/ | ignored — Permission control event, not session history. |
PostToolUse | A tool succeeds — tool_output available. Can post-process the result. | ref | post-tool-use/ | write-event-marker · update-counts · flush-transcript-chunk |
PostToolUseFailure | A tool fails — error_message available. | ref | post-tool-use-failure/ | write-event-marker · update-counts · flush-transcript-chunk |
PostToolBatch | A batch of parallel tool calls resolves. | ref | post-tool-batch/ | ignored — Batch boundary; the individual PostToolUse events are already captured. |
Subagents, teams & tasks
| Hook | Fires when | Docs | Examples | What we do |
|---|
SubagentStart | A subagent is spawned — agent_type, agent_id, task_description. | ref | subagent-start/ | write-event-marker · update-counts |
SubagentStop | A subagent finishes — summary of its work. | ref | subagent-stop/ | write-event-marker · update-counts |
TeammateIdle | A team teammate goes idle. | ref | teammate-idle/ | ignored — Team orchestration, not session history. |
TaskCreated | A task is created via TaskCreate. | ref | task-created/ | ignored — Task orchestration, not session history. |
TaskCompleted | A task is marked complete. | ref | task-completed/ | ignored — Task orchestration, not session history. |
Display, MCP & notifications
| Hook | Fires when | Docs | Examples | What we do |
|---|
MessageDisplay | An assistant message is streamed/displayed to the user. | ref | message-display/ | ignored — UX event; the message content is already in the transcript. |
Elicitation | An MCP server requests user input. | ref | elicitation/ | ignored — MCP interaction control hook; an observe-only writer gains nothing. |
ElicitationResult | The user responds to an elicitation. | ref | elicitation-result/ | ignored — MCP interaction event; the content is in the transcript. |
Notification | Claude Code emits a notification (permission_prompt, idle_prompt, auth_success, …). | ref | notification/ | ignored — UX notification, not session history. |
Environment, config & files
| Hook | Fires when | Docs | Examples | What we do |
|---|
CwdChanged | The working directory changes during a session. | ref | cwd-changed/ | ignored — Host signal, out of session scope. |
FileChanged | A watched file changes on disk. | ref | file-changed/ | ignored — Watcher signal, out of session scope. |
ConfigChange | A settings/config/skills file changes during the session (user_settings, project_settings, …). | ref | config-change/ | ignored — Config-change signal, out of session scope. |
Worktrees
| Hook | Fires when | Docs | Examples | What we do |
|---|
WorktreeCreate | A git worktree is created (--worktree). | ref | worktree-create/ | ignored — Git-worktree lifecycle, irrelevant to session logging. |
WorktreeRemove | A git worktree is removed. | ref | worktree-remove/ | ignored — Git-worktree lifecycle, irrelevant to session logging. |
Compaction
| Hook | Fires when | Docs | Examples | What we do |
|---|
PreCompact | Before context compaction — trigger ∈ manual/auto. | ref | pre-compact/ | write-event-marker |
PostCompact | After compaction completes — trigger ∈ manual/auto. | ref | post-compact/ | write-event-marker |
Turn end
| Hook | Fires when | Docs | Examples | What we do |
|---|
Stop | Claude finishes responding to a turn — turn_number, assistant_message. | ref | stop/ | write-event-marker · flush-transcript-chunk |
StopFailure | A turn ends with an API error — rate_limit, overloaded, max_output_tokens, … A turn-level failure (see the crash note in the doc). | ref | stop-failure/ | write-event-marker · update-counts |
Session end
| Hook | Fires when | Docs | Examples | What we do |
|---|
SessionEnd | The session terminates — reason ∈ clear/resume/logout/prompt_input_exit/bypass_permissions_disabled/other. | ref | session-end/ | flush-transcript-chunk · write-summary · upload-blobs |
On crashes. There is no dedicated "session crashed" event. Abnormal termination surfaces in three ways, in increasing severity:
StopFailure — the turn hit an API/runtime error but the session is alive.SessionEnd with reason: "other" — an orderly-but-non-standard shutdown.- No
SessionEnd at all — a hard crash / kill. The session is then detected as incomplete by derivation (see couchdb.md → status model) and finalised by the reconcile utility (tools.md). Fixtures for (1) and (2) live under stop-failure/ and session-end/; case (3) is exercised by leaving a started session with no end fixture.
Coverage vs. what we wire today
We currently bind actions to 11 of the 30 events — SessionStart, UserPromptSubmit, PostToolUse, PostToolUseFailure, SubagentStart, SubagentStop, PreCompact, PostCompact, Stop, StopFailure, SessionEnd. The rest are intentionally ignored — the "What we do" column gives the reason per event: a passive, observe-only writer gains nothing from blocking / UX / orchestration hooks, and every hook invocation costs a Bun startup, so we wire only the events that carry the session record (actions.md). Wiring an ignored event = add the action + binding in the blueprint, then regenerate hooks.json (bun run gen:hooks).
Field-shape caveat. Payload field names/casing follow the official reference at authoring time. Claude Code is upstream and evolving; when in doubt, capture a real payload (every hook just receives JSON on stdin — … | tee fixture.json) and reconcile against the official reference.