Briefing
If you run a team that builds software, here is a question worth sitting with: how much of your "engineering standards" actually live in someone's head, get forgotten under deadline pressure, and only surface in a code review three days too late?
That is the problem Claude Code hooks are built to solve. A hook is a small rule that fires automatically when something happens in the coding workflow, a file gets saved, a test fails, a commit is about to land, an AI agent finishes a job. Instead of hoping people remember the rules, you wire the rules into the tool itself. The assistant stops being something you have to ask and starts being an environment that quietly checks the work as it goes.
Two things are worth flagging up front, because the wider commentary on hooks has muddied them. First, hooks are not new. They shipped in mid-2025, not "early 2026" as some write-ups claim. Second, the exact syntax matters and a lot of online examples get it wrong. Real hooks are configured in JSON inside settings files, and they hang off specific named events. So treat the patterns below as the useful part (what hooks are good for) and check the official hooks reference before you copy any config verbatim.
The payoff, when it works, is the boring kind that compounds: standards that enforce themselves, documentation that does not rot, and a smaller pile of "why did this slip through" conversations.
The Hook Lifecycle
Hooks work on an event-and-action model. Something happens, Claude Code checks a condition, and if the condition holds it runs an action. Depending on the hook type, that condition and action can be a shell command, an HTTP call, or, in the case of the prompt and agent hook types, a natural-language instruction the model interprets. Those handler types (command, prompt, agent, and http) are all real and documented.
One correction worth making here, because the original framing oversells it: not every hook is "natural language". The default and most common type is a plain shell command matched by structured patterns. The model-interpreted prompt and agent hooks are the more sophisticated end of the range, not the baseline.
Event Types
A quick warning before the example: the YAML format and the event names below (file_save, test_failure, and so on) are illustrative rather than real Claude Code syntax. Actual hooks use JSON and a different set of event names, including PreToolUse, PostToolUse, PostToolUseFailure, FileChanged, and SubagentStop. The pseudocode is here to show the shape of the idea, not to be pasted into a config file.
# .claude/hooks.yaml
events:
- type: file_save
pattern: "*.ts"
condition: "file contains new public API surface"
action: "generate JSDoc comments for all new exports"
- type: test_failure
condition: "failure is in a file modified in the last hour"
action: "analyse failure, suggest fix, do not apply without approval"
- type: git_commit
condition: "commit message is vague or missing issue reference"
action: "suggest improved commit message with conventional commit format"
- type: agent_completion
condition: "task touched more than 3 files"
action: "generate a summary of changes for the pull request description"In a real setup, you would express the first rule through FileChanged, the git rule through a PostToolUse hook matched to the Bash tool, the test rule through PostToolUseFailure, and the completion rule through SubagentStop.
Pattern 1: Pre-Commit Validation Gate
The most common use is a gate that stops a commit when it fails your checks. It runs tests, linting, and type checking before anything reaches the remote:
# .claude/hooks.yaml
hooks:
pre_commit_validation:
event: git_pre_commit
priority: critical
condition: "any staged file is in src/ directory"
actions:
- "run npm run typecheck"
- "run npm run lint --staged"
- "run npm test --related --fail-fast"
- "if any action fails: abort commit and show actionable error"The difference from a plain git hook is context. A PreToolUse hook can inspect what is about to run and block it, where exit code 2 means block and exit code 0 means allow, and the hook reads the tool input as JSON on stdin. So if type checking fails on a missing import, a well-built gate does not just refuse the commit. It can point at the fix, and with your approval, apply it and run the checks again.
One caveat: the priority: critical and blocking: false fields shown in these examples could not be confirmed in the official reference. Blocking behaviour is reportedly handled through exit codes and JSON output rather than a named YAML key, so do not rely on those fields existing.
Pattern 2: Auto-Documentation
Documentation rot is the quiet way a codebase turns hostile. A hook can keep docs current without anyone remembering to:
auto_docs:
event: file_save
pattern: "src/**/*.ts"
condition: "function signatures changed or new exports added"
actions:
- "update README.md API section if public API changed"
- "regenerate docs/api.md from JSDoc comments"
- "add changelog entry to CHANGELOG.md with conventional commit format"Pattern 3: Architectural Guardrails
For teams with firm architectural boundaries, a hook can enforce the rule at the moment code is written. This one stops controllers from talking to the database directly:
architecture_guard:
event: file_save
pattern: "src/controllers/**/*.ts"
condition: "code imports database driver or raw SQL"
actions:
- "flag violation: controllers must use service layer"
- "suggest: move query to appropriate service in src/services/"
- "if user insists: require justification comment and log to architecture-decisions.log"Pattern 4: Post-Completion Review
When the agent finishes a task, a hook can kick off a structured review. On any job that touches more than three files, it writes a change summary, points out likely side effects, and suggests tests:
completion_review:
event: agent_completion
condition: "files_modified > 3 or test_coverage_delta < 0"
actions:
- "generate diff summary in conventional commit format"
- "identify untested paths in modified code"
- "suggest test cases for uncovered paths"
- "check for breaking changes in public APIs"Pattern 5: Sub-Agent Orchestration
The most ambitious pattern hands follow-on work to specialised sub-agents. When a particular file changes, each sub-agent picks up one piece of the cleanup. This leans on Opus 4.8's Dynamic Workflows, which Anthropic introduced for running large numbers of parallel sub-agents in a single session:
subagent_orchestration:
event: file_save
pattern: "src/schema/**/*.graphql"
actions:
- "spawn subagent: generate TypeScript types from schema changes"
- "spawn subagent: update client query hooks"
- "spawn subagent: regenerate mock data for tests"
- "await all: run integration tests for affected queries"Worth noting: Opus 4.8 is real and shipped on 28 May 2026 with Dynamic Workflows. The claim that the hooks system itself was specifically "refined through Opus 4.8" is not something the sources confirm; hooks have evolved across several Claude Code releases on their own track, separate from any one model version. Simon Willison's write-up of Opus 4.8 covers what actually shipped.
Debugging Hooks
Here the original article goes badly off the map, so read this section as a correction. It refers to a claude hooks trace --last command and a claude hooks test <file> dry run:
# Show hook execution trace for last session
claude hooks trace --last
# Show hooks that would trigger for a specific file (dry run)
claude hooks test src/api/users.tsThose commands do not exist. Real hook debugging uses the interactive /hooks menu, which is a read-only browser of the hooks you have configured, plus the --debug flag for verbose logging when a hook misbehaves. That is where you find out whether the problem is in event detection, the condition, or the action. The diagnostic instinct in the original is right; the specific commands are invented.
Performance Considerations
Hooks add time to whatever event triggers them. A save hook that type-checks the whole project will make every save feel slow. The fix is to scope conditions tightly and use incremental checks. The article also mentions a priority field for ordering and a blocking: false option for running non-critical hooks asynchronously, but as noted above, those specific fields are unconfirmed in the official reference, so test before you depend on them.
The bigger point holds up even after the syntax corrections. The interesting move with hooks is that the assistant stops waiting to be asked. It watches what happens, checks it against your team's standards, and acts. Get that right and the tool you invoke turns into the environment you work inside. Just build it on the real config format, not the one in the marketing examples.


