Claude hooks
Claude / Hooks
119 hook commands are registered in 7 places and run 70 distinct scripts; each script has its own page. In a $HOME-rooted session 83 of them are live. Pages: 70 registered hooks and 29 other hook modules.
Lifecycle
The diagram shows the hooks that load in a $HOME session (the codetools plugin is marked cond.). Repo-scoped twins registered in wt-MAP-PRECOMMIT/.claude/settings.json are dark in $HOME sessions and are left out. Click a hook to open its page.
Counts
Registrations per source
| Source | Hook commands | Live in $HOME | Block | Ask | Advisory |
|---|---|---|---|---|---|
| ~/.claude/settings.json | 2 | yes | 1 | 0 | 1 |
| ~/.claude/settings.local.json | 3 | yes | 1 | 0 | 2 |
| orchestrata plugin 1.5.0 hooks.json | 65 | yes | 30 | 1 | 34 |
| tmux-status plugin 1.2.0 hooks.json | 11 | yes | 0 | 0 | 11 |
| turn-navigator plugin 1.1.3 hooks.json | 2 | yes | 0 | 0 | 2 |
| codetools plugin 0.1.0 hooks.json | 5 | conditional | 3 | 0 | 2 |
| wt-MAP-PRECOMMIT/.claude/settings.json | 31 | no | 21 | 0 | 10 |
| Live in a $HOME session | 83 | yes | 32 | 1 | 50 |
| All sources | 119 | 56 | 1 | 62 |
Registrations per event
| Event | All | Live in $HOME | Codetools (conditional) | Repo (dark) |
|---|---|---|---|---|
| SessionStart | 30 | 21 | 1 | 8 |
| UserPromptSubmit | 13 | 12 | 0 | 1 |
| PreToolUse | 41 | 24 | 2 | 15 |
| PermissionRequest | 2 | 2 | 0 | 0 |
| PostToolUse | 8 | 6 | 0 | 2 |
| Notification | 3 | 3 | 0 | 0 |
| ElicitationResult | 1 | 1 | 0 | 0 |
| Stop | 15 | 8 | 2 | 5 |
| SubagentStart | 1 | 1 | 0 | 0 |
| SubagentStop | 2 | 2 | 0 | 0 |
| SessionEnd | 3 | 3 | 0 | 0 |
All hook scripts
| Hook | Event(matcher) | Type | Sources | Live in $HOME | Role |
|---|---|---|---|---|---|
| dispatch_ledger | SubagentStop | advisory | S | yes | dispatch_ledger.py records one row per finished subagent in an append-only NDJSON ledger. |
| unshipped_guard | Stop | block | S | yes | unshipped_guard.py blocks the end of a turn while committed work this session produced exists only on the local machine. |
| codemap_refresh | SessionStart, SubagentStart | advisory | SL | yes | codemap_refresh.sh gives the session and every subagent the codetools codebase-map instruction, and regenerates a repo's map when the repo opts in. |
| precommit_gate_subagent | SubagentStop | block | SL | yes | precommit_gate_subagent.sh stops a worker from handing back Python edits that the repository's commit gate would refuse. |
| autoformat | PostToolUse(Write|Edit|MultiEdit) | advisory | OH | yes | autoformat.py formats a file right after Claude writes it. |
| test_isolation_hook | PostToolUse(Write|Edit|MultiEdit) | advisory | OH | yes | test_isolation_hook.py audits a test file for isolation leaks the moment it is written. |
| ast_sync_hook | PostToolUse(Write|Edit|MultiEdit) | advisory | OH | yes | ast_sync_hook.py keeps the code-intelligence graph and Prolog knowledge base current in any project, in the background. |
| ast-incremental-refresh | PostToolUse(Write|Edit|MultiEdit) | block | OH, WS | yes | ast-incremental-refresh.sh refreshes the AST snapshot as soon as a Python file changes, so the structural queries the toolkit forces on the model are not served from a stale parse. |
| typecheck-on-write | PostToolUse(Write|Edit|MultiEdit) | block | OH, WS | yes | typecheck-on-write.sh runs mypy right after a source file is written and reports when the tree is red. |
| session_resume_context | SessionStart | advisory | OH | yes | session_resume_context.py loads the last session's context into a new one. |
| boot_health_check | SessionStart | advisory | OH | yes | boot_health_check.sh prints a short machine health report at session start and injects it as context. |
| irc_agents_hook | SessionStart | advisory | OH | yes | irc_agents_hook.sh makes sure Claude is joined to the #agents IRC channel and that the capture listener is running. |
| claude_irc_inbox | SessionStart, UserPromptSubmit | advisory | OH | yes | claude_irc_inbox.py puts #agents IRC messages addressed to Claude in front of the session. |
| conversation_recall_hook | SessionStart | advisory | OH | yes | conversation_recall_hook.sh restores the last few minutes of recorded work at session start. |
| project_context | SessionStart | advisory | OH | yes | project_context.sh prints a dense, factual digest of the project the session is in, at session start. |
| platform_conventions_prompt | SessionStart | advisory | OH | yes | platform_conventions_prompt.py loads the standing platform conventions into every session and verifies the machine state behind each one. |
| agent_mail_inbox | SessionStart, UserPromptSubmit | advisory | OH | yes | agent_mail_inbox.py delivers direct messages from other agents into the session. |
| project_context_refresh | SessionStart | advisory | OH | yes | project_context_refresh.py re-derives the project's structural context at every session start and after compaction. |
| test_run_context | SessionStart, UserPromptSubmit, PreToolUse(Bash) | block | OH | yes | test_run_context.py tells the model what test runs are in flight on the box and denies CPU-heavy commands while an authoritative run is measuring. |
| ast-freshness-pin | SessionStart | advisory | OH, WS | yes | ast-freshness-pin.sh pins the AST mandate together with the evidence that it is safe to obey, at every session start. |
| inject-codebase-map | SessionStart | advisory | OH, WS | yes | inject-codebase-map.sh keeps the two-tier codebase map fresh at session start. |
| start-ast-daemon | SessionStart | advisory | OH, WS | yes | start-ast-daemon.sh makes sure the AST daemon serving the repo is the deployed one. |
| start-architecture-sync | SessionStart | advisory | OH, WS | yes | start-architecture-sync.sh launches a full architecture sync into the operational graph at session start, in the background. |
| session-overview | SessionStart | advisory | OH, WS | yes | session-overview.sh puts the session overview digest into the first turn's context. |
| worktree-gc | SessionStart | advisory | OH, WS | yes | worktree-gc.sh removes finished git worktrees at session start. |
| error-report | SessionStart | advisory | OH, WS | yes | error-report.sh prints the current red list into the first turn so nothing is reported green before it has been looked at. |
| reap-orphan-waiters | SessionStart | advisory | OH, WS | yes | reap-orphan-waiters.sh kills polling loops that a finished agent left behind. |
| session_handoff_reminder | SessionEnd | advisory | OH | yes | session_handoff_reminder.py reminds you to write a handoff when a session ends with the tracker still open. |
| session_open_hook | UserPromptSubmit | advisory | OH | yes | session_open_hook.py starts a session when the user types the start phrase. |
| session_close_hook | UserPromptSubmit | advisory | OH | yes | session_close_hook.py closes the session when the user types the close phrase. |
| remember_hook | UserPromptSubmit | advisory | OH | yes | remember_hook.py answers "do you remember" questions from stored conversation history before the model sees the prompt. |
| infra_check | UserPromptSubmit | advisory | OH | yes | infra_check.py is meant to report infrastructure status when the user asks about it, and it never fires. |
| claude_turn_capture | UserPromptSubmit, Stop | advisory | OH | yes | claude_turn_capture.py records every conversation turn so it can be recalled later. |
| workflow_context_inject | UserPromptSubmit | advisory | OH | yes | workflow_context_inject.py injects the methodology that fits the task the prompt describes. |
| decision_adr_trigger | UserPromptSubmit, Stop | advisory | OH, CH | yes | decision_adr_trigger.sh is two different scripts with one name - a working UserPromptSubmit reminder in the orchestrata plugin, and an inert Stop hook in the codetools plugin. |
| decision-adr-trigger | UserPromptSubmit | advisory | OH, WS | yes | decision-adr-trigger.sh reminds the model to use the decision skill whenever a prompt talks about decisions. |
| forbidden-doubles-stop | Stop | block | OH, WS | yes | forbidden-doubles-stop.sh is a Stop guard that blocks the end of a turn that wrote a test double into Python or talked about mocks, fakes or stubs as something to use. |
| no-guessing-stop | Stop | block | OH, WS | yes | no-guessing-stop.sh is the Stop guard for RUL-017 - it blocks a turn that hedged instead of finding out. |
| no-preexisting-excuse | Stop | block | OH, WS | yes | no-preexisting-excuse.sh is the Stop guard for RUL-024 - "pre-existing" is a diagnosis, not a disposition. |
| no-offer-instead-of-fix | Stop | block | OH, WS | yes | no-offer-instead-of-fix.sh is the Stop guard for RUL-006, fix on sight - offering to fix a named defect, or deferring it on your own authority, is the violation. |
| stop-timestamp | Stop | advisory | OH, WS | yes | stop-timestamp.sh stamps every assistant turn end with the wall-clock time. |
| route_pytest_to_threads | PreToolUse(Bash) | block | OH | yes | route_pytest_to_threads.py rewrites a direct pytest invocation into the project's threaded, live-observed runner, or denies it when it cannot rewrite safely. |
| convention_guard | PreToolUse(Bash|Write|Edit|MultiEdit) | ask | OH | yes | convention_guard.py is the one hook that asks rather than denies - it stops a command or edit that contradicts a standing platform convention and lets Mohamed confirm with one keypress. |
| task_context_hook | PreToolUse(Agent|Edit|MultiEdit|Write|NotebookEdit) | block | OH | yes | task_context_hook.py gates every subagent brief and injects structural context into briefs and into the main session's Python edits. |
| intercept_bash | PreToolUse(Bash) | block | OH | yes | intercept_bash.py is the PreToolUse(Bash) guard that stops files being written through the shell and stops any deletion command, in every project. |
| intercept_write | PreToolUse(Write) | block | OH | yes | intercept_write.py is the PreToolUse(Write) guard that forces Edit for existing files and keeps session state and plans out of the Write tool. |
| intercept_edit | PreToolUse(Edit|MultiEdit) | advisory | OH | yes | intercept_edit.py is a PreToolUse(Edit|MultiEdit) hook that records an undo checkpoint before every edit and never blocks. |
| install_secret_guard | PreToolUse(Bash) | block | OH | yes | install_secret_guard.py is the PreToolUse(Bash) guard against unpinned package installs, registry overrides and credential materialization. |
| no-xdist | PreToolUse(Bash) | block | OH, WS | yes | no-xdist.sh denies pytest-xdist invocations in the governed tree. |
| force-ast-toolkit | PreToolUse(Bash), PreToolUse(Read) | block | OH, WS | yes | force-ast-toolkit.sh denies hand-reading of the governed tree's Python source and sends the model to the AST toolkit. |
| single-gate-entrypoint | PreToolUse(Bash) | block | OH, WS | yes | single-gate-entrypoint.sh denies running the review gates one by one and points to the single entry point. |
| force-test-observation | PreToolUse(Bash) | block | OH, WS | yes | force-test-observation.sh enforces the 2026-07-10 ruling that every test run is observed live, never waited on blind. |
| no-unbounded-wait | PreToolUse(Bash) | block | OH, WS | yes | no-unbounded-wait.sh refuses polling loops that have no way to stop. |
| force-trace-intel | PreToolUse(Bash) | block | OH, WS | yes | force-trace-intel.sh denies sweeping the tree for requirement ids or @traces - traceability is a query, not a file crawl. |
| proportionate-test-scope | PreToolUse(Bash) | block | OH, WS | yes | proportionate-test-scope.sh denies a full-suite run when the change is small enough to be tested by a few modules, and hands back the exact targeted command. |
| force-code-intel | PreToolUse(Bash) | block | OH, WS | yes | force-code-intel.sh denies recursive greps for structural questions (imports, definitions, calls) and points to the code-intelligence queries. |
| force-graph-query | PreToolUse(Bash) | block | OH, WS | yes | force-graph-query.sh denies ad-hoc graph driver one-liners and sends the model through the sanctioned graph seams. |
| no-doubles-py | PreToolUse(Write|Edit|MultiEdit) | block | OH, WS | yes | no-doubles-py.sh refuses to write a Python file that introduces a test double (mock, fake or stub). |
| no-banned-deps | PreToolUse(Write|Edit|MultiEdit) | block | OH, WS | yes | no-banned-deps.sh denies adding a banned library to pyproject.toml. |
| force-session-cli | PreToolUse(Write|Edit|MultiEdit) | block | OH, WS | yes | force-session-cli.sh denies hand edits to the session tracker files and lists the session CLI commands that replace them. |
| require-design-before-build | PreToolUse(Agent) | block | OH, WS | yes | require-design-before-build.sh enforces RUL-022, design before build - it refuses to dispatch a builder, wirer or refactorer without a ratified design. |
| workflow-default-sonnet | PreToolUse(Workflow) | block | OH, WS | yes | workflow-default-sonnet.sh refuses a Workflow script whose agent() calls omit a model, so delegated work does not silently inherit the main-loop model. |
| permission_no_hang | PermissionRequest | block | OH | yes | permission_no_hang.py turns an auto-mode classifier denial into an immediate refusal so the session does not stall on a permission prompt nobody will answer. |
| tmux-rename | SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Stop, SessionEnd, PermissionRequest, ElicitationResult, Notification(permission_prompt), Notification(elicitation_dialog), Notification(idle_prompt) | advisory | TH | yes | tmux-rename.sh shows the Claude Code session state in the tmux window name. |
| setup-nav | SessionStart | advisory | NH | yes | setup-nav.sh turns on turn navigation for the pane at session start. |
| turn-nav | SessionEnd | advisory | NH | yes | turn-nav is the command the turn-navigator plugin uses to manage per-pane turn navigation; the hook registration runs turn-nav deactivate on SessionEnd. |
| ensure-swipl | SessionStart | advisory | CH | conditional | ensure-swipl.sh makes sure a SWI-Prolog is available to the codetools plugin at session start. |
| block_except_pass | PreToolUse(Write|Edit|MultiEdit) | block | CH | conditional | block_except_pass.py is a codetools PreToolUse(Write|Edit|MultiEdit) hook meant to refuse bare except - and except ... - pass in Python. |
| error_gate | PreToolUse(Write|Edit|MultiEdit) | block | CH | conditional | error_gate.py is a codetools PreToolUse(Write|Edit|MultiEdit) hook meant to refuse Python that does not parse or that declares more than one top-level class. |
| coverage_gate | Stop | block | CH | conditional | coverage_gate.py is a codetools Stop hook meant to refuse a finish when measured line coverage is under the floor. |
Every registration
The 119 hook commands in order of source and event. Registrations of the same script share one page.
| # | Event | Matcher | Source | Live | Page |
|---|---|---|---|---|---|
| 1 | SubagentStop | all | S | yes | dispatch_ledger |
| 2 | Stop | all | S | yes | unshipped_guard |
| 3 | SessionStart | all | SL | yes | codemap_refresh |
| 4 | SubagentStart | all | SL | yes | codemap_refresh |
| 5 | SubagentStop | all | SL | yes | precommit_gate_subagent |
| 6 | PostToolUse | Write|Edit|MultiEdit |
OH | yes | autoformat |
| 7 | PostToolUse | Write|Edit|MultiEdit |
OH | yes | test_isolation_hook |
| 8 | PostToolUse | Write|Edit|MultiEdit |
OH | yes | ast_sync_hook |
| 9 | PostToolUse | Write|Edit|MultiEdit |
OH | yes | ast-incremental-refresh |
| 10 | PostToolUse | Write|Edit|MultiEdit |
OH | yes | typecheck-on-write |
| 11 | SessionStart | all | OH | yes | session_resume_context |
| 12 | SessionStart | all | OH | yes | boot_health_check |
| 13 | SessionStart | all | OH | yes | irc_agents_hook |
| 14 | SessionStart | all | OH | yes | claude_irc_inbox |
| 15 | SessionStart | all | OH | yes | conversation_recall_hook |
| 16 | SessionStart | all | OH | yes | project_context |
| 17 | SessionStart | all | OH | yes | platform_conventions_prompt |
| 18 | SessionStart | all | OH | yes | agent_mail_inbox |
| 19 | SessionStart | all | OH | yes | project_context_refresh |
| 20 | SessionStart | all | OH | yes | test_run_context |
| 21 | SessionStart | all | OH | yes | ast-freshness-pin |
| 22 | SessionStart | all | OH | yes | inject-codebase-map |
| 23 | SessionStart | all | OH | yes | start-ast-daemon |
| 24 | SessionStart | all | OH | yes | start-architecture-sync |
| 25 | SessionStart | all | OH | yes | session-overview |
| 26 | SessionStart | all | OH | yes | worktree-gc |
| 27 | SessionStart | all | OH | yes | error-report |
| 28 | SessionStart | all | OH | yes | reap-orphan-waiters |
| 29 | SessionEnd | all | OH | yes | session_handoff_reminder |
| 30 | UserPromptSubmit | all | OH | yes | session_open_hook |
| 31 | UserPromptSubmit | all | OH | yes | session_close_hook |
| 32 | UserPromptSubmit | all | OH | yes | remember_hook |
| 33 | UserPromptSubmit | all | OH | yes | infra_check |
| 34 | UserPromptSubmit | all | OH | yes | claude_turn_capture |
| 35 | UserPromptSubmit | all | OH | yes | claude_irc_inbox |
| 36 | UserPromptSubmit | all | OH | yes | workflow_context_inject |
| 37 | UserPromptSubmit | all | OH | yes | agent_mail_inbox |
| 38 | UserPromptSubmit | all | OH | yes | test_run_context |
| 39 | UserPromptSubmit | all | OH | yes | decision_adr_trigger |
| 40 | UserPromptSubmit | all | OH | yes | decision-adr-trigger |
| 41 | Stop | all | OH | yes | claude_turn_capture |
| 42 | Stop | all | OH | yes | forbidden-doubles-stop |
| 43 | Stop | all | OH | yes | no-guessing-stop |
| 44 | Stop | all | OH | yes | no-preexisting-excuse |
| 45 | Stop | all | OH | yes | no-offer-instead-of-fix |
| 46 | Stop | all | OH | yes | stop-timestamp |
| 47 | PreToolUse | Bash |
OH | yes | route_pytest_to_threads |
| 48 | PreToolUse | Bash|Write|Edit|MultiEdit |
OH | yes | convention_guard |
| 49 | PreToolUse | Agent|Edit|MultiEdit|Write|NotebookEdit |
OH | yes | task_context_hook |
| 50 | PreToolUse | Bash |
OH | yes | test_run_context |
| 51 | PreToolUse | Bash |
OH | yes | intercept_bash |
| 52 | PreToolUse | Write |
OH | yes | intercept_write |
| 53 | PreToolUse | Edit|MultiEdit |
OH | yes | intercept_edit |
| 54 | PreToolUse | Bash |
OH | yes | install_secret_guard |
| 55 | PreToolUse | Bash |
OH | yes | no-xdist |
| 56 | PreToolUse | Bash |
OH | yes | force-ast-toolkit |
| 57 | PreToolUse | Bash |
OH | yes | single-gate-entrypoint |
| 58 | PreToolUse | Bash |
OH | yes | force-test-observation |
| 59 | PreToolUse | Bash |
OH | yes | no-unbounded-wait |
| 60 | PreToolUse | Bash |
OH | yes | force-trace-intel |
| 61 | PreToolUse | Bash |
OH | yes | proportionate-test-scope |
| 62 | PreToolUse | Bash |
OH | yes | force-code-intel |
| 63 | PreToolUse | Bash |
OH | yes | force-graph-query |
| 64 | PreToolUse | Read |
OH | yes | force-ast-toolkit |
| 65 | PreToolUse | Write|Edit|MultiEdit |
OH | yes | no-doubles-py |
| 66 | PreToolUse | Write|Edit|MultiEdit |
OH | yes | no-banned-deps |
| 67 | PreToolUse | Write|Edit|MultiEdit |
OH | yes | force-session-cli |
| 68 | PreToolUse | Agent |
OH | yes | require-design-before-build |
| 69 | PreToolUse | Workflow |
OH | yes | workflow-default-sonnet |
| 70 | PermissionRequest | all | OH | yes | permission_no_hang |
| 71 | SessionStart | all | TH | yes | tmux-rename |
| 72 | UserPromptSubmit | all | TH | yes | tmux-rename |
| 73 | PreToolUse | all | TH | yes | tmux-rename |
| 74 | PostToolUse | all | TH | yes | tmux-rename |
| 75 | Stop | all | TH | yes | tmux-rename |
| 76 | SessionEnd | all | TH | yes | tmux-rename |
| 77 | PermissionRequest | all | TH | yes | tmux-rename |
| 78 | ElicitationResult | all | TH | yes | tmux-rename |
| 79 | Notification | permission_prompt |
TH | yes | tmux-rename |
| 80 | Notification | elicitation_dialog |
TH | yes | tmux-rename |
| 81 | Notification | idle_prompt |
TH | yes | tmux-rename |
| 82 | SessionStart | all | NH | yes | setup-nav |
| 83 | SessionEnd | all | NH | yes | turn-nav |
| 84 | SessionStart | all | CH | conditional | ensure-swipl |
| 85 | PreToolUse | Write|Edit|MultiEdit |
CH | conditional | block_except_pass |
| 86 | PreToolUse | Write|Edit|MultiEdit |
CH | conditional | error_gate |
| 87 | Stop | all | CH | conditional | coverage_gate |
| 88 | Stop | all | CH | conditional | decision_adr_trigger |
| 89 | UserPromptSubmit | all | WS | no | decision-adr-trigger |
| 90 | SessionStart | all | WS | no | ast-freshness-pin |
| 91 | SessionStart | all | WS | no | inject-codebase-map |
| 92 | SessionStart | all | WS | no | start-ast-daemon |
| 93 | SessionStart | all | WS | no | start-architecture-sync |
| 94 | SessionStart | all | WS | no | session-overview |
| 95 | SessionStart | all | WS | no | worktree-gc |
| 96 | SessionStart | all | WS | no | error-report |
| 97 | SessionStart | all | WS | no | reap-orphan-waiters |
| 98 | PreToolUse | Bash |
WS | no | no-xdist |
| 99 | PreToolUse | Bash |
WS | no | force-ast-toolkit |
| 100 | PreToolUse | Bash |
WS | no | single-gate-entrypoint |
| 101 | PreToolUse | Bash |
WS | no | force-test-observation |
| 102 | PreToolUse | Bash |
WS | no | no-unbounded-wait |
| 103 | PreToolUse | Bash |
WS | no | force-trace-intel |
| 104 | PreToolUse | Bash |
WS | no | proportionate-test-scope |
| 105 | PreToolUse | Bash |
WS | no | force-code-intel |
| 106 | PreToolUse | Bash |
WS | no | force-graph-query |
| 107 | PreToolUse | Read |
WS | no | force-ast-toolkit |
| 108 | PreToolUse | Write|Edit|MultiEdit |
WS | no | no-doubles-py |
| 109 | PreToolUse | Write|Edit|MultiEdit |
WS | no | no-banned-deps |
| 110 | PreToolUse | Write|Edit|MultiEdit |
WS | no | force-session-cli |
| 111 | PreToolUse | Agent |
WS | no | require-design-before-build |
| 112 | PreToolUse | Workflow |
WS | no | workflow-default-sonnet |
| 113 | Stop | all | WS | no | forbidden-doubles-stop |
| 114 | Stop | all | WS | no | no-guessing-stop |
| 115 | Stop | all | WS | no | no-preexisting-excuse |
| 116 | Stop | all | WS | no | no-offer-instead-of-fix |
| 117 | Stop | all | WS | no | stop-timestamp |
| 118 | PostToolUse | Write|Edit|MultiEdit |
WS | no | ast-incremental-refresh |
| 119 | PostToolUse | Write|Edit|MultiEdit |
WS | no | typecheck-on-write |
Source keys: S = ~/.claude/settings.json; SL = ~/.claude/settings.local.json; OH = orchestrata plugin 1.5.0 hooks.json; TH = tmux-status plugin 1.2.0 hooks.json; NH = turn-navigator plugin 1.1.3 hooks.json; CH = codetools plugin 0.1.0 hooks.json; WS = wt-MAP-PRECOMMIT/.claude/settings.json.
Other hook modules
Pages for modules that are not registered as hook commands (libraries, earlier hooks):
| Module | Status | Description |
|---|---|---|
| ast-toolkit-hint | historical | PreToolUse(Bash) hook that suggests the token-precise AST toolkit when a grep/rg/sed command performs a structural search over src/. |
| block_file_tools | shipped | PreToolUse hook that enriches Read/Grep tool calls with knowledge-graph context injected as additionalContext. |
| context_graph-init | shipped | Package init that re-exports the four context-graph components as the public API. |
| context_graph-compactor | shipped | GraphCompactor prunes old session context from Neo4j using tiered retention while preserving relationships. |
| context_graph-loader | shipped | ContextGraphLoader queries Neo4j for only the session context relevant to the current session, replacing full context.md reads. |
| context_graph-schema | shipped | Driver factory plus create/verify/drop functions for the Ctx-prefixed Neo4j schema backing session context. |
| context_graph-updater | shipped | ContextGraphUpdater records sessions, tasks, decisions, files, blockers, and errors into the Neo4j context graph. |
| deception_detector | shipped | Pattern-based checks that compare Claude's claimed actions against actual tool usage, used by the Stop Auditor hook. |
| enforcement_hook | shipped | PreToolUse hook that validates every tool call against CLAUDE.constraints.json rules and blocks or warns by severity. |
| error_gate-init | shipped | Stop-hook entry point that blocks Claude from ending a session while unfixed errors exist. |
| error_gate-checks_lint | shipped | Runs flake8 on git-modified Python files for critical E9/F8 error categories only. |
| error_gate-checks_structure | shipped | AST-based structural checks detecting stub methods, deep nesting, and oversized classes or files. |
| error_gate-checks_syntax | shipped | Detects syntax errors in git-modified Python files by parsing each with ast in a subprocess. |
| error_gate-checks_test | shipped | Runs pytest on recently changed test files, excluding pyswip/Prolog tests, to catch regressions. |
| error_gate-utils | shipped | Shared subprocess, git file-discovery, and AST-parsing helpers plus thresholds for all error-gate checks. |
| error_gate_hook | shipped | Thin Stop-hook entry point that blocks session end while the codebase has unfixed errors. |
| instruction_enforcer_hook | shipped | PreToolUse hook that enforces CLAUDE.md constraint rules — prohibited patterns, required workflows, uv-over-pip, safe file removal, no test mocking, no AI attribution — by blocking, warning, or rewriting tool calls. |
| log_operation | shipped | PostToolUse hook that appends every file operation and shell command to a JSON-lines audit log. |
| posttool_auditor | shipped | PostToolUse hook that appends per-session JSONL records of every tool call for analysis and deception detection. |
| read_throttle | shipped | Claude Code PreToolUse hook that limits Read/Grep operations to three per 30 seconds to encourage knowledge-graph-first exploration. |
| session-prime | historical | SessionStart hook that runs session prime synchronously and prints its startup digest into first-turn context. |
| session_context_hook | shipped | Claude SessionStart hook that injects enforcement config, persona, and Neo4j project context into the session. |
| stop_audit-init | shipped | One-line package docstring marking the stop_audit deception-detection submodules for the Stop hook. |
| stop_audit-deception | shipped | Pattern-based checks comparing Claude's claimed actions against actual tool usage in the session. |
| stop_audit-subagent | shipped | Thin shim re-exporting the subagent Stop hook handlers from stop_auditor_subagent. |
| stop_audit-transcript | shipped | Extracts assistant message text from Claude Code JSONL session transcripts for the Stop Auditor. |
| stop_auditor | shipped | Stop-event hook that audits each session for deception by comparing assistant claims against recorded tool usage. |
| stop_auditor_subagent | shipped | Helper module imported by stop_auditor.py that audits subagent transcripts for deception on SubagentStop events. |
| sync_context_md | shipped | PostToolUse hook that re-renders context.md whenever context.json is written. |
Notes
This index covers every hook command Claude Code reads on this host. The inventory was taken on 2026-10-22 and rechecked on 2026-10-23: 119 hook commands in seven registration places, run by 70 distinct scripts, and 83 of the commands are live in a session rooted in $HOME.
Where hooks come from
Hooks are registered at the user level only (RUL-035): in ~/.claude/settings.json and settings.local.json (hand-placed hooks such as the dispatch ledger, the unshipped-work guard and the pre-commit gate for subagents), in the orchestrata plugin's hooks/hooks.json (65 commands, the bulk of the behaviour), and in the tmux-status and turn-navigator plugins (13 commands that only drive the terminal). Two registrations are not live in a $HOME session. The codetools plugin is installed with local scope for /home/mohamed/workspace, so its 5 hooks fire only in sessions rooted there. The worktree's .claude/settings.json holds 31 repo-scoped twins of the project guards; a $HOME-rooted session never reads that file, which is why the guards were delivered through the plugin instead. Two files look like registrations and are not read: ~/.claude/settings.hooks.json (34 hooks, copied by the installer, never loaded) and the repository's claude/settings.json (12 hooks, never deployed, one of which names a script that does not exist). ~/.claude/settings.json is not generated from the repository file: the installer only rewrites interpreter paths in it.
The project dispatcher
Thirty-one of the plugin's commands (30 distinct scripts; force-ast-toolkit is registered for both Bash and Read) are bash _dispatch.sh <guard>. The dispatcher finds the repository that owns the call (a leading cd, then the file_path, the payload cwd, CLAUDE_PROJECT_DIR, the hook's cwd), runs the guard only when that tree holds scripts/serialize_codebase_ast.py, and exits 0 silently everywhere else, so one registration governs one project without touching others. Pathless events (Stop, Agent, Workflow, UserPromptSubmit) reuse a per-session memo that an earlier path-bearing call wrote, and SessionStart cannot, because the memo is empty then. If CLAUDE_PROJECT_DIR is the repo and the repo has its own .claude/settings.json, the plugin copy stands down so the guard does not fire twice. Each guard runs in its own process group under a 120 second watchdog; a timeout counts as no opinion. Every decision is appended to $XDG_RUNTIME_DIR/orchestrata-project-hooks/audit.log, which records RUN before the stand-down check and therefore over-reports.
How to read the types
Of all 119 commands, 54 can block or deny, 1 asks for confirmation (convention_guard) and 64 are advisory (inject context or run a side effect). Of the 83 live in $HOME, 30 block, 1 asks and 52 are advisory. Two kinds of block exist and behave differently. A PreToolUse deny stops the call before it runs. A Stop block forces the turn to continue with the reason; the four Stop guards (no-guessing-stop, no-preexisting-excuse, no-offer-instead-of-fix, forbidden-doubles-stop) read the last message and skip when stop_hook_active is set. A PostToolUse exit 2 (typecheck-on-write, ast-incremental-refresh) cannot undo the write, so it is feedback, not a block.
The five that change daily work most
intercept_bash (no file writes or deletes through Bash), intercept_write (Write only for new files), autoformat (rewrites the file after every write), task_context_hook (gates and enriches every subagent brief) and the dispatch guards led by force-ast-toolkit and force-test-observation. Once a session touches the governed tree, every Bash call passes nine deny guards and every Read one. Next: unshipped_guard, test_run_context, precommit_gate_subagent and convention_guard.
Open defects
The detail is on each page; the ones that matter across pages. Three hand-placed hooks (codemap_refresh, precommit_gate_subagent, dispatch_ledger) and ~/bin/precommit-check are in no repository, so the installer's rsync --delete removes them on the next deploy while the settings still register them. Several hooks never act: infra_check reads the wrong payload field, and the codetools block_except_pass, error_gate and Stop decision_adr_trigger read top-level fields or emit a decision value that the event ignores; coverage_gate can loop. The decision reminder is injected twice (decision-adr-trigger). Ten plugin commands run the separately deployed ~/.claude copies instead of ${CLAUDE_PLUGIN_ROOT}, so the plugin alone does not carry them. Two writers can race on docs/CODEBASE_MAP*.md. $HOME is a git repository with a pyproject.toml, so $HOME sessions index it. Each Bash call starts about fifteen hook commands, and tmux-status fires on every tool call. Unverified: whether the dispatcher's 120 second watchdog exceeds the harness's default per-hook timeout. For the practical side see the shell-guards skill; the policy sits in workflow, gates and briefs.
Earlier documentation
Event-driven scripts that run on SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Stop, SubagentStop, and SessionEnd. Each page documents the trigger contract, every function, a decision-flow diagram, and the full source.
Shell hooks (.claude/hooks/)
| Hook | Event | Purpose |
|---|---|---|
| session-prime | SessionStart | Run the session prime startup digest (45s backstop) |
| inject-codebase-map | SessionStart | Refresh/inject the two-tier codebase map |
| start-architecture-sync | SessionStart | Background graph + semantic-twin sync |
| start-ast-daemon | SessionStart | Warm the AST daemon if not healthy |
| ast-toolkit-hint | PreToolUse(Bash) | Advisory hint toward the AST toolkit (never blocks) |
| force-test-observation | PreToolUse(Bash) | Enforce live observation of test runs (ruling 2026-07-10) |
| no-xdist | PreToolUse(Bash) | Deny pytest -n/--dist (xdist deadlock ban) |
| no-banned-deps | PreToolUse(Write/Edit) | Deny banned libraries entering pyproject.toml |
| no-doubles-py | PreToolUse(Write/Edit) | Block mock/fake/stub patterns in Python edits |
| no-preexisting-excuse | Stop | RUL-024: "pre-existing" is a diagnosis, not a disposition |
| forbidden-doubles-stop | Stop | Transcript scan for mock/fake/stub usage |
| require-design-before-build | PreToolUse(Agent) | RUL-022 design gate before dispatching agents |
Python hooks (claude/hooks/)
| Hook | Event | Purpose |
|---|---|---|
| session_context_hook | SessionStart | Inject session context |
| session_resume_context | SessionStart | Auto-load session status |
| test_run_context | SessionStart + PreToolUse(Bash) | Report the run in flight; deny contending CPU work |
| session_open_hook | UserPromptSubmit | "SNS" session start flow |
| infra_check | UserPromptSubmit | Infra status on SNS/status/infra prompts |
| session_handoff_reminder | SessionEnd | Remind to record handoff |
| enforcement_hook | PreToolUse(*) | Constraint enforcement + event logging |
| instruction_enforcer_hook | PreToolUse | Instruction enforcement with redirect responses |
| task_context_hook | PreToolUse(Agent/Edit/Write) | Inject module AST, blast radius, contracts + RAG |
| intercept_bash | PreToolUse(Bash) | Bash interception |
| intercept_edit | PreToolUse(Edit) | Git checkpoint before edits |
| intercept_write | PreToolUse(Write) | Write guards (context files, plans, overwrites) |
| block_except_pass | PreToolUse(Write/Edit) | AST-block bare except:/except: pass |
| block_file_tools | PreToolUse(Read/Grep) | Context injector (currently allow-only) |
| log_operation | PostToolUse | Append to file_operations.log |
| posttool_auditor | PostToolUse | Per-session tool-call audit JSONL |
| read_throttle | PreToolUse(Read) | Read throttling |
| remember_hook | — | Remember/wikipedia helper |
| sync_context_md | — | Sync context.md |
| error_gate_hook | Stop | Shim into the error_gate package |
| deception_detector | Stop library | Deception-detection checks |
| stop_auditor | Stop | Transcript audit on stop |
| stop_auditor_subagent | SubagentStop | Subagent transcript audit |
context_graph/ package
| Module | Purpose |
|---|---|
| context_graph-init | Package facade |
| context_graph-loader | ContextGraphLoader read API + context dataclasses |
| context_graph-updater | ContextGraphUpdater write API |
| context_graph-compactor | GraphCompactor tiered retention |
| context_graph-schema | Graph schema management |
error_gate/ package
| Module | Purpose |
|---|---|
| error_gate-init | Package entry / main gate logic |
| error_gate-checks_lint | Lint checks |
| error_gate-checks_structure | Structure checks |
| error_gate-checks_syntax | Syntax checks |
| error_gate-checks_test | Test-failure checks |
| error_gate-utils | Shared utilities |
stop_audit/ package
| Module | Purpose |
|---|---|
| stop_audit-init | Package marker |
| stop_audit-deception | Deception-detection module |
| stop_audit-subagent | Re-export shim |
| stop_audit-transcript | JSONL transcript parser |
Lifecycle
Back to Claude configuration.