
Claude Code Hooks: Hướng Dẫn Tự Động Hóa Agent Cho Power User
Claude Code hooks tự động chạy các lệnh của bạn tại những thời điểm nhất định trong vòng đời tác vụ — xác thực, lint, chặn hoặc ghi log mà không cần bạn túc trực. Tìm hiểu các sự kiện, cách cấu hình, 5 công thức thực chiến, lỗi mã thoát (exit-code) cần lưu ý, và cách chạy Claude Code mà không cần cài đặt gì.
Claude Code hooks là các lệnh do người dùng định nghĩa, chạy tự động tại các điểm cụ thể trong vòng đời của Claude Code — trước khi gọi một tool, sau khi chỉnh sửa, khi một session bắt đầu, khi Claude hoàn thành một lượt phản hồi — để bạn có thể xác thực, định dạng, ghi log, hoặc chặn các hành động mà không cần phải tham gia mỗi lần. Đó chính là sự khác biệt giữa một AI coding agent chỉ gợi ý và một agent tuân theo quy tắc của bạn một cách xác định (deterministic). Bài viết này giải thích hooks là gì, mọi sự kiện mà chúng có thể kích hoạt, cách cấu hình chúng, năm công thức thực tế bạn có thể sao chép, cạm bẫy về exit-code khiến ai cũng vướng phải, và cách sử dụng toàn bộ sức mạnh của Claude Code mà không cần thiết lập cục bộ.
Claude Code Hooks Là Gì?
Một hook là một handler — một lệnh shell, một endpoint HTTP, một lệnh gọi MCP tool, hoặc thậm chí là một prompt cho model — mà Claude Code tự động chạy khi một sự kiện cụ thể xảy ra. Handler nhận đầu vào có cấu trúc (qua stdin đối với command hooks, hoặc dưới dạng POST body đối với HTTP hooks), có thể kiểm tra điều gì đang diễn ra, thực hiện một hành động, và tùy chọn trả về một quyết định làm thay đổi bước tiếp theo mà Claude thực hiện.
Phần cuối đó chính là điều khiến hooks trở nên mạnh mẽ hơn là chỉ tiện lợi. Một hook không chỉ là một thông báo — nó có thể chặn một lệnh gọi tool, viết lại đầu vào hoặc đầu ra của một tool, chèn thêm ngữ cảnh, hoặc dừng hoàn toàn Claude. Nói cách khác, hooks biến Claude Code từ một trợ lý thông minh thành một trợ lý có thể lập trình được, thực thi các rào chắn của nhóm bạn một cách xác định, không chỉ khi model tình cờ nhớ đến chúng.
Khi Hooks Kích Hoạt: Vòng Đời
Hooks gắn vào các sự kiện, và Claude Code cung cấp rất nhiều sự kiện như vậy. Chúng được nhóm theo nhịp độ: một số kích hoạt một lần mỗi session, một số một lần mỗi lượt, và một số ở mỗi lệnh gọi tool.
Nơi hooks kích hoạt trong suốt một session Claude Code — từ SessionStart đến SessionEnd.
Những sự kiện bạn sẽ dùng nhiều nhất:
SessionStart/SessionEnd— một lần khi một session bắt đầu hoặc kết thúc. Rất phù hợp để tải ngữ cảnh (issue đang mở, thông tin branch, các biến môi trường) hoặc dọn dẹp.UserPromptSubmit— kích hoạt khi bạn gửi một prompt, trước khi Claude xử lý nó. Bạn có thể lọc hoặc bổ sung prompt.PreToolUse— trước bất kỳ lệnh gọi tool nào. Đây là nơi bạn chặn các hành động nguy hiểm.PostToolUse(vàPostToolUseFailure) — sau khi một lệnh gọi tool thành công (hoặc thất bại). Nơi dành cho linting, formatting, và xác minh.Stop/StopFailure— khi Claude hoàn thành phản hồi, hoặc lượt phản hồi kết thúc do lỗi.Notification— khi Claude Code phát ra một thông báo (hữu ích cho cảnh báo trên desktop).
Ngoài những sự kiện đó, Claude Code còn kích hoạt hooks cho subagent (SubagentStart/SubagentStop), task (TaskCreated/TaskCompleted), context compaction (PreCompact/PostCompact), thay đổi thư mục làm việc (CwdChanged), thay đổi file trên đĩa (FileChanged), tải instructions (InstructionsLoaded), và nhiều hơn nữa. Sự đa dạng đó chính là điểm mấu chốt: hầu như bất kỳ thời điểm nào trong vòng lặp của agent cũng là nơi bạn có thể gắn chính sách.
Năm Loại Handler Của Hook
Một sự kiện hook có thể kích hoạt năm loại handler khác nhau, đó là điều làm cho hệ thống này linh hoạt:
command— chạy một lệnh shell; đọc đầu vào trên stdin, báo hiệu quyết định qua exit code và stdout.http— POST JSON của sự kiện đến một URL và đọc phản hồi JSON.mcp_tool— gọi một tool trên một MCP server đã kết nối.prompt— một đánh giá model đơn lượt trả về quyết định JSON yes/no (hữu ích cho các kiểm tra mờ/không rõ ràng).agent— sinh ra một subagent (thử nghiệm).
Đối với hầu hết các nhóm, command hooks chiếm 90% công việc — một shell script là đủ để lint, chặn, hoặc ghi log.
Cách Cấu Hình Một Hook
Hooks nằm trong các file settings (tài liệu chính thức official Claude Code hooks documentation là tài liệu tham khảo chuẩn), và vị trí bạn đặt chúng quyết định phạm vi:
| Vị trí | Phạm vi |
|---|---|
~/.claude/settings.json | Tất cả các project của bạn |
.claude/settings.json | Một project (có thể commit — chia sẻ được với nhóm của bạn) |
.claude/settings.local.json | Một project, chỉ cục bộ (bị gitignore) |
| Managed policy settings | Toàn tổ chức (admin) |
Cấu trúc lồng ba cấp: chọn một event, thêm một nhóm matcher, sau đó định nghĩa các handlers. Matchers quyết định hook áp dụng cho lệnh gọi tool nào — "*" (hoặc bỏ qua nó) khớp với mọi thứ, một matcher đơn giản như Edit|Write khớp chính xác với các tool đó, và bất cứ thứ gì phức tạp hơn được coi như một biểu thức chính quy (regular expression). (MCP tools khớp theo mẫu mcp__<server>__<tool>.)
Đây là một PostToolUse hook chạy kiểm tra lint sau mỗi lần chỉnh sửa:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "/path/to/lint-check.sh" }]
}
]
}
}Năm Công Thức Hook Thực Tế
Đây là những mẫu mà các nhóm thường dùng đầu tiên:
- Lint hoặc format sau mỗi lần chỉnh sửa. Một
PostToolUsehook khớp vớiEdit|Writechạy formatter hoặc linter của bạn, để code của agent luôn đáp ứng quy tắc style của bạn. - Chặn các lệnh phá hoại. Một
PreToolUsehook khớp vớiBashkiểm tra lệnh và chặnrm -rfvà những lệnh tương tự trước khi chúng có thể chạy. - Thông báo trên desktop. Một
Notificationhook thông báo cho bạn khi Claude cần sự chú ý hoặc hoàn thành một task dài. - Ghi log kiểm toán (audit logging). Một
PostToolUse(hoặc hook nhắm vào MCP) ghi log mọi lệnh gọi tool để tuân thủ — chạy gì, khi nào, và với đối số nào. - Tải ngữ cảnh project khi khởi động. Một
SessionStarthook kéo vào các issue đang mở, branch hiện tại, hoặc các biến môi trường để agent bắt đầu mỗi session đã có định hướng sẵn.
Năm công thức hook phổ biến và các sự kiện chúng gắn vào.
Cạm Bẫy Exit-Code
Đây là chi tiết khiến ai cũng vướng phải, vì vậy hãy ghi nhớ kỹ: đối với command hooks, chỉ exit code 2 mới chặn. Exit 0 nghĩa là thành công (và stdout được phân tích để tìm quyết định JSON nào đó). Exit 2 là một lỗi chặn (blocking) — stderr của nó được đưa lại cho Claude. Bất kỳ mã nào khác, bao gồm cả exit 1, là một lỗi không chặn (non-blocking) — Claude vẫn tiếp tục.
Vì vậy nếu bạn viết một hook "chặn cái này" và dùng exit 1, nó sẽ không chặn — hành động vẫn tiếp diễn. Để thực sự thực thi một chính sách từ một command hook, hãy dùng exit 2. (Command hooks cũng có thể trả về quyền kiểm soát chi tiết hơn dưới dạng JSON trên stdout — permissionDecision: "deny" cho PreToolUse, updatedInput để viết lại đối số, additionalContext để chèn thông tin, và continue: false để dừng hoàn toàn Claude.)
Một Ví Dụ Thực Tế: Chặn rm -rf
Hãy xây dựng rào chắn chống lệnh phá hoại từ đầu đến cuối, vì nó thể hiện mọi thành phần chuyển động. Đầu tiên, cấu hình — một PreToolUse hook khớp với Bash:
{ "hooks": { "PreToolUse": [{ "matcher": "Bash",
"hooks": [{ "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/guard.sh" }] }] } }Sau đó là script, guard.sh. Claude Code gửi sự kiện dưới dạng JSON trên stdin, bao gồm đầu vào của tool; script đọc nó, kiểm tra lệnh, và quyết định:
#!/usr/bin/env bash
input=$(cat)
cmd=$(echo "$input" | jq -r '.tool_input.command // ""')
if echo "$cmd" | grep -Eq 'rm +-rf|mkfs'; then
echo "Blocked: destructive command refused by policy." >&2
exit 2 # exit 2 blocks — exit 1 would NOT
fi
exit 0Dòng quyết định là exit 2. Trả về 0 và lệnh sẽ chạy; trả về 1 và — thật ngược đời — nó vẫn chạy như một lỗi không chặn; chỉ exit 2 mới chặn và đưa lại thông báo stderr của bạn cho Claude để nó hiểu lý do tại sao. Hãy làm cho script có thể thực thi, commit nó dưới .claude/hooks/, và mọi lệnh gọi Bash giờ đây sẽ đi qua rào chắn của bạn — cho toàn bộ nhóm của bạn, vì settings.json của project có thể chia sẻ được. Để có một sự bảo đảm chắc chắn hơn là chỉ nỗ lực tốt nhất (best-effort), hãy kết hợp nó với các quy tắc quyền (permission rules) của Claude Code; như một lưới an toàn xác định, được kiểm soát phiên bản, hook này đã hoàn thành nhiệm vụ của nó.
Khi Nào Hooks Không Phải Là Câu Trả Lời
Hooks dành cho các chính sách xác định, có thể lặp lại — "luôn lint sau khi chỉnh sửa", "không bao giờ chạy rm -rf". Chúng là công cụ sai cho những việc cần sự phán đoán (hãy dùng model hoặc một prompt hook cho các quyết định mờ) và cho các bảo đảm an ninh chắc chắn (hãy dùng hệ thống quyền, vì các bộ lọc if của command-hook fail open — mặc định cho qua khi lỗi). Cũng đừng lạm dụng hook: mỗi command hook chạy một process có timeout, và một loạt các hook chậm sẽ làm tăng độ trễ cho mỗi lệnh gọi tool. Hãy giữ chúng nhanh, ít, và tập trung vào những quy tắc thực sự quan trọng.
Những Ghi Chú An Toàn Cần Biết
Một vài thực tế mà tài liệu nói rõ:
- Bộ lọc
iffail open. Nếu bạn dùng trườngifđể giới hạn phạm vi của một hook theo một quy tắc quyền và lệnh không thể được phân tích, hook vẫn chạy. Để thực thi allow/deny một cách chắc chắn, hãy dùng hệ thống quyền của Claude Code, không phải hooks. - Hooks chạy mà không có terminal điều khiển — chúng không thể nhắc (prompt) trên
/dev/tty. Hãy dùngsystemMessagehoặc đầu raterminalSequencebị giới hạn cho các thông báo hướng tới người dùng. - Stdout phải sạch. Chỉ có đối tượng quyết định JSON nên xuất hiện trên stdout; đầu ra ngẫu nhiên từ shell profile có thể làm hỏng việc phân tích.
- Xử lý ngữ cảnh được chèn vào một cách cẩn thận.
additionalContextnên được viết dưới dạng các phát biểu thực tế, không phải các lệnh mang tính bắt buộc, để phối hợp tốt với các biện pháp phòng vệ chống prompt-injection.
Hooks Là Harness Engineering Thu Nhỏ
Lùi lại một bước, hooks là một ví dụ cụ thể của một ý tưởng lớn hơn: model không phải là toàn bộ agent — hệ thống xung quanh nó mới là điều quan trọng. Hooks là một phần của harness làm cho một coding agent trở nên đáng tin cậy, nằm cạnh loop, tools, memory, và sandbox. (Chúng tôi đi sâu vào mô hình tư duy đó trong bài harness engineering.) Khi bạn viết một block PreToolUse hay một linter PostToolUse, bạn đang thực hiện harness engineering — định hình hành vi của agent một cách xác định thay vì hy vọng model hành xử đúng.
Cách nhìn nhận đó cũng cho bạn biết khi nào hooks đáng để đầu tư công sức: bất kỳ quy tắc nào mà bạn phải nhắc agent mỗi lần đều là ứng viên cho một hook.
Sử Dụng Toàn Bộ Sức Mạnh Của Claude Code Mà Không Cần Thiết Lập Cục Bộ
Hooks nằm trong Claude Code CLI, nghĩa là bạn cần cài đặt và cấu hình nó để sử dụng chúng — một rào cản đối với bất kỳ ai không quen thao tác trong terminal, và không thể thực hiện được đối với các đồng nghiệp không phải nhà phát triển. Nếu bạn muốn có các khả năng agent của Claude Code mà không cần quản lý một bản cài đặt cục bộ, bạn có thể chạy Claude Code ngay trên trình duyệt của mình trên Happycapy: nó chạy Claude Code trong một sandbox cloud được quản lý, nơi harness — loop, tools, memory, và cách ly mà hooks gắn vào — đã được kết nối sẵn cho bạn. Bạn mô tả một task và theo dõi agent làm việc trên một desktop trực quan, không cần terminal.
Hãy nghĩ theo cách này: hooks cho phép người dùng cao cấp tự tay tinh chỉnh harness của Claude Code; Happycapy mang đến cho mọi người một harness được quản lý sẵn ngay từ đầu. Nếu bạn đã muốn đưa Claude Code vào công việc nhưng việc thiết lập CLI đã cản bạn lại, hãy bắt đầu miễn phí tại happycapy.ai và chạy một task thực sự ngay trên trình duyệt của bạn ngay hôm nay.
Các Câu Hỏi Thường Gặp
Hỏi: Claude Code hooks là gì?
Chúng là các handler do người dùng định nghĩa — lệnh shell, endpoint HTTP, lệnh gọi MCP tool, hoặc prompt cho model — mà Claude Code tự động chạy tại các sự kiện trong vòng đời như trước khi gọi một tool (PreToolUse), sau khi chỉnh sửa (PostToolUse), hoặc khi session bắt đầu. Chúng có thể xác thực, định dạng, ghi log, chặn, hoặc viết lại các hành động.
Hỏi: Claude Code hỗ trợ những sự kiện hook nào?
Rất nhiều — bao gồm SessionStart/SessionEnd, UserPromptSubmit, PreToolUse, PostToolUse (và PostToolUseFailure), Stop/StopFailure, Notification, các sự kiện subagent và task, và các sự kiện compaction. Chúng kích hoạt một lần mỗi session, một lần mỗi lượt, hoặc ở mỗi lệnh gọi tool.
Hỏi: Làm sao để một hook chặn một lệnh gọi tool?
Đối với command hooks, hãy exit với mã 2 — chỉ exit 2 mới chặn (exit 1 thì không). Đối với PreToolUse, bạn cũng có thể trả về JSON với permissionDecision: "deny". Để thực thi chắc chắn, hãy ưu tiên hệ thống quyền của Claude Code, vì bộ lọc if của hook fail open.
Hỏi: Tôi cấu hình Claude Code hooks ở đâu?
Trong các file settings: ~/.claude/settings.json (tất cả project), .claude/settings.json (một project, có thể chia sẻ), hoặc .claude/settings.local.json (chỉ cục bộ). Bạn chọn một sự kiện, thêm một matcher, và định nghĩa các handler.
Hỏi: Tôi có thể dùng Claude Code hooks mà không cần cài CLI không?
Hooks bản thân chúng yêu cầu Claude Code CLI. Nếu mục tiêu của bạn là sử dụng Claude Code mà không cần thiết lập cục bộ, hãy chạy nó trong một sandbox trình duyệt được quản lý như Happycapy, cung cấp sẵn agent và harness của nó — lý tưởng khi bạn không muốn tự cài đặt và cấu hình CLI.
Hỏi: Hook đầu tiên nào nên thêm vào là tốt?
Một linter PostToolUse khớp với Edit|Write — nó chạy formatter của bạn sau mỗi lần thay đổi code, để đầu ra của agent luôn đáp ứng quy tắc style của bạn. Nó ít rủi ro và có ích ngay lập tức.
Các hướng dẫn liên quan
- How Claude Code Review Actually Works: Diffs, Hooks, and What the Agent Catches
- Build Autonomous Agents with the Claude Code SDK: A Practical Developer's Guide
- Claude Code Web: How to Run Claude Code in Your Browser (No Install)
- Claude Code vs GitHub Copilot: Autonomous Agent or In-Editor Assistant?

