TL;DR — Claude Code có 4 loại hook handler (command, prompt, agent, http) và 21 lifecycle events. Hầu hết developer chỉ dùng command hook trên PreToolUse. Bài này giúp bạn chọn đúng loại cho đúng event, và cho biết 3 hook nào nên implement trước. Nhảy đến decision tree →
📊 Bài này cho bạn:
- Decision tree để chọn CLAUDE.md vs hook vs cả hai
- Danh sách 7 events ưu tiên, xếp theo thứ tự implement
- Bảng so sánh handler types (speed, reliability, codebase access)
- Exit code cheat sheet và cách debug hook
Hai config. Cùng mục tiêu: chặn force push lên main. Độ tin cậy khác nhau hoàn toàn:
# Command hook (deterministic, <5ms)COMMAND=$(jq -r '.tool_input.command // empty' < /dev/stdin)if echo "$COMMAND" | grep -qE 'git push.*(--force|-f).*main'; then echo "BLOCKED: force push to main" >&2 exit 2fi{ "type": "prompt", "prompt": "Block this if it looks like a force push to a production branch"}Command hook là 5 dòng bash. Chạy dưới 5ms. Bắt mọi git push --force main không trượt phát nào.
Prompt hook gọi LLM. Mất 300-2000ms. Có thể quyết định --force-with-lease là “đủ an toàn” rồi cho qua.
Cả hai đều là “hooks.” Nhưng chọn sai loại, guardrail của bạn biến thành lời khuyên. CLAUDE.md instructions đạt 70-90% compliance (Dotzlaw Consulting, 2026). Hooks đạt 100%, nhưng chỉ khi bạn chọn đúng loại.
Đây là framework tôi ước mình có từ sáu tháng trước khi bắt đầu viết hooks. Nếu bạn chưa biết hooks là gì, đọc Claude Code Hooks guide trước. Để hiểu bức tranh lớn, đọc Harness Engineering: Hệ Thống Quanh AI Quan Trọng Hơn AI.
4 loại hook handler trong Claude Code là gì?
Claude Code hooks có 4 loại: command (shell scripts), prompt (LLM judgment), agent (multi-turn verification có quyền truy cập codebase), và http (webhooks đến external services). Mỗi loại đánh đổi tốc độ lấy trí thông minh theo cách khác nhau. Chọn sai loại, guardrail 100% của bạn tụt xuống thành “có thể block, có thể không” (Dotzlaw Consulting, 2026).
| Handler | Tốc độ | Deterministic? | Truy cập codebase? | Dùng cho |
|---|---|---|---|---|
| command | <5ms | Có | Không (stdin only) | Guardrails, formatting, logging |
| prompt | 300-2000ms | Không | Không | Quyết định tinh tế trên Stop |
| agent | 2-10s | Không | Có (full tools) | Verification sâu, kiểm tra architecture |
| http | 50-500ms | Có (server bạn) | Không | Team policies, audit tập trung |
Command hooks là shell scripts. Đọc JSON từ stdin, chạy nhanh, trả kết quả deterministic. Dùng cho mọi thứ bạn có thể diễn đạt bằng string match, path check, hoặc regex.
Prompt hooks gọi LLM để đưa ra judgment. Chậm hơn và non-deterministic. Chỉ dùng khi quyết định thực sự cần reasoning, ví dụ đánh giá output của subagent có đạt tiêu chuẩn không trên SubagentStop.
Agent hooks là option nặng nhất. Spawn một Claude Code session đầy đủ, có thể đọc files, search code, chạy tools. Chỉ dành cho verification tasks cần context từ codebase, như kiểm tra refactor không phá vỡ module boundary trước Stop.
HTTP hooks POST đến server của bạn. Phù hợp cho team policies tập trung và audit logging. Chạy async mặc định, không block agent.
Quy tắc quan trọng nhất: không bao giờ dùng prompt hooks cho safety boundaries. Prompt hooks phụ thuộc vào LLM judgment, và LLM có thể sai. Safety boundaries cần command hooks deterministic.
Key insight: 4 loại hook handler của Claude Code đánh đổi tốc độ lấy trí thông minh. Command hooks chạy <5ms với 100% deterministic enforcement. Prompt hooks thêm LLM judgment ở 300-2000ms nhưng đưa vào non-determinism. Quy tắc then chốt: không bao giờ dùng prompt hooks cho safety boundaries (Dotzlaw Consulting, 2026).
Khi nào dùng CLAUDE.md, khi nào dùng hook, khi nào dùng cả hai?
CLAUDE.md dành cho conventions mà agent nên follow: naming, style, architecture preferences. Hooks dành cho rules mà agent không bao giờ được phá: không force push, không edit secrets, luôn format on save. Dùng cả hai khi bạn muốn agent hiểu TẠI SAO rule tồn tại, đồng thời hook enforce CÁI GÌ phải xảy ra. Context files đơn thuần chỉ cải thiện tối đa ~4% (nghiên cứu ETH Zurich, phân tích đầy đủ trong bài pillar).
Decision tree:
Đây có phải HARD constraint (KHÔNG BAO GIỜ được vi phạm)?├── CÓ → Test được bằng string/path/regex không?│ ├── CÓ → Command hook (PreToolUse)│ └── KHÔNG → Cần truy cập codebase không?│ ├── CÓ → Agent hook│ └── KHÔNG → Prompt hook hoặc HTTP hook└── KHÔNG → Đây là preference hay convention? ├── CÓ → CLAUDE.md (~70-90% compliance) └── KHÔNG → Đây là workflow lặp lại? ├── CÓ → Skill hoặc .claude/commands/ └── KHÔNG → Có lẽ bạn không cần nóRanh giới then chốt: CLAUDE.md là lời khuyên. Hook là enforcement. HumanLayer giữ CLAUDE.md của họ dưới 60 dòng vì lý do này. Ít instructions hơn, nhiều hooks hơn. CLAUDE.md càng ngắn, agent càng dễ follow từng instruction. Càng dài, từng rule càng bị pha loãng trong 200K tokens context.
Khi nào dùng cả hai? Khi constraint mang tính structural (hook enforce), nhưng agent cũng cần hiểu reasoning đằng sau. Ví dụ:
- Hook: PreToolUse block
git push --forcelên main - CLAUDE.md: “Dùng
--force-with-leasethay vì--forcevì tháng 3/2026 force push đã ghi đè commits của teammate”
Hook ngăn hành động sai. CLAUDE.md giúp agent chọn đúng hành động thay thế.
Để viết CLAUDE.md hiệu quả hơn, đọc Why CLAUDE.md Is the Most Important File in Your Project.
Key insight: CLAUDE.md đạt ~70-90% compliance vì nó cạnh tranh với 200K tokens context để giành sự chú ý của model. PreToolUse command hook đạt 100% compliance vì nó chạy ngoài chuỗi reasoning của LLM. Dùng CLAUDE.md để giải thích TẠI SAO. Dùng hooks để enforce CÁI GÌ (Dotzlaw Consulting, 2026).
Nên implement hook events nào trước?
Bắt đầu với 3 events theo thứ tự: (1) PreToolUse cho security guardrails, (2) PostToolUse cho auto-formatting và logging, (3) Stop cho completion verification. Theo kinh nghiệm của tôi, ba event này cover phần lớn use cases production. Thêm SessionStart và SubagentStop chỉ khi bạn cần environment setup hoặc multi-agent quality gates.
| Ưu tiên | Event | Handler | Chức năng | Setup |
|---|---|---|---|---|
| 1 | PreToolUse | command | Block hành động nguy hiểm | 15 phút |
| 2 | PostToolUse | command | Auto-format, log actions | 20 phút |
| 3 | Stop | agent | Verify trước khi xong | 30 phút |
| 4 | SessionStart | command | Load env vars, context | 10 phút |
| 5 | SubagentStop | prompt | Validate subagent output | 20 phút |
| 6 | PermissionRequest | command | Auto-approve patterns an toàn | 15 phút |
| 7 | PreCompact | command | Giữ context khi compact | 15 phút |
Danh sách đầy đủ 21 events xem tại official hooks reference.
Hook đầu tiên của bạn: PreToolUse command hook chặn force push lên protected branches. Copy-paste ready:
#!/bin/bash# Block git push --force và -f lên main/master/production
COMMAND=$(jq -r '.tool_input.command // empty' < /dev/stdin)
if echo "$COMMAND" | grep -qE 'git push.*(--force|-f)' && \ echo "$COMMAND" | grep -qE '(main|master|production)'; then echo "BLOCKED: force push to protected branch" >&2 exit 2fi
exit 0Register trong .claude/settings.json:
{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "bash .claude/hooks/block-force-push.sh" } ] } ] }}Với team cần SOC2 hoặc compliance, ưu tiên 1 và 2 (PreToolUse + PostToolUse) tạo audit trail mà team compliance cần. Mọi action được log, hành động nguy hiểm bị block trước khi execute.
Thêm PreToolUse security patterns: Stop npm Supply Chain Attacks with Claude Code Hooks.
Key insight: Verification feedback loops là yếu tố Boris Cherny coi là quan trọng nhất cho chất lượng agent (ngữ cảnh đầy đủ trong bài pillar). PostToolUse hooks và Stop hooks chính là feedback loop đó, built-in trong agent lifecycle. Chúng chạy tự động, không phụ thuộc vào quyết định của model.
Nhiều hooks trên cùng event thì chạy thế nào?
Hooks trên cùng event chạy theo thứ tự bạn define. Với PreToolUse, quyết định nghiêm ngặt nhất thắng: deny thắng defer, defer thắng ask, ask thắng allow. Nếu bất kỳ hook nào deny, action bị block bất kể hooks khác trả về gì. Xếp hooks từ nhanh đến chậm để giảm latency cho allowed actions (Claude Code docs).
3-hook PreToolUse chain trong thực tế:
{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "bash .claude/hooks/block-force-push.sh" }, { "type": "command", "command": "bash .claude/hooks/validate-paths.sh" }, { "type": "command", "command": "bash .claude/hooks/log-action.sh" } ] } ] }}Đặt security blocks trước (nhanh nhất, quan trọng nhất), validation sau, logging cuối. Nếu hook 1 deny, hooks 2 và 3 vẫn chạy nhưng quyết định của chúng không override được deny.
Thứ tự ưu tiên quyết định:
deny → Action bị block. Feedback gửi về model.defer → Action tạm dừng (headless mode). External UI resume.ask → User được hỏi xác nhận.allow → Action tiến hành. Bỏ qua built-in permission check.(none) → Default behavior. Built-in permission check chạy.Cẩn thận với slow hooks. Command hook gọi external API sẽ block toàn bộ agent loop cho đến khi trả về hoặc timeout. Nếu cần external validation, dùng http handler type. HTTP hooks chạy async, không làm treo session.
Chi tiết event system: Claude Code Has 17 Hook Events Now.
Key insight: Claude Code hooks dùng decision precedence nghiêm ngặt trên cùng event: deny > defer > ask > allow. Nếu bất kỳ hook nào trong chain return deny, action bị block bất kể hooks khác quyết định gì. Điều này có nghĩa bạn có thể thêm logging hooks sau security hooks mà không làm yếu enforcement (Claude Code docs).
Nhận tips Claude Code hàng tuần — Mỗi tuần một tip thực tế. Không spam, không rác. Đăng ký AI Developer Weekly →
Những lỗi hook phổ biến nhất (và cách debug)?
Ba lỗi chiếm phần lớn reports “hook không work,” bao gồm GitHub issue #6305: (1) sai exit code, trong đó exit 1 là silent error còn exit 2 mới là block; (2) typo đường dẫn hook, hook im lặng không chạy; (3) quên đọc stdin, hook không nhận được context nào về tool call.
Exit code cheat sheet
| Exit Code | Ý nghĩa | Model thấy feedback? |
|---|---|---|
| 0 | Thành công (parse JSON từ stdout) | Có, nếu có JSON |
| 2 | Block action (stderr thành feedback) | Có |
| Khác | Silent error (chỉ log ở verbose) | Không |
Exit 1 vs exit 2 là cái bẫy số 1. Exit 1 nghĩa là “hook bị crash.” Claude Code log lại rồi tiếp tục. Exit 2 nghĩa là “tôi cố ý block action này.” Claude Code dừng tool call và gửi stderr message về cho model.
Cách debug
Test bất kỳ hook nào bằng cách pipe JSON vào:
echo '{"tool_name":"Bash","tool_input":{"command":"git push --force main"}}' \ | bash .claude/hooks/block-force-push.shecho "Exit code: $?"Nếu hook không chạy, check danh sách này:
- Đường dẫn đúng chưa? Command path relative từ project root, không phải từ hooks directory
- Matcher đúng chưa?
"matcher": "Bash"match tool name, không phải command content - Settings level? Project (
.claude/settings.json) override user (~/.claude/settings.json) - File executable chưa? Chạy
chmod +x .claude/hooks/your-hook.sh - JSON hợp lệ chưa? Syntax error trong settings.json im lặng disable tất cả hooks
Câu chuyện thực tế về hook bị config sai dẫn đến file bị xóa: I Set Up 3 Layers of Defense in Claude Code. It Deleted My File Anyway.
Key insight: 81% AI agents đang hoạt động, nhưng chỉ 14.4% có full security approval (Authority Partners, 2026). Khoảng cách giữa “chúng tôi có guardrails” và “guardrails thực sự hoạt động” thường nằm ở exit codes, typo đường dẫn, và configurations chưa được test.
Thử ngay:
- Copy force-push blocker script vào
.claude/hooks/block-force-push.sh- Register trong
.claude/settings.jsonbằng JSON config ở trên- Cấp quyền execute:
chmod +x .claude/hooks/block-force-push.sh- Test:
echo '{"tool_name":"Bash","tool_input":{"command":"git push --force main"}}' | bash .claude/hooks/block-force-push.sh- Verify exit code 2 (blocked). Bạn có ngay một guardrail production-ready.
Hooks là Layer 4 trong production harness. Blueprint đầy đủ 5 layers: 5 Layers of a Production-Ready Claude Code Harness.
FAQ
4 loại hook handler trong Claude Code là gì?
Command (shell scripts, <5ms, deterministic), prompt (LLM judgment, 300-2000ms), agent (multi-turn verification với codebase access, 2-10s), và http (webhooks, 50-500ms). Dùng command hooks cho guardrails và formatting. Dùng prompt hoặc agent hooks cho quyết định tinh tế cần reasoning. Dùng http hooks cho team policies tập trung.
Nên dùng CLAUDE.md hay hook cho security rules?
Hooks. CLAUDE.md instructions đạt 70-90% compliance vì phải cạnh tranh với 200K tokens context để giành sự chú ý của model. PreToolUse command hook đạt 100% compliance vì chạy ngoài reasoning chain của LLM. Dùng CLAUDE.md giải thích TẠI SAO rule tồn tại. Dùng hooks enforce CÁI GÌ phải xảy ra.
PreToolUse và PostToolUse hooks khác nhau thế nào?
PreToolUse chạy TRƯỚC tool execute và có thể block (exit code 2) hoặc modify input. PostToolUse chạy SAU execution, không thể undo action, nhưng có thể auto-format code, log những gì đã xảy ra, hoặc inject feedback mà Claude thấy ở turn tiếp theo. PreToolUse cho prevention, PostToolUse cho reaction.
Claude Code hooks có chạy trong headless mode không?
Có. Tất cả hook types hoạt động trong headless mode (claude -p). PreToolUse hooks có thể return permissionDecision: "defer" để tạm dừng execution cho external UI collection, sau đó resume bằng claude -p --resume <session-id>. Hooks hoàn toàn tương thích với CI/CD pipelines và SDK-based workflows.
Build harness, không chỉ prompts. Hooks chỉ là một layer. Hệ thống đầy đủ gồm memory, tools, permissions, và observability. Bắt đầu Claude Code Mastery course để học cả năm layers.
Đọc tiếp
- 5 Layers of a Production-Ready Claude Code Harness — Hooks là Layer 4. Bài này cover blueprint đầy đủ cho cả 5 layers, kèm file templates và setup checklist.
- Harness Engineering: Hệ Thống Quanh AI Quan Trọng Hơn AI — Bài pillar giải thích tại sao hệ thống quanh AI agent quan trọng hơn bản thân model.
- AGENTS.md Is a Failure Log, Not an Instruction File — Phương pháp failure-first để viết CLAUDE.md, trong đó mỗi dòng tương ứng với một lỗi agent thực tế bạn đã ngăn chặn.