Domain 7: Security and Safety·Task 7.3
Hook của Claude - chặn hành động phá huỷ một cách tất định
Hook làm guardrail tất định - sự kiện nào chặn được hành động, nhắm hook bằng matcher và if, các loại handler, đặt cấu hình ở đâu, chỉ gắn cho việc rủi ro.
- 7 phút đọc
- Đối chiếu docs 02/11/2026
- 5 nguồn
Đọc xong bạn nắm được
- Biết hook chạy ở những thời điểm nào, và sự kiện nào chặn được hành động, sự kiện nào chỉ quan sát
- Nhắm hook đúng tool và đúng lệnh bằng matcher và điều kiện if
- Chọn loại handler và nơi đặt cấu hình cho một hook guardrail
- Chỉ gắn hook cho hành động rủi ro cao để giữ an toàn mà không làm chậm agent
"Cẩn thận với database" trong system prompt không ngăn được một câu DROP TABLE. Model làm theo phần lớn thời gian, nhưng "phần lớn" không đủ với hành động không lấy lại được. Hook là cách đặt một lớp kiểm bằng code chạy mọi lần, nằm ngoài model.
Bài này giúp bạn trả lời: hook chạy lúc nào, chặn được gì, nhắm vào đâu, và đặt cấu hình ở chỗ nào?
Ví dụ xuyên suốt: agent bảo trì của phần mềm quản lý trường mầm non
Một công ty làm phần mềm quản lý cho khoảng 300 trường mầm non (điểm danh, học phí, sổ liên lạc). Đội vận hành dùng Claude Code làm agent bảo trì: đọc log, chạy truy vấn kiểm tra trên database qua psql, sửa script cấu hình.
Tháng trước agent chạy một câu DELETE thiếu điều kiện WHERE trên bảng điểm danh của production. Đội phản ứng bằng cách gắn hook kiểm tra cho mọi hành động, và agent chậm hẳn: mỗi lần đọc file cũng phải chờ hook chạy xong.
Hook chạy ở đâu trong vòng lặp
Hook là lệnh, endpoint hay prompt của bạn, được Claude Code chạy ở những thời điểm cố định. Docs best practices nói: thứ gì phải xảy ra mọi lần thì đưa vào hook, luật deny hay managed setting, vì CLAUDE.md chỉ là hướng dẫn và Claude có thể quyết định nó không áp dụng.
Sự kiện nào chặn được hành động là điểm đề thi hay hỏi:
| Sự kiện | Khi nào | Chặn được? |
|---|---|---|
PreToolUse | Trước khi một tool chạy | Có: thoát mã 2, hoặc trả permissionDecision: "deny" |
PermissionRequest | Khi tool cần quyết định cấp quyền | Có, qua object decision (mã 2 không có tác dụng ở đây) |
UserPromptSubmit | Khi một prompt được gửi | Có: prompt không tới Claude |
Stop, SubagentStop | Khi Claude hay subagent định dừng | Có: buộc làm tiếp |
PostToolUse | Sau khi tool chạy thành công | Không: tool đã chạy rồi, chỉ báo lại cho Claude |
SessionStart, PreCompact, Notification | Đầu phiên, trước khi nén, khi có thông báo | Dùng để nạp ngữ cảnh, lưu lại, gửi cảnh báo |
Muốn ngăn một câu lệnh phá huỷ thì phải dùng PreToolUse. PostToolUse hợp với việc ghi nhật ký hay chạy formatter sau khi sửa file, không cứu được dữ liệu đã xoá.
Mã thoát của hook command: 0 là thành công (đọc JSON in ra nếu có), 2 là lỗi chặn (stderr là lý do, gửi cho Claude), mã khác là lỗi không chặn: hành động vẫn chạy, trừ khi hook được cấu hình để lỗi của nó cũng chặn (onFailure: "block"). Vì vậy một hook guardrail viết sai, thoát mã 1, mặc định sẽ không chặn gì cả.
Nhắm đúng chỗ: matcher và if
Gắn hook cho mọi hành động là lý do agent trong ví dụ chậm đi. Docs cho hai tầng lọc:
matcherlọc theo tên tool. Chỉ có chữ, số,_,-,|,,thì so khớp chính xác (Bash,Edit|Write); có ký tự khác thì là biểu thức chính quy (mcp__db__.*khớp mọi tool của MCP serverdb). Tên tool phân biệt chữ hoa chữ thường.iflọc sâu hơn theo cú pháp luật quyền, ví dụ"Bash(psql *)": hook chỉ được khởi chạy khi lệnh khớp, đỡ tốn công chạy script cho mọi lệnh Bash.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "if": "Bash(psql *)", "command": "./.claude/hooks/kiem-sql.sh" }
]
}
]
}
}Script kiem-sql.sh đọc JSON đầu vào từ stdin, lấy câu lệnh, và thoát mã 2 kèm lý do nếu gặp DROP, TRUNCATE hay DELETE không có WHERE. Với thay đổi hợp lệ nhưng nhạy cảm, hook có thể trả quyết định "ask" để buộc người duyệt thay vì chặn hẳn.
Loại handler và nơi đặt cấu hình
Docs liệt kê năm loại handler:
type | Làm gì |
|---|---|
command | Chạy lệnh shell, nhận JSON qua stdin, trả kết quả bằng mã thoát và stdout |
http | Gửi JSON tới một URL bằng POST, đọc kết quả từ body |
mcp_tool | Gọi một tool trên MCP server đã cấu hình |
prompt | Hỏi một model Claude một lượt, nhận quyết định dạng JSON |
agent | Chạy một subagent dùng tool (Read, Grep…) để kiểm điều kiện; còn thử nghiệm |
Với guardrail chặn hành động phá huỷ, command là lựa chọn tất định nhất: cùng đầu vào luôn cùng kết quả. prompt và agent dùng model để phán đoán, hợp với điều kiện khó viết thành luật, nhưng không còn tất định.
Nơi đặt quyết định phạm vi:
| Nơi đặt | Phạm vi |
|---|---|
~/.claude/settings.json | Mọi dự án của bạn |
.claude/settings.json | Một dự án, commit chung cho cả đội |
.claude/settings.local.json | Một dự án, riêng bạn |
| Managed settings | Cả tổ chức, do quản trị viên kiểm soát |
| Plugin, skill, subagent | Khi plugin bật, sau khi skill được gọi, trong lúc subagent chạy |
Hook ở các tầng cộng dồn chứ không thay nhau: hook của user hay project không gỡ được hook managed. Quản trị viên có thể bật allowManagedHooksOnly để chỉ hook managed được chạy. Hook trong settings và managed cũng chạy khi subagent gọi tool. Trong ví dụ, hook kiem-sql.sh đặt ở .claude/settings.json và commit để mọi người trong đội vận hành đều có.
Nếu bạn dựng agent bằng Agent SDK thay vì Claude Code, hook là các hàm callback truyền vào tuỳ chọn hooks, cùng tên sự kiện và cùng ý tưởng (bài 1.2).
Anthropic Exam Pro