Skip to content

🌐 日本語

Hooks Lifecycle

IMPORTANT

→ Why: Hallucination mitigation (test execution Hooks detect mechanically) → Why: Sycophancy mitigation (compilers and test runners don't follow along) → Why: Instruction Decay mitigation (forced execution independent of context)

What Are Hooks?

Hooks are context-independent processing triggered by Claude Code lifecycle events. They don't consume the LLM's context window.

AttributeValue
Injection TimingNot injected into context
Context ConsumptionNone (Prompt/Agent Hook reason is fed back to Claude on ok: false)
Execution LocationClaude Code runtime (shell / HTTP / sub-LLM / subagent)
Definition Locationhooks key in settings.json

Why They Exist

If you instruct an LLM to "run eslint every time,"

  1. It consumes the context window
  2. It may be forgotten due to Instruction Decay
  3. It may skip judgment due to Sycophancy ("looks fine")

Hooks execute at the runtime level, avoiding all these problems.

Lifecycle Flow

TIP

Three-layer structure: Session layer (SessionStartSessionEnd) wraps the agent loop layer, and async event layer fires in parallel with the loop.

Event List

Session Lifecycle

EventFire TimingMain Use Case
SessionStartSession start/resumeEnvironment check, log initialization
SessionEndSession endCleanup
UserPromptSubmitUser input submissionInput validation, context addition
StopResponse completionContinuation judgment, quality gate
StopFailureAPI error terminationError log, alert sending

Tool Execution

EventFire TimingMain Use Case
PreToolUseBefore tool executionBlock dangerous commands
PermissionRequestPermission dialog displayAuto-approve/deny permissions
PostToolUseAfter tool successAuto-format, run lint
PostToolUseFailureAfter tool failureError log, retry judgment

Subagent & Tasks

EventFire TimingMain Use Case
SubagentStartSubagent generationContext injection to agents
SubagentStopSubagent completionResult validation, continuation judgment
TaskCreatedTask creationEnforce naming conventions, task validation
TaskCompletedTask completionValidate completion conditions
TeammateIdleBefore teammate waitsQuality gate, resource validation

Configuration & Environment Changes

EventFire TimingMain Use Case
InstructionsLoadedCLAUDE.md / rules loadedAudit log, compliance tracking
ConfigChangeConfiguration file changeSecurity audit, policy enforcement
CwdChangedWorking directory changeEnvironment variable management (direnv, etc.)
FileChangedWatched file changeAutomate file change triggers
NotificationNotification occursDesktop notification

Context Management

EventFire TimingMain Use Case
PreCompactBefore context compressionPre-compression validation
PostCompactAfter context compressionPost-compression validation

Worktree & MCP

EventFire TimingMain Use Case
WorktreeCreateWorktree creationReplace Git operations
WorktreeRemoveWorktree deletionCleanup
ElicitationMCP input requestAutomate user input
ElicitationResultMCP input responseValidate/correct response data

NOTE

For detailed event information (JSON input/output schema, matcher specification, async Hooks, etc.), refer to the official reference: Hooks reference | Hooks guide

Hook Types

IMPORTANT

All four types share the same nesting structure: event → [{ matcher?, hooks: [{ type, ... }] }]. The matcher field is a string regex (e.g. "Edit|Write") against tool names, not an object with toolName / pathPattern keys. Tool names are PascalCase (Edit, Write, Bash).

Command Hook (most common)

Runs a shell command. Hook input arrives on stdin as JSON; parse it with jq to extract fields like file_path. exit 0 allows, exit 2 blocks with stderr fed back to Claude.

jsonc
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs -r npx prettier --write --ignore-unknown",
          },
        ],
      },
    ],
  },
}

Prompt Hook (single-turn LLM judgment)

Sends the hook input to a Claude model (Haiku by default) for a yes/no decision. The model must return {"ok": true} to allow, or {"ok": false, "reason": "..."} to block. On Stop events, the reason is fed back to Claude so it keeps working.

jsonc
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Check if all tasks are complete. If not, respond with {\"ok\": false, \"reason\": \"what remains to be done\"}.",
          },
        ],
      },
    ],
  },
}

HTTP Hook (external service integration)

POSTs the hook input as JSON to an HTTP endpoint. The endpoint returns the same ok/reason JSON via response body. Useful for shared audit services across a team.

jsonc
{
  "hooks": {
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "http",
            "url": "http://localhost:8080/hooks/tool-use",
            "headers": { "Authorization": "Bearer $MY_TOKEN" },
            "allowedEnvVars": ["MY_TOKEN"],
          },
        ],
      },
    ],
  },
}

Agent Hook (multi-turn verification, experimental)

WARNING

Agent hooks are experimental. Behavior and configuration may change. For production workflows, prefer Command hooks.

Spawns a subagent that can read files, search code, and use other tools to verify conditions before returning {"ok": ..., "reason": ...}. Default timeout 60s, up to 50 tool-use turns.

jsonc
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "agent",
            "prompt": "Verify that all unit tests pass. Run the test suite and check the results. $ARGUMENTS",
            "timeout": 120,
          },
        ],
      },
    ],
  },
}

TIP

When to choose which: Command for deterministic shell rules (lint, format, file protection). Prompt when input data alone is enough for judgment (Haiku-level evaluation). Agent when verification needs to read files or run commands (e.g. test execution). HTTP when an external service should handle the logic.

Exit Code Meanings (Command Hook only)

Exit CodeMeaning
0Allow operation (continue as is. stdout may be added to context via additionalContext)
2Block operation (stderr content fed back to Claude)
OtherContinue operation. stderr logged but not shown to Claude

Prompt/Agent/HTTP hooks use the {"ok": true/false, "reason": "..."} JSON response format instead of exit codes.

Practical Recipes by Framework

FrameworkRecipe
Angular + NgRx + RxJSexamples/angular-ngrx/
SvelteKit + Svelte 5examples/svelte-kit/

8 Problems × Hooks: Quick Reference

IMPORTANT

Hooks aren't a silver bullet for every structural problem. The table below shows where Hooks are strong, where they're partial, and where other layers (rules / Agents / sessions) carry more weight. Use this as a "should I reach for a Hook here?" decision aid.

Structural ProblemRecommended Hook EventConcrete Command / TypeEffectStrength
Context RotSessionStart (matcher: compact)echo project conventions, git log --oneline -5Re-injects key rules after compaction◯ Partial — /compact itself is the main mitigation
Lost in the Middle(Hooks alone are weak)Hooks don't reposition context△ Rules / Agents are more effective
Priority SaturationPostToolUse, Stopprettier, eslint, tsc --noEmitRemoves mechanical rules from CLAUDE.md◎ Strong — frees the instruction budget
HallucinationPostToolUse, Stoptsc --noEmit, svelte-check, vitest runCompilers / type checkers don't hallucinate◎ Strong — primary mitigation
SycophancyStopCommand: eslint --no-warn-ignored
Agent Hook: "verify tests pass"
LLM agreement bias doesn't affect runners◎ Strong — mechanical verifiers don't flatter
Knowledge BoundaryStopsvelte-check (catches legacy Svelte syntax mixed with Svelte 5), tsc (catches missing types)Detects outdated API / syntax patterns◯ Partial — works only when the boundary is checkable
Prompt SensitivityPreToolUse, StopSame mechanical checks as HallucinationOutput quality doesn't depend on prompt wording◯ Partial — last line of defense
Instruction DecayStop, PreToolUseblock-dangerous-commands.sh, tsc --noEmitForced execution independent of context◎ Strong — Hooks can't be "forgotten"

TIP

Reading the strength column:

  • ◎ Strong: Hooks are the primary mitigation for this problem
  • ◯ Partial: Hooks help, but other layers (rules / Agents / sessions) do more
  • △ Weak: Don't reach for Hooks first — use a different layer

For the full countermeasure landscape across all layers (rules, Skills, Agents, sessions, plugins), see Appendix: Problem × Countermeasure Map.


Previous: The Role of settings.json

Next: Why Not Show LLMs

Released under the CC BY 4.0 License.