Claude Transcripts docs GitHub
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. These docs describe the intended design as much as the current state.

<!-- GENERATED from the app model (@claude-transcripts/shared) by scripts/gen-hook-events.ts. Do NOT edit by hand — run bun run gen:hook-events. Edit the model: packages/shared/src/model/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 model (@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. The complementary hooks.md narrates the hook → action model, and hook.md covers the writer mechanics. The per-version authoritative list (which events each supported Claude Code version exposes) is generated into compatibility.json (compatibility.md, ADR 0025) — treat that as the source of truth if this table and a given CC version disagree.

How to read this table

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.

FieldTypeMeaning
session_idstringClaude Code's own session UUID — our stable key.
transcript_pathstringAbsolute path to the session transcript (JSONL) on disk.
cwdstringWorking directory at the time the event fired.
hook_event_namestringThe event name (e.g. PostToolUse) — mirrors the row.
permission_modestring?Present on tool-related events (default, plan, …).
effortobject?`{ "level": "low\medium\high\…" }` when applicable.

Session start & setup

HookFires whenDocsExamplesWhat we do
SessionStartA session begins, resumes, is cleared, or restarts after compaction — sourcestartup/resume/clear/compact. The per-session entry point.refsession-start/seed-session-start · write-event-marker
SetupThe CLI runs in init/maintenance mode (e.g. --init-only) — one-time environment setup.refsetup/ignored — Env/setup signal, not session activity.
InstructionsLoadedCLAUDE.md / .claude/rules/*.md instruction files are loaded — load_reason records why. Observability of which instructions applied.refinstructions-loaded/ignored — Instruction-load audit — out of Tier-1 scope.

Turn input

HookFires whenDocsExamplesWhat we do
UserPromptSubmitThe user submits a prompt, before Claude sees it. Can block or inject context.refuser-prompt-submit/write-event-marker · update-counts · flush-transcript-chunk
UserPromptExpansionA slash command / skill prompt is expanded/templated before use.refuser-prompt-expansion/ignored — Slash-command expansion — redundant with UserPromptSubmit.

Tool lifecycle

HookFires whenDocsExamplesWhat we do
PreToolUseBefore a tool executes — tool_name + tool_input available. Can block or modify the input.refpre-tool-use/ignored — Blocking pre-hook; an observe-only writer gains nothing — PostToolUse captures the outcome.
PermissionRequestA permission dialog is about to be shown for a tool call.refpermission-request/ignored — Permission-dialog control hook, not session history.
PermissionDeniedA tool call was denied (auto-classifier or user).refpermission-denied/ignored — Permission control event, not session history.
PostToolUseA tool succeeds — tool_output available. Can post-process the result.refpost-tool-use/write-event-marker · update-counts · flush-transcript-chunk
PostToolUseFailureA tool fails — error_message available.refpost-tool-use-failure/write-event-marker · update-counts · flush-transcript-chunk
PostToolBatchA batch of parallel tool calls resolves.refpost-tool-batch/ignored — Batch boundary; the individual PostToolUse events are already captured.

Subagents, teams & tasks

HookFires whenDocsExamplesWhat we do
SubagentStartA subagent is spawned — agent_type, agent_id, task_description.refsubagent-start/write-event-marker · update-counts
SubagentStopA subagent finishes — summary of its work.refsubagent-stop/write-event-marker · update-counts
TeammateIdleA team teammate goes idle.refteammate-idle/ignored — Team orchestration, not session history.
TaskCreatedA task is created via TaskCreate.reftask-created/ignored — Task orchestration, not session history.
TaskCompletedA task is marked complete.reftask-completed/ignored — Task orchestration, not session history.

Display, MCP & notifications

HookFires whenDocsExamplesWhat we do
MessageDisplayAn assistant message is streamed/displayed to the user.refmessage-display/ignored — UX event; the message content is already in the transcript.
ElicitationAn MCP server requests user input.refelicitation/ignored — MCP interaction control hook; an observe-only writer gains nothing.
ElicitationResultThe user responds to an elicitation.refelicitation-result/ignored — MCP interaction event; the content is in the transcript.
NotificationClaude Code emits a notification (permission_prompt, idle_prompt, auth_success, …).refnotification/ignored — UX notification, not session history.

Environment, config & files

HookFires whenDocsExamplesWhat we do
CwdChangedThe working directory changes during a session.refcwd-changed/ignored — Host signal, out of session scope.
FileChangedA watched file changes on disk.reffile-changed/ignored — Watcher signal, out of session scope.
ConfigChangeA settings/config/skills file changes during the session (user_settings, project_settings, …).refconfig-change/ignored — Config-change signal, out of session scope.

Worktrees

HookFires whenDocsExamplesWhat we do
WorktreeCreateA git worktree is created (--worktree).refworktree-create/ignored — Git-worktree lifecycle, irrelevant to session logging.
WorktreeRemoveA git worktree is removed.refworktree-remove/ignored — Git-worktree lifecycle, irrelevant to session logging.

Compaction

HookFires whenDocsExamplesWhat we do
PreCompactBefore context compaction — triggermanual/auto.refpre-compact/write-event-marker
PostCompactAfter compaction completes — triggermanual/auto.refpost-compact/write-event-marker

Turn end

HookFires whenDocsExamplesWhat we do
StopClaude finishes responding to a turn — turn_number, assistant_message.refstop/write-event-marker · flush-transcript-chunk
StopFailureA turn ends with an API error — rate_limit, overloaded, max_output_tokens, … A turn-level failure (see the crash note in the doc).refstop-failure/write-event-marker · update-counts

Session end

HookFires whenDocsExamplesWhat we do
SessionEndThe session terminates — reasonclear/resume/logout/prompt_input_exit/bypass_permissions_disabled/other.refsession-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:

  1. StopFailure — the turn hit an API/runtime error but the session is alive.
  2. SessionEnd with reason: "other" — an orderly-but-non-standard shutdown.
  3. 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 (hooks.md). Wiring an ignored event = add the action + binding in the model and register it in hooks.json (regenerated by 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 compatibility.json.