Extend Hard ยท deterministic GA ⓘ legend

Hooks

Your own code, run automatically at lifecycle events. The hard-enforcement escape hatch: an instruction in CLAUDE.md is a request; a hook is a guarantee.

Analogy โ€” CI hooks / git pre-commit hooks for the agent. They fire on an event whether or not anyone remembers to ask. A linter that runs after every write doesn’t depend on the model choosing to lint.

Mechanism

Configured under the "hooks" key in settings.json, three levels deep: event โ†’ matcher group โ†’ handler. Handler type is command (deterministic shell), http, mcp_tool, prompt, or agent (experimental).

Command hooks receive JSON on stdin and signal via exit codes: 0 = success (stdout JSON processed as a decision), 2 = blocking error (stderr fed back to Claude, action blocked), any other = non-blocking.

"hooks": {
  "PreToolUse": [{
    "matcher": "Bash",
    "hooks": [{ "type": "command", "command": "./guard.sh" }]
  }],
  "PostToolUse": [{
    "matcher": "Edit|Write",
    "hooks": [{ "type": "command", "command": "prettier --write \"$CLAUDE_FILE\"" }]
  }]
}
Event names & the deny decision

SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PostToolUseFailure, Stop, SubagentStart/Stop, InstructionsLoaded, PreCompact/PostCompact, and the team events TeammateIdle/TaskCreated/TaskCompleted.

PreToolUse can return hookSpecificOutput.permissionDecision: "deny" | "allow" | "ask" | "defer". The if field accepts permission-rule syntax (e.g. "Bash(git push *)") so you don’t spawn a process you don’t need. Output capped at 10,000 chars; default timeout 600s (UserPromptSubmit 30s).

When to reach for it

โœ“
You want something to happen every time, guaranteed — format on save, log every command, block a pattern.
โœ“
A guardrail that must hold even if the model “decides” otherwise โ†’ PreToolUse with a deny decision.
โœ“
Quality gates on agent teams (exit code 2 on TaskCompleted).

When not to

โœ•
Simple block/allow by command pattern โ†’ a permission rule is lighter (no process spawned).
โœ•
Guidance the model should consider but can adapt โ†’ CLAUDE.md or a skill.

Best practices

โ˜…
Keep command hooks deterministic and idempotent — they may run often.
โ˜…
Use the if field to avoid firing on irrelevant tool calls.
โ˜…
Inspect what’s active with /hooks; remember managed settings can force or restrict them.
Hooks โ‰  rules A hook runs your code. A “permission rule” is config. A .claude/rules/ file is just memory. Three different things wear the word “rule” — see the corrections.

Sources