Khi làm việc cùng các trợ lý lập trình AI trong Terminal, việc phải lặp đi lặp lại lời nhắc "Hãy format lại file vừa sửa" hoặc "Nhớ chạy lại bộ test kiểm tra lỗi" sau mỗi lần chỉnh sửa thường gây mất thời gian và đôi khi bị AI bỏ sót. Để giải quyết triệt để vấn đề này, Anthropic đã trang bị tính năng Claude Code Hooks — cơ chế tự động thực thi các câu lệnh hoặc kịch bản (script) mỗi khi một sự kiện nhất định diễn ra trong vòng đời làm việc của tác tử.
Trong bài viết chuyên sâu dưới đây, iTee Pro sẽ hướng dẫn bạn chi tiết cách cấu hình Claude Code Hooks từ con số 0 thông qua một dự án thực hành thực tế: tự động định dạng (format) file cấu hình, kích hoạt 5 bài kiểm thử tự động sau mỗi lần Claude sửa code, cố ý tạo lỗi logic để kiểm chứng khả năng bắt lỗi của Hook và khắc phục lại mã nguồn chuẩn xác.
1. Claude Code Hooks là gì và cơ chế hoạt động ra sao?
Claude Code Hooks là cơ chế kết nối một Sự kiện (Event) trong quá trình hoạt động của Claude Code với một Hành động (Action) được định nghĩa sẵn (thường là một lệnh CLI hoặc script cục bộ). Điểm khác biệt lớn nhất giữa Hooks và lời nhắc trong Prompt (hay tệp CLAUDE.md) là tính tất định (deterministic): Hook được hệ thống kích hoạt bắt buộc 100% khi sự kiện khớp điều kiện, không phụ thuộc vào việc mô hình ngôn ngữ lớn (LLM) có "nhớ" làm theo lời dặn hay không.
Hai sự kiện phổ biến nhất khi kiểm soát thao tác chỉnh sửa tệp tin của Claude Code bao gồm:
- PreToolUse: Kích hoạt trước khi công cụ được thực thi. Thường dùng để kiểm tra điều kiện an toàn, chặn chỉnh sửa vào các thư mục nhạy cảm hoặc yêu cầu phê duyệt.
- PostToolUse: Kích hoạt ngay sau khi một công cụ (như
EdithoặcWrite) vừa thực hiện thành công. Đây là thời điểm lý tưởng để chạy trình định dạng mã nguồn (Formatter), trình kiểm tra cú pháp (Linter) hoặc bộ kiểm thử đơn vị (Unit Test).
Trong bài thực hành này, chúng ta sẽ sử dụng sự kiện PostToolUse theo dõi hai công cụ Edit và Write trên một bài toán kinh điển: Xây dựng bộ tính phí vận chuyển (Shipping Fee Calculator) với quy tắc đơn hàng dưới 50 USD tính phí ship 5 USD, và từ 50 USD trở lên được miễn phí vận chuyển (0 USD). Chỉ cần sai lệch một dấu so sánh giữa >= và >, code vẫn chạy trơn tru nhưng nghiệm thu nghiệp vụ tại mốc 50 USD sẽ sai hoàn toàn — một kịch bản hoàn hảo để kiểm chứng sức mạnh của Claude Code Hooks.
2. Phân biệt Hooks với Permissions, Skills và Mods trong Claude Code
Hệ sinh thái Claude Code cung cấp nhiều công cụ tùy biến khác nhau. Để tránh nhầm lẫn khi thiết kế quy trình làm việc (Workflow lập trình), bạn có thể đối chiếu qua bảng so sánh dưới đây:
| Mục tiêu của lập trình viên | Tính năng nên sử dụng | Đặc điểm vận hành |
|---|---|---|
| Chạy tự động một bước kiểm tra cố định (Format, Lint, Test) ngay sau khi gọi công cụ | Hooks (trong settings.json) |
Thực thi tất định bằng lệnh hệ thống mỗi khi sự kiện công cụ khớp matcher. |
| Kiểm soát quyền hạn Claude được phép dùng công cụ nào hoặc truy cập đường dẫn nào | Permissions (Quy tắc phân quyền) | Chặn hoặc cho phép truy cập tài nguyên ở cấp độ bảo mật hệ thống. |
| Lưu trữ hướng dẫn, quy chuẩn kiến trúc cho một tác vụ chuyên môn lặp đi lặp lại | Agent Skills (Kỹ năng AI) | Nạp ngữ cảnh và quy trình làm việc cho mô hình AI khi tác vụ phù hợp. |
| Tùy biến hộp thoại phê duyệt, bảng điều khiển hoặc hành vi giao diện tương tác | Mods | Can thiệp vào luồng phê duyệt tương tác trước hoặc trong khi thao tác. |
3. Chuẩn bị môi trường và nguyên tắc an toàn trước khi thực hành
Bài hướng dẫn này sử dụng trình chạy kiểm thử tích hợp sẵn của Node.js (node:test), giúp bạn thực hành ngay lập tức mà không cần cài đặt thêm bất kỳ thư viện bên thứ ba nào:
- Claude Code CLI: Đã cài đặt và đăng nhập tài khoản trong Terminal.
- Node.js: Phiên bản
22.17.0trở lên (hỗ trợ đầy đủ sự kiệntest:summarycó cấu trúc trongnode:test). - Trình soạn thảo mã nguồn: VS Code, Cursor hoặc bất kỳ Code Editor nào bạn quen dùng.
Trước khi bắt đầu, hãy mở Terminal và kiểm tra nhanh phiên bản công cụ trên máy:
claude --version
node --version
Lưu ý an toàn quan trọng:
- Hãy khởi tạo một thư mục thực hành trống hoàn toàn, tách biệt với các dự án thực tế của khách hàng hoặc công ty.
- Các script Hook dạng
commandchạy trực tiếp với quyền tài khoản người dùng trên máy tính của bạn. Vì vậy, hãy luôn đọc kỹ mã nguồn của file Hook và file Test trước khi kích hoạt hoặc cấp quyền Workspace Trust.
4. Hướng dẫn 7 bước cấu hình Claude Code Hooks tự động Format và chạy Test
Bước 1: Khởi tạo dự án mẫu với bộ 5 bài kiểm thử tiêu chuẩn
Đầu tiên, bạn hãy tạo một thư mục mới tên là claude-hooks-practice, di chuyển vào thư mục đó và khởi chạy Claude Code:
mkdir claude-hooks-practice
cd claude-hooks-practice
claude
Tiếp theo, hãy sao chép toàn bộ nội dung Prompt dưới đây và gửi cho Claude Code để AI tự động khởi tạo 3 file nền tảng cho dự án:
Tạo một dự án thực hành nhỏ trong thư mục trống này. Dùng Node.js và trình chạy test có sẵn. Không cài gói nào và không kết nối dịch vụ nào.
1. Tạo file shipping.json với hai giá trị: freeShippingAt là 50 và standardFee là 5 (đơn vị USD).
2. Tạo file shipping.cjs xuất một hàm tên shippingFee đọc các cài đặt đó và trả về 5 cho đơn dưới 50, hoặc 0 cho đơn từ 50 trở lên. Dùng phép so sánh >= cho ngưỡng. Từ chối tổng âm và giá trị không phải số hữu hạn bằng RangeError.
3. Tạo file shipping.test.cjs với đúng 5 bài test có tên:
- (1) cài đặt khớp chính sách vận chuyển đã thống nhất: đúng hai giá trị trên;
- (2) đơn dưới 50 USD phí ship 5 USD: thử đơn 49;
- (3) đơn đúng 50 USD được miễn phí ship: thử đơn 50;
- (4) đơn trên 50 USD được miễn phí ship: thử đơn 75;
- (5) tổng đơn không hợp lệ bị từ chối: thử -1, NaN, Infinity, "50" và null.
Dùng node:test và node:assert/strict. Không bỏ qua test nào. Giữ kết quả kỳ vọng tách biệt với phần cài đặt. Hiển thị các file để tôi xem. Chưa cấu hình hook, chưa đổi quyền, chưa triển khai gì.
Sau khi Claude tạo xong, bạn hãy kiểm tra nội dung file shipping.json:
{
"freeShippingAt": 50,
"standardFee": 5
}
Chạy thử bộ test độc lập trên Terminal để đảm bảo cả 5 bài kiểm thử đều đạt (PASS) trước khi gắn Hook:
node --test shipping.test.cjs
Bước 2: Tạo kịch bản Hook và bật chế độ tự động định dạng (--format-only)
Ở bước này, bạn yêu cầu Claude Code tạo hai kịch bản xử lý cục bộ bên trong thư mục .claude/hooks/ bằng Prompt sau:
Tạo hai file thực hành cục bộ: .claude/hooks/after-edit.cjs và .claude/hooks/run-shipping-tests.cjs. Chỉ dùng thư viện có sẵn của Node.js. Tạo file nhưng chưa bật trong settings.
- Trong after-edit.cjs: đọc sự kiện hook dạng JSON từ stdin. Chỉ xử lý PostToolUse cho hai công cụ Edit và Write. Đọc tool_input.file_path và yêu cầu đường dẫn tuyệt đối. Lấy thư mục chứa hook suy ra gốc dự án. Chỉ xử lý 3 file shipping.json, shipping.cjs, shipping.test.cjs, bỏ qua các đường dẫn khác. Từ chối file thiếu, symlink, hard link và file lớn hơn 64 KB.
- Khi shipping.json thay đổi, phân tích cú pháp và ghi lại cùng giá trị với thụt lề 2 khoảng trắng và dòng mới ở cuối. Nếu JSON lỗi cú pháp, báo lỗi mà không ghi đè nội dung.
- Hỗ trợ cờ --format-only để chỉ định dạng và bỏ qua toàn bộ test. Nếu không có cờ này, sau khi định dạng xong sẽ gọi run-shipping-tests.cjs bằng process.execPath (không qua shell), timeout 10 giây.
- Trong run-shipping-tests.cjs: dùng node:test run() chạy shipping.test.cjs với isolation: 'none' và concurrency: false. Đọc sự kiện test:fail và test:summary để in kết quả JSON có cấu trúc. Yêu cầu đủ 5 bài test đạt.
- Khi thành công, in JSON hợp lệ kèm systemMessage báo kết quả. Khi thất bại, ghi chi tiết lỗi ra stderr và thoát với exit code 2, nêu rõ chỉnh sửa đã được lưu. Hiển thị cả hai file để tôi kiểm duyệt.
Lúc này, cấu trúc thư mục dự án của bạn sẽ trông như sau:
claude-hooks-practice/
├── shipping.json
├── shipping.cjs
├── shipping.test.cjs
└── .claude/
└── hooks/
├── after-edit.cjs
└── run-shipping-tests.cjs
Sau khi đã đọc và kiểm tra độ an toàn của 2 file script, bạn tiến hành tạo tệp cấu hình .claude/settings.json để kích hoạt Hook ở chế độ chỉ định dạng (--format-only):
{
"hooks": {
"PostToolUse": [
{
"matcher": "^(Edit|Write)$",
"hooks": [
{
"type": "command",
"command": "node",
"args": [
"${CLAUDE_PROJECT_DIR}/.claude/hooks/after-edit.cjs",
"--format-only"
],
"timeout": 30
}
]
}
]
}
}
Giải thích ý nghĩa cấu hình:
"matcher": "^(Edit|Write)$": Chỉ kích hoạt Hook khi Claude Code vừa dùng công cụEdithoặcWritethành công."--format-only": Tham số truyền vào để script chỉ thực hiện chuẩn hóa định dạng JSON mà chưa chạy bộ kiểm thử.- Bạn có thể gõ lệnh
/hooksngay trong cửa sổ phiên làm việc của Claude Code để kiểm tra xem mụcPostToolUseđã được nạp thành công hay chưa.
Bước 3: Kiểm chứng khả năng tự động Format sau khi ghi file
Để kiểm tra xem Hook có thực sự tự động làm đẹp mã nguồn sau khi Claude ghi file hay không, hãy gửi yêu cầu sau cho Claude:
Dùng công cụ Write để lưu shipping.json với đúng chuỗi JSON viết liền một dòng này: {"freeShippingAt":50,"standardFee":5}. Giữ nguyên helper và test. Không tự chạy trình định dạng. Dừng lại ngay sau khi ghi để tôi kiểm tra kết quả của hook.
Ngay sau khi công cụ Write hoàn tất, Hook sẽ tự động chạy ngầm và trả về thông báo hệ thống (systemMessage):
[after-edit] Formatted shipping.json. Tests are off.
Khi mở lại file shipping.json trong trình soạn thảo, bạn sẽ thấy chuỗi JSON một dòng đã được tự động ngắt dòng và thụt lề 2 khoảng trắng chuẩn xác mà không cần nhắc Claude thêm bất kỳ câu lệnh nào.
Bước 4: Bật tính năng tự động chạy 5 bài Test vào chung một Hook
Bây giờ, để kích hoạt luôn quy trình kiểm thử tự động ngay sau bước định dạng, bạn hãy mở file .claude/settings.json và xóa tham số "--format-only" khỏi mảng args:
"args": [
"${CLAUDE_PROJECT_DIR}/.claude/hooks/after-edit.cjs"
]
Tại sao Blog iTee khuyên bạn nên gộp cả việc định dạng và chạy test vào chung một script điều phối thay vì tách thành 2 handler riêng biệt? Lý do là trong Claude Code, các Hook handler cùng khớp một sự kiện sẽ chạy song song (parallel). Nếu tách riêng, trình chạy test có thể đọc file ngay trong lúc trình định dạng đang ghi đè, gây xung đột dữ liệu. Gộp chung vào một script giúp đảm bảo thứ tự tuần tự: Định dạng xong mới chạy Test.
Khi bạn lặp lại thao tác ghi file ở Bước 3, màn hình sẽ lập tức báo cáo cả 5 bài kiểm thử đã vượt qua:
[after-edit] PASS: 5 tests passed.
Bước 5: Cố ý tạo lỗi logic (Bug) và quan sát Hook bắt lỗi
Để thấy rõ giá trị thực chiến của Claude Code Hooks trong việc ngăn chặn lỗi phát sinh khi lập trình với AI, hãy yêu cầu Claude cố tình thay đổi dấu so sánh trong file shipping.cjs:
Dùng công cụ Edit để chỉ đổi phép so sánh >= thành > trong shipping.cjs. Đây là lỗi cố ý để thử nghiệm cục bộ. Giữ nguyên cài đặt vận chuyển và cả 5 bài test. Để hook tự chạy, báo cáo kết quả của nó, rồi dừng lại trước khi sửa bất cứ thứ gì.
Với thay đổi từ >= 50 sang > 50, các đơn hàng 49 USD và 75 USD vẫn tính phí đúng, nhưng đơn hàng chạm mốc đúng 50 USD sẽ bị tính nhầm 5 USD phí ship. Ngay khi công cụ Edit vừa lưu file, Hook lập tức phát hiện lỗi biên (boundary bug) và trả về mã thoát 2 kèm cảnh báo chi tiết cho cả bạn lẫn Claude:
[after-edit] Tests failed: 4 passed, 1 failed, 0 skipped, 0 todo, 0 cancelled.
- orders at $50 ship free: Expected values to be strictly equal: 5 !== 0; expected: 0; actual: 5
The tool's edit has already saved. Review the failure before continuing.
Lưu ý rằng vì PostToolUse chạy sau khi công cụ đã lưu file, thay đổi chứa lỗi vẫn nằm trong shipping.cjs nhưng quá trình làm việc đã được phanh lại kịp thời kèm nguyên nhân lỗi rõ ràng. Nguyên tắc vàng ở đây là: Sửa lại mã nguồn logic, tuyệt đối không sửa bài test để cho qua lỗi.
Bước 6: Khôi phục mã nguồn chuẩn và xác minh lại toàn bộ hệ thống
Hãy gửi yêu cầu tiếp theo để Claude khôi phục lại phép toán đúng và để Hook tự động nghiệm thu kết quả:
Khôi phục phép so sánh >= trong shipping.cjs bằng công cụ Edit. Giữ nguyên shipping.json và các bài test gốc. Để hook chạy và báo kết quả. Không commit, không triển khai và không đổi file khác.
Ngay sau khi sửa lại thành >=, Hook sẽ chạy lại toàn bộ 5 bài kiểm thử và trả về trạng thái PASS: 5 tests passed. Bạn có thể đối chiếu lại toàn bộ chu trình kiểm thử qua bảng tổng kết dưới đây:
| Thao tác kiểm tra | Kết quả mong đợi từ hệ thống Hook |
|---|---|
Ghi file shipping.json trên 1 dòng khi bật --format-only |
File tự động được trình bày lại thành nhiều dòng, thụt lề 2 khoảng trắng. |
| Chỉnh sửa code khi thuật toán tính phí vận chuyển chuẩn xác | Hook báo cáo cả 5 bài test đều đạt (5 tests passed). |
Đổi >= thành > làm đơn hàng 50 USD mất ưu đãi miễn phí |
Bài test ở mốc 50 USD báo lỗi ngay lập tức (Kỳ vọng: 0, Thực tế: 5). |
Kiểm tra trạng thái file sau khi Hook báo lỗi PostToolUse |
Thay đổi lỗi vẫn được lưu trên ổ cứng nhưng kèm thông báo chặn để rà soát. |
Khôi phục lại toán tử >= trong shipping.cjs (giữ nguyên bộ test) |
Cả 5 bài kiểm thử xanh trở lại mà không cần chạy lệnh thủ công. |
Bước 7: Cách tắt hoặc gỡ bỏ Hook khi không còn sử dụng
Khi muốn tắt Hook thử nghiệm này trong dự án, bạn chỉ cần mở tệp .claude/settings.json và xóa mục cấu hình tương ứng bên trong danh sách PostToolUse (giữ nguyên các thiết lập phân quyền hoặc các Hook khác của nhóm). Claude Code sẽ tự động nạp lại cấu hình mới ngay trong phiên làm việc hiện tại — bạn có thể gõ /hooks để xác nhận danh sách đã trống.
5. Bảng tra cứu nhanh các lỗi thường gặp khi cấu hình Claude Code Hooks
Trong quá trình thiết lập, nếu Hook không hoạt động như ý muốn, bạn có thể tra cứu nguyên nhân và cách khắc phục nhanh theo bảng dưới đây:
| Hiện tượng lỗi | Nguyên nhân & Cách kiểm tra khắc phục |
|---|---|
| Hook không phản hồi gì sau khi sửa file | Gõ lệnh /hooks kiểm tra xem Hook đã nạp chưa; xác nhận đã cấp quyền Workspace Trust cho thư mục và thao tác sửa vừa rồi có thực sự dùng tool Edit hoặc Write hay không. |
Không tải được file .claude/settings.json |
Gõ lệnh /status để xem thông báo lỗi cú pháp JSON (rất hay gặp lỗi dư dấu phẩy ở phần tử cuối cùng). |
| Chỉ chạy Format mà không chạy Test | Kiểm tra lại mảng args trong settings.json xem bạn đã xóa cờ --format-only chưa. |
Hook báo lỗi không tìm thấy lệnh node |
Chạy thử node --version trong cùng cửa sổ Terminal và khởi động lại phiên làm việc nếu vừa cập nhật biến môi trường PATH. |
| Lệnh Shell sửa file nhưng Hook không kích hoạt | Biểu thức matcher trong bài chỉ bắt sự kiện của công cụ Edit và Write, không bắt công cụ Bash. |
Mẹo gỡ lỗi nâng cao (Debug Log): Nếu muốn theo dõi chi tiết từng lệnh mà Claude Code đã gọi ngầm khi thực thi Hook, bạn có thể khởi động phiên làm việc kèm cờ ghi nhật ký riêng tư:
claude --debug-file hook-debug.log
6. Câu hỏi thường gặp (FAQ)
1. Sự kiện PostToolUse và PreToolUse khác nhau như thế nào?
PreToolUse chạy trước khi công cụ thực thi nên có thể dùng để kiểm tra điều kiện và ngăn chặn thao tác nguy hiểm. Ngược lại, PostToolUse chạy sau khi công cụ đã thực hiện xong (file đã được lưu xuống ổ đĩa), chuyên dùng để tự động định dạng code, chạy linter hoặc chạy unit test kiểm tra chất lượng.
2. Khi bài test trong PostToolUse thất bại, Claude có tự động hoàn tác (Revert) file vừa lưu không?
Không. Vì PostToolUse diễn ra sau khi thao tác ghi file đã hoàn tất nên nội dung vừa sửa vẫn được giữ nguyên. Tuy nhiên, khi script thoát với mã lỗi 2 và gửi thông báo qua stderr, Claude Code sẽ nhận được ngay phản hồi chi tiết về bài test bị lỗi để cùng bạn phân tích và sửa lại ở bước kế tiếp.
3. Có nên cấu hình Hook chạy toàn bộ bộ Test lớn của dự án sau mỗi lần sửa file không?
Không nên nếu bộ kiểm thử của bạn mất nhiều thời gian thực thi. Đối với sự kiện PostToolUse kích hoạt liên tục sau mỗi lần sửa file, bạn chỉ nên cấu hình chạy các bài Unit Test nhỏ, nhanh (dưới vài giây) liên quan trực tiếp đến module đang sửa, và để dành các bài Integration/E2E Test nặng cho bước kiểm tra trước khi tạo Pull Request hoặc CI/CD.
7. Lời kết
Việc làm chủ Claude Code Hooks giúp bạn chuyển đổi quy trình lập trình với AI từ bị động nhắc nhở sang tự động hóa kiểm soát chất lượng chặt chẽ và nhất quán. Chỉ cần tuân thủ 3 nguyên tắc cốt lõi: kiểm duyệt kỹ mã nguồn Hook trước khi bật, giữ nguyên tính toàn vẹn của bài Test khi sửa lỗi và ưu tiên các bài kiểm tra nhanh sau mỗi thao tác chỉnh sửa, bạn sẽ khai thác tối đa sức mạnh của AI Agent mà không lo phát sinh lỗi ngầm. Đừng quên theo dõi iTee Pro mỗi ngày để cập nhật thêm nhiều thủ thuật AI Coding và tối ưu hóa quy trình phát triển phần mềm mới nhất!

💬 Thảo Luận & Hỏi Đáp Kỹ Thuật
Nhận xét
Đăng nhận xét