Claude Code Hooks: How to Bypass Model Self‑Awareness and Enforce Deterministic Actions
Claude Code hooks are deterministic scripts that run at specific events—such as PreToolUse, PostToolUse, SessionStart, and UserPromptSubmit—to enforce hard constraints, bypass the probabilistic suggestions in CLAUDE.md, and enable interception, feedback, analytics, and automation, with detailed configuration, input/output protocols, and safety considerations.
Claude Code provides three layers of control: CLAUDE.md (suggestions with probabilistic compliance), skill (on‑demand reusable workflows), and Hook (deterministic code that runs automatically at defined events, guaranteeing execution regardless of the model’s willingness).
1. Distinguishing the Three Layers
CLAUDE.md is a textual guideline that the model may follow; it cannot guarantee 100 % compliance. Skills are loaded only when needed and also lack enforcement. Hooks are actual scripts executed by Claude Code at specific moments, providing the only way to achieve absolute guarantees such as “never modify the production database”.
The three layers can be compared to a workplace hierarchy: CLAUDE.md is a wall‑posted policy, skill is an on‑demand manual, and Hook is a physical safety latch that stops the machine from proceeding.
2. Hook Lifecycle – When Hooks Can Be Mounted
Claude Code defines over thirty events; the most commonly used ones are:
SessionStart : triggers at the beginning of a session for initialization.
UserPromptSubmit : fires before a user prompt is sent to the model, allowing pre‑submission checks or context injection.
PreToolUse : occurs before a tool is actually invoked; this is the prime interception point.
PostToolUse : runs after a tool finishes, suitable for formatting or feedback.
Stop : triggers when the model thinks it has finished; can be used to verify task completion.
PreCompact and Notification : other auxiliary events.
Only events that fire before an action (e.g., PreToolUse, UserPromptSubmit, Stop) can block the action; events that fire after (e.g., PostToolUse) can only provide feedback.
3. PreToolUse – Interception Example
PreToolUse receives a JSON payload on stdin containing tool_name and tool_input. The script decides whether to allow the call by either exiting with code 0 (allow) or code 2 (deny) or by outputting a structured JSON with a permissionDecision field set to deny, allow, or ask.
#!/usr/bin/env python3
import json, sys
data = json.load(sys.stdin) # read the call information
cmd = data.get("tool_input", {}).get("command", "")
# Block dangerous production deploys on non‑release branches
if "deploy --prod" in cmd and current_branch() != "release":
print("禁止在非 release 分支部署生产环境", file=sys.stderr)
sys.exit(2) # 2 = deny
sys.exit(0) # 0 = allowThis script denies a production deployment if the current git branch is not release, demonstrating a hard‑constraint that CLAUDE.md could never enforce.
4. PostToolUse – Feedback and Automation
PostToolUse cannot block the tool but can run follow‑up actions such as automatic formatting. A typical configuration looks like:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "python3 .claude/hooks/format_and_check.py" }
]
}
]
}
}The script can also return a JSON with a decision of block and a reason, allowing the model to automatically repair the issue in the next step.
5. Configuration and I/O Protocol
Hooks are configured in settings.json, which can exist at three levels:
User‑wide: ~/.claude/settings.json Project‑wide: .claude/settings.json (tracked in Git)
Local only: .claude/settings.local.json The JSON structure is a three‑level nesting: event name → array of objects containing a matcher and a list of hooks. The matcher can be a plain tool name, a regex, or a pipe‑separated list (e.g., "Edit|Write").
Input to a Hook is a JSON object via stdin with common fields ( session_id, cwd, hook_event_name) and event‑specific fields ( tool_name, tool_input, etc.). Output can be an exit code or a structured JSON. Exit code 0 signals success; code 2 signals a block (stderr is shown to the model); any other non‑zero code is a non‑blocking error. Structured output can include fields such as permissionDecision, additionalContext, continue, and reason.
Matchers support regular expressions, enabling precise targeting (e.g., mcp__memory__.* matches all MCP services). Command‑type hooks can be executed via the shell (allowing pipelines) or as an argument array to avoid injection risks.
6. Execution Characteristics
Multiple hooks on the same event run in parallel, and the most restrictive decision wins (any deny results in a block). Identical hook commands are de‑duplicated across configuration layers. Timeouts are long by default (600 s) but are shortened for high‑frequency events like UserPromptSubmit (30 s), so scripts for those events must be fast.
7. Beyond Interception – Analytics and Automation
Hooks can be used for telemetry: a PostToolUse hook can log each skill invocation, allowing the user to quantify usage (e.g., a skill called 120 times vs. another 45 times in a month). The logged data can be fed back into the model via the additionalContext field.
Hooks also enable automatic context injection. For example, a SessionStart hook can insert the current git branch into the model’s context, and a UserPromptSubmit hook can attach the latest error log, reducing back‑and‑forth clarification.
The Stop event can enforce completion checks: if a batch job produces fewer artifacts than expected, the hook can block the model’s termination and request continuation.
8. Safety Considerations
Because hooks run with full user permissions, they can read environment variables, modify code, or execute arbitrary commands. Therefore:
Never copy unknown settings.json configurations without reviewing each hook.
Treat project‑level hooks as code reviews: audit them before merging.
Enterprise deployments can restrict hooks to centrally managed ones.
The /hooks command lists all active hooks and their sources, helping users audit their environment.
9. Interview Answer Blueprint
When asked about Claude Code hooks in an interview, answer in four steps:
Core distinction (≈20 s): CLAUDE.md is probabilistic advice; Hook is deterministic code that guarantees execution.
Lifecycle (≈30 s): Mention the main events (PreToolUse, PostToolUse, UserPromptSubmit, Stop, SessionStart) and the before/after blocking difference.
Practical usage (≈30 s): Explain PreToolUse interception (exit‑code or permissionDecision) and PostToolUse formatting, plus the three‑layer settings.json configuration.
Judgment & safety (≈20 s): Emphasize selective hook placement for high‑risk actions and the security risk of running arbitrary code.
Follow‑up questions often probe the blocking capability of PreToolUse vs. PostToolUse or the parallel execution model; answer that only pre‑action events can block and that the strictest decision wins.
10. Key Takeaways
Remember the three‑tier model: write preferences in CLAUDE.md, reusable flows as skills, and hard constraints as hooks. Use hooks sparingly for high‑risk or repetitive tasks, and always audit them for security and performance.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Wu Shixiong's Large Model Academy
We continuously share large‑model know‑how, helping you master core skills—LLM, RAG, fine‑tuning, deployment—from zero to job offer, tailored for career‑switchers, autumn recruiters, and those seeking stable large‑model positions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
