Các bài trong khoáBài 21/25

25 bài

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ệnKhi nàoChặn được?
PreToolUseTrước khi một tool chạyCó: thoát mã 2, hoặc trả permissionDecision: "deny"
PermissionRequestKhi tool cần quyết định cấp quyềnCó, qua object decision (mã 2 không có tác dụng ở đây)
UserPromptSubmitKhi một prompt được gửiCó: prompt không tới Claude
Stop, SubagentStopKhi Claude hay subagent định dừngCó: buộc làm tiếp
PostToolUseSau khi tool chạy thành côngKhô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áoDù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:

  • matcher lọ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 server db). Tên tool phân biệt chữ hoa chữ thường.
  • if lọ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:

typeLàm gì
commandChạy lệnh shell, nhận JSON qua stdin, trả kết quả bằng mã thoát và stdout
httpGửi JSON tới một URL bằng POST, đọc kết quả từ body
mcp_toolGọi một tool trên MCP server đã cấu hình
promptHỏi một model Claude một lượt, nhận quyết định dạng JSON
agentChạ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 đặtPhạm vi
~/.claude/settings.jsonMọi dự án của bạn
.claude/settings.jsonMột dự án, commit chung cho cả đội
.claude/settings.local.jsonMột dự án, riêng bạn
Managed settingsCả tổ chức, do quản trị viên kiểm soát
Plugin, skill, subagentKhi 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).

Nguồn

  1. Exam Guide CCDV-F v1.0, Domain 7(mở tab mới)
  2. Hooks reference (Claude Code Docs)(mở tab mới)
  3. Get started with hooks (Claude Code Docs)(mở tab mới)
  4. Intercept and control agent behavior with hooks (Claude Code Docs)(mở tab mới)
  5. Best practices for Claude Code (Claude Code Docs)(mở tab mới)

Nắm rồi thì thử sức với đề

Xem khoá luyện thi
Hook của Claude - chặn hành động phá huỷ một cách tất định · Anthropic Exam Pro