Mười hai ngày từ 'nếu bạn muốn tính năng này' đến Tetris
Claude Code Mods là các module TypeScript chạy bên trong engine của Claude Code và hook các event của nó dưới dạng hàm. Boris Cherny, người phụ trách Claude Code tại Anthropic, thông báo chúng bằng năm chữ: "Claude mods are landing now." Bài đăng thu về 2.400 lượt thích, và đã có người dựng xong Tetris bên trong terminal. Tetris, Doom, và một con thú cưng lớn dần trong lúc Claude chạy test của bạn, tất cả được render ngay phía trên ô prompt, với chi phí bằng 0 token.
Bài thông báo không dẫn tới trang docs nào. Nó dẫn tới một GitHub issue được một kỹ sư Anthropic mở ra 12 ngày trước đó, kèm một điều kiện được viết thẳng vào issue. Alice Poteat viết rằng phản ứng từ cộng đồng nhiều khả năng sẽ quyết định tính năng này có được ship hay không. 177 bình luận sau đó, người ta đã vắt kiệt file binary được gắn cờ, đo timeout của nó, và dựng game trên nền đó.
| Measure | Value |
|---|---|
| Likes on the announcement | 2,400 |
| Comments on the GitHub issue | 177 |
| Typed surface in this week's build | 10,700 lines |
| Events on nouns (issue-thread build) | 84 on 19 |
| Mods on GitHub inside 48 hours | 31 |
Trang docs tại thời điểm viết bài trả về lỗi 404. Bài viết này đề cập bốn cách để mở rộng Claude Code, một Mod hữu ích được dựng lên rồi cố tình phá vỡ, và những gì vẫn còn bất ổn trước khi bạn ship một Mod.
Một Mod là một hàm nằm ở giữa
Cây mã nguồn định nghĩa nó trong một câu: một Mod là một plugin của Claude Code có hành vi nằm trong một hooks module. Một dòng đăng ký (register) hook các event của engine dưới dạng hàm. Trên đĩa, đó là một thư mục plugin, một hooks manifest chỉ định đúng một module, và bản thân module đó.
Mỗi hook là một hàm của ba thứ: $, cánh cửa mà mọi side effect đều đi qua; event; và continuation, tức phần còn lại của chain bên dưới bạn. Các hook lồng vào nhau như middleware. Hook nào đăng ký trước sẽ sở hữu event đó, và không hook nào ở dưới trong chain có thể ngăn nó lại. Thứ tự đó do cấu hình quyết định, không phải do thứ tự cài đặt. Theo lời Alice Poteat, thứ tự do configuration đặt ra, không phải do thời điểm bạn cài chúng.
Không có quyền truy cập ngầm định nào cả. Mọi thứ một Mod làm đều đi qua $, nên một admin có thể audit, cho phép, từ chối hoặc log bất kỳ event nào. Một người bình luận tóm gọn: những gì một plugin đã làm chính xác là những lệnh gọi nó đã thực hiện. Một hook duy nhất trên * thấy được mọi event, nên một audit log chỉ là một hàm. Một Mod có thể vẽ, vì interface là React. Nó chạy in-process trên Bun, ở mức 50 microsecond tại percentile thứ 99. Một biến môi trường bật nó lên. Những gì thực sự nằm trên $ vẫn đang được thiết kế cùng các đối tác early-access.
Bốn cách mở rộng Claude Code, và cách nào dùng cho việc gì
Một shell hook là một script được engine gọi vào một thời điểm cố định. Nó nhận JSON qua standard input và trả lời bằng một exit code. Câu trả lời có một giới hạn: 8.000 ký tự context trả về, và 2.000 cho một số hook. Theo lời Pratham, trên Windows chúng thường hỏng theo những cách kỳ lạ.
Một plugin là một cái hộp. Một manifest gói gọn skills, agents, hooks và MCP server. Nó được cài từ một marketplace hoặc load thẳng từ một thư mục trên đĩa, và một lệnh duy nhất validate cái hộp đó trước khi bất cứ thứ gì chạy.
Một skill là văn xuôi mà model đọc khi cần đến. Phần nội dung chỉ load khi có một prompt khớp với nó. Đây vẫn là cách rẻ nhất để thay đổi hành vi.
Một Mod là cùng một cái hộp đó cộng thêm một file: một hooks manifest chỉ định một module, và module đó là TypeScript, có kiểu (typed), chạy in-process, trên mọi event của engine. Đó là toàn bộ sự khác biệt.
| Mechanism | What it is | Runs | Ceiling |
|---|---|---|---|
| Shell hook | Script called at a fixed moment | Subprocess, exit code | 8,000 chars back (2,000 for some hooks) |
| Plugin | Bundle of skills, agents, hooks, MCP servers | Installed or loaded from disk | Validated before it runs |
| Skill | Prose loaded on a matching prompt | In the model's context | Cheapest change |
| Mod | Plugin plus a TypeScript hooks module | In process, on every event | Typed, early access |
Các kiểu (types) đến từ một slash command duy nhất, lệnh này ghi thẳng toàn bộ danh sách những gì $ cung cấp vào project của bạn. Các shell hook cũ được bọc lại (wrapped), không bị khai tử. Trên một bản build sớm, Spencer Morley đã chứng kiến lớp wrapper đó load lỗi mà vẫn ở trạng thái được khai báo. Quy tắc chung: để thay đổi những gì Claude biết, hãy viết một skill; để chạy một script tại một thời điểm, một shell hook; để ship một bundle, một plugin; để nằm bên trong engine, một Mod. Shell hook vẫn hoạt động ở mọi nơi có flag đang tắt.
Ba Mod của chính Anthropic, đọc từ mã nguồn
Ba Mod được ship sẵn bên trong binary và mã nguồn của chúng có trên GitHub: một security default, một diff pane, và telemetry.
Security default nằm ở lớp ngoài cùng. Trên một máy có managed settings, hoặc trong một tổ chức Team hay Enterprise, không gì một người dùng cài vào có thể vượt lên trên nó. Nó hook 12 event, và mỗi hook thực hiện một trong ba hành động: cho đi tiếp qua user tier, từ chối một caller từ user tier theo tên, hoặc pass. Nó fail closed, và doc comment nói rõ điều đó chỉ trong hai chữ. Đó chính là phần mà thread quan tâm nhất: một admin gỡ một khả năng khỏi $, và không gì được đăng ký bên dưới có thể gọi lại nó được nữa. Theo lời một người bình luận, điều đó khác biệt hoàn toàn so với việc chỉ yêu cầu một plugin đừng làm gì đó.
Diff là một pane bên cạnh transcript, hiển thị các thay đổi chưa commit của session, từng file một, được refresh liên tục khi Claude chỉnh sửa. Nó được đăng ký lúc session bắt đầu và trải rộng trên 27 file phụ trợ, không hề là một món đồ chơi.
Telemetry thêm một noun vào $ từ bên trong quá trình khởi tạo engine. Nó await những gì nằm bên dưới và trả về cả cái đó lẫn chính nó. Nó chỉ chạy trong các bản build nội bộ.
README nói hãy chạy một cái từ source và test một cái từ source. Phần help của bản build hôm nay liệt kê validate, eval, và details. Không có test trong danh sách đó, dù phần help của test vẫn trả lời khi gọi. Tầng built-in cũng từ chối bản sao của bạn: ship một plugin trùng một trong những tên đó, binary sẽ load bản của chính nó.
Bốn mươi hai dòng: một Mod giấu bí mật khỏi model
Slash command ghi ra các kiểu (types) tạo ra, trên bản build này, 11.700 dòng: 84 event trên 23 noun. Hook tool call trả lời bằng một result hoặc một deny, không bao giờ là văn bản gốc. Phần đó do core quy định.
Mod này gồm ba file: plugin manifest, hooks manifest với một dòng duy nhất, và module. Module dài 42 dòng. Nó await những gì nằm bên dưới, làm sạch (scrub) kết quả, rồi trả lại. Bốn pattern bao phủ hai dạng vendor key, một GitHub token, và bất cứ thứ gì được gán cho một biến tên là key, secret hoặc token.
Validate đọc mã nguồn trước khi nó chạy. Nó nêu tên event mà module hook vào và thứ duy nhất nó gọi trên $. Cảnh báo duy nhất là thiếu tên tác giả (author). Được load từ đĩa với flag bật, file test chứa hai key, cả hai đều giả có chủ đích, và model đọc được "redacted". Theo lời chính nó, các giá trị trả về là redacted, nên nó không thể thấy bên trong chúng chứa gì.
| Measure | Value |
|---|---|
| Module length | 42 lines |
| Hop latency, worker included | 28 ms |
| Tokens added to the session | 0 |
Engine ghi log hop này là đã được resolved bởi một hooks module. Inventory không cho thấy skill nào, agent nào, không gì luôn bật sẵn. Một giới hạn vẫn còn đó: giấu khỏi model không phải là giấu khỏi màn hình. Transcript vẫn hiển thị những gì tool đã in ra. Đó là một Mod khác, như Max ở Ship Notes đã ghi chú trong một dòng.
Phá nó: một guard chậm là một guard bị vượt qua
Vẫn Mod đó, thêm đúng một dòng: một sleep 15 giây trước lệnh gọi tới thứ nằm bên dưới. Mười giây sau, engine bỏ cuộc với nó, báo rằng hook đã vượt ngân sách (budget) và bị skip, rồi thứ bên dưới nó chạy thay vào chỗ đó. Lệnh vẫn chạy như thường và in ra "hi".
Thay sleep bằng một throw: 574 millisecond, cùng một kết quả, skipped, và lệnh vẫn chạy.
| Case | Time | Verdict |
|---|---|---|
| Healthy hook | 28 ms | Resolved |
| Throw | 574 ms | Skipped, command ran |
| Hang | over 10 s | Skipped, command ran |
Cả hai kiểu lỗi đều kết thúc bằng cùng một từ: skipped. Thread này đã đo được sự bất đối xứng đó từ một tuần trước. Một khả năng bị thiếu lúc load sẽ fail closed. Một hook vượt ngân sách sẽ fail open: ồn ào nhưng bị vượt qua, theo lời Spencer Morley. Một block không kèm lý do chỉ đơn giản đẩy model sang một tool khác. Pratham đã chứng kiến nó chọn một tool khác và vẫn ghi file như thường.
Câu trả lời đang được đặt lên bàn là một catch. Alice Poteat đề xuất một catch trên phần return của hook, sẽ chạy nếu bạn mất quá nhiều thời gian hoặc throw. Một lần ghi (write) đã bị viết lại vẫn cần một ghi chú gửi tới model: nó thấy những gì nó đã yêu cầu ghi, vì lý do caching, nên bạn phải thêm một dòng context. Ngân sách đó cũng chính là ranh giới cô lập (isolation). Hooks worker chạy tách biệt, và khi nó crash, engine sẽ respawn nó và tắt hooks cho cả session đó. Bản sửa không phải là một ngân sách dài hơn mà là một catch được khai báo rõ ràng.
Bốn mươi tám giờ của Mods, và một câu lệnh mua được gì
Hai ngày sau: Tetris ngay phía trên prompt cùng bảy game khác, chơi được trong khi Claude vẫn đang làm việc, với chi phí bằng 0 token. Doom, bản gốc năm 1993, chạy trong tiến trình riêng của nó; Mod này chạm tới nó qua HTTP nội bộ và redraw 10 lần mỗi giây. Có một breathing pacer trong spinner, và một story model với 260.000 tham số chạy bên trong hooks worker, với 0 API token.
Registry đã quét 31 Mod bằng validate. 14 trong số đó có thể chạy host process. 13 thấy được mọi tool call.
Demo 8 của community thread hứa hẹn rằng một câu duy nhất sẽ viết ra một plugin giấu bí mật trước khi model đọc được chúng. Chúng tôi đã yêu cầu một cái.
| Measure | Value |
|---|---|
| Time | 4 min |
| Turns | 34 |
| Cost | $1.23 |
| Lines (plus a test file) | 190, against our 42 |
| Tests | 4 pass in a third of a second |
Nó gắn nhãn cho những gì nó giấu theo loại, validate sạch, và không cần API key lẫn lệnh gọi model nào. Một câu trả lời đã diễn đạt điều này: allowlist mới là sản phẩm, Tetris chỉ là bản demo.
Kết luận: xây dựng ngay bây giờ, ship sau
Chính các con số của registry là lời cảnh báo. 14 trên 31 Mod có thể chạy host process, và cơ chế kiểm định duy nhất là một dấu vết tĩnh (static footprint). Chính phần help của eval cũng nói rõ điều đó: một test suite pass không phải là một sự kiểm định bảo mật.
| Signal | Value |
|---|---|
| Events on the 8th | 20 |
| Events on the 15th | 84 |
| CLI versions in a fortnight | 14 |
| Hacker News points | 2 |
| Replies to the compatibility question | 0 |
Ngân sách 10 giây nằm trong runtime, không nằm trong types, theo lời Marat. Không có dòng changelog nào, không trang docs, không bài launch. Một đối thủ nói Anthropic đã copy ý tưởng này: Ahmad Awais chỉ thẳng vào mods của Command Code, và anh viết luôn ví dụ mod của họ, nên hãy tự cân nhắc điều đó. Bài đăng "early access, APIs may change" thu về 357 lượt thích.
Xây dựng một cái ngay bây giờ nếu bạn đã viết hook sẵn và muốn có audit, redaction hoặc một pane. Chờ đợi nếu bạn sắp ship cho một team trước khi hợp đồng (contract) được viết rõ ràng. Chính sự cởi mở đó là lý do vì sao cái ngân sách fail open, lỗi sai kiểu MCP call, và lỗi wrapper đều được người dùng phát hiện chỉ trong vài ngày.
AIDive