TL;DR

Prompt là ràng buộc mềm: bạn "xin" AI làm theo. Hook là ràng buộc cứng: hệ thống bắt buộc chạy một hành động khi sự kiện xảy ra - không cần AI nhớ, không cần AI đồng ý. Claude Code có hơn 27 lifecycle events mà bạn có thể kéo hook vào. Đây là cơ chế thực sự để kiểm soát AI agent.

Vấn đề với prompt-only workflow

Khi bạn viết trong CLAUDE.md: "Sau khi sửa code nhớ chạy test", Claude Code sẽ làm theo... hầu hết thời gian. Đó là vấn đề: "hầu hết" là không đủ khi bạn làm việc trên codebase quan trọng.

Prompt là soft constraint - một lời nhắn bạn gửi cho AI. AI hiểu rồi thực hiện dựa trên ngữ cảnh, trạng thái, và đôi khi cả yếu tố ngẫu nhiên. Trong dự án thử nghiệm chạy một tuần rồi bỏ? Không sao. Trong repo production của công ty? Đó là nguồn gốc của sự cố.

Hook sinh ra để giải quyết đúng vấn đề này: chuyển một phần "dựa vào AI tự giác" thành "hệ thống tự động kích hoạt".

Hook là gì - giải thích không cần thuật ngữ

Hook (móc câu) là một đoạn hành động được gắn sẵn vào một vị trí cụ thể trong luồng chạy của chương trình. Khi chương trình đi đến vị trí đó, đoạn hành động tự động thực thi - không phụ thuộc vào việc ai đó có nhớ kích hoạt nó không.

Hai ví dụ trực quan:

  • Đèn cảm biến chuyển động: Bạn không cần nhớ bật đèn - chỉ cần bước vào vùng cảm biến, đèn tự sáng. Hook không phụ thuộc vào trí nhớ của bất kỳ ai.

  • SMS báo bưu kiện: Bạn không cần hỏi nhân viên bưu điện - miễn là kiện hàng đến, tin nhắn tự gửi. Quy tắc: sự kiện xảy ra → hành động tất yếu thực thi, không thương lượng.

Ứng dụng vào Claude Code: khi AI chuẩn bị chạy một lệnh Bash, trước khi lệnh đó thực thi, một hook PreToolUse của bạn sẽ chạy để kiểm tra. Nếu lệnh đó là rm -rf, hook trả về "deny" - AI không thể tiếp tục, dù nó có muốn hay không.

CodeIsland - ví dụ trực quan nhất về hooks

Trước khi đào sâu vào cấu hình, hãy nhìn vào một ứng dụng thực tế để thấy hooks hoạt động thế nào trong đời thực.

CodeIsland là dự án mã nguồn mở biến vùng notch trên MacBook thành bảng điều khiển real-time cho AI coding agents. Thay vì phải chuyển qua lại giữa terminal và cửa sổ khác để xem Claude Code đang làm gì, bạn chỉ cần liếc qua notch: pixel animation hiển thị trạng thái hiện tại - đang chạy task, đang chờ bạn xác nhận, hay đã xong việc. Ứng dụng hỗ trợ hơn 12 tools bao gồm Claude Code, Codex, Gemini CLI, Cursor.

Cơ chế hoạt động hoàn toàn dựa trên hooks. CodeIsland cài một bộ hook nhẹ vào config của từng AI tool. Mỗi khi AI thực hiện một hành động - bắt đầu session, gọi tool, hiện hộp thoại xin quyền - hook tương ứng được kích hoạt và gửi một message qua Unix socket. CodeIsland lắng nghe phía kia, nhận message và cập nhật animation trên notch ngay lập tức.

Hook ở đây chỉ làm một việc cực nhanh: gửi một tin nhắn qua socket (vài millisecond) rồi trả control về cho AI. Phần render animation nặng hơn được xử lý bởi app CodeIsland chạy nền. Đây là pattern quan trọng ta sẽ gặp lại nhiều lần khi làm việc với hooks.

Điểm thú vị: CodeIsland được lấy cảm hứng từ dự án claude-island, rồi cộng đồng tiếp tục phát triển thành nhiều variant khác. Chính điều này cho thấy hooks là một "cửa mở" linh hoạt đến mức nào - bạn có thể làm animation, log, cảnh báo, hay bất kỳ thứ gì bạn muốn.

Prompt là soft constraint, Hook là hard constraint

Hook vs prompt - sự khác biệt thực chất

Để hiểu tại sao hooks quan trọng hơn hẳn prompt với vai trò kiểm soát, cần nhìn thẳng vào bản chất của từng loại:

Tiêu chí

Prompt (CLAUDE.md)

Hook

Cơ chế

AI đọc, hiểu, quyết định tuân theo

Hệ thống chạy bắt buộc khi event xảy ra

Độ tin cậy

"Hầu hết" - phụ thuộc ngữ cảnh

Tất định - không có ngoại lệ

Có thể chặn tool?

Không - chỉ đề nghị

Có - PreToolUse trả về deny

Tốc độ phản hồi

Phụ thuộc vào reasoning của AI

Milliseconds - script shell

Vấn đề cốt lõi mà hooks giải quyết: AI là thực thể không hoàn toàn tin cậy được. Không phải vì AI xấu - mà vì AI đưa ra quyết định dựa trên ngôn ngữ tự nhiên, và ngôn ngữ tự nhiên vốn có sự mơ hồ. Hooks đưa một phần kiểm soát ra khỏi tay AI, vào tay hệ thống xác định hơn.

Câu nói thực tế từ cộng đồng lập trình: "Prompt là thứ bạn hy vọng AI làm theo. Hook là thứ xảy ra dù AI có muốn hay không."

Ba lớp cấu hình của một hook

Mỗi hook trong Claude Code được định nghĩa qua ba lớp lồng nhau:

  1. Event - điểm lifecycle nào sẽ trigger: PreToolUse, SessionStart, Stop...

  2. Matcher - điều kiện lọc thêm: "chỉ khi tool là Bash", "chỉ khi file là *.env"

  3. Handler - thực thi gì khi khớp: shell script, HTTP endpoint, hoặc LLM prompt

Dữ liệu về event được truyền vào script qua stdin dưới dạng JSON. Script xử lý xong, trả kết quả qua stdout để Claude Code biết tiếp tục hay dừng. Exit code quyết định behavior: 0 cho phép tiếp tục, 2 chặn lại.

Ví dụ cụ thể: khi Claude Code chuẩn bị chạy rm -rf /tmp/build:

  1. Event PreToolUse được kích hoạt

  2. Matcher "Bash" khớp với tool name

  3. Hook script nhận JSON input chứa command, kiểm tra, thấy rm -rf, trả về {"permissionDecision": "deny"}

  4. Claude Code đọc output, hủy tool call, báo cho AI biết lý do

Toàn bộ quá trình xảy ra trước khi lệnh nguy hiểm chạy - đó là sức mạnh của PreToolUse.

Kết - trật tự đúng để làm chủ AI agent

Hooks không phải magic bullet. Chúng là một lớp kiểm soát quan trọng trong kiến trúc làm việc với AI agent. Tác giả bài viết gốc (一个 iOS engineer) đúc kết trật tự đúng: trước tiên làm AI có thể quan sát được, rồi mới nói đến kiểm soát nó, cuối cùng mới tự động hóa. Làm ngược sẽ xây được ảo giác an toàn, không phải an toàn thực sự.

Bài tiếp theo sẽ đi sâu vào toàn bộ 27+ lifecycle events của Claude Code và giới hạn thực sự của hooks - thứ chúng làm được và thứ chúng không thể làm.

via CodeIsland GitHub | Claude Code Hooks Docs