Twelve days from 'if you want this' to Tetris
Claude Code Mods are TypeScript modules that run inside the Claude Code engine and hook its events as functions. Boris Cherny, who leads Claude Code at Anthropic, announced them with five words: "Claude mods are landing now." The post collected 2,400 likes, and someone had already built Tetris inside the terminal. Tetris, Doom, and a pet that grows while Claude runs your tests, all rendered above the prompt, at zero tokens.
The announcement links no docs page. It links a GitHub issue opened 12 days earlier by an Anthropic engineer, with one condition written into it. Alice Poteat wrote that the response from the community would likely dictate whether the feature ships or not. 177 comments later, people had hammered the flagged binary, measured its timeouts, and built games on it.
| 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 |
The docs page at the time of writing returns a 404. This article covers the four ways to extend Claude Code, one useful Mod built and broken on purpose, and what is still unstable before you ship one.
A Mod is a function in the middle
The source tree defines it in one sentence: a Mod is a Claude Code plugin whose behaviour lives in a hooks module. One register entry hooks the engine's events as functions. On disk, that is a plugin folder, a hooks manifest naming exactly one module, and the module itself.
Every hook is a function of three things: $, the door every side effect goes through; the event; and the continuation, the rest of the chain beneath you. Hooks nest like middleware. The one registered first owns the event, and nothing further down the chain can inhibit it. That order is configured, not installed. In Alice Poteat's words, order is set by configuration, not by when you installed them.
There is no ambient access. Everything a Mod does goes through $, so an admin can audit, allow, deny or log any event. One commenter summarised it: what a plugin did is exactly the calls it made. A single hook on * sees every event, so an audit log is one function. A Mod can draw, because the interface is React. It runs in process on Bun, at 50 microseconds at the 99th percentile. One environment variable turns it on. What actually lives on $ is still being designed with early-access partners.
Four ways to extend Claude Code, and which one for what
A shell hook is a script the engine calls at a fixed moment. It gets JSON on standard input and answers with an exit code. The answer has a ceiling: 8,000 characters of context back, and 2,000 for some hooks. In Pratham's words, on Windows they often break in weird ways.
A plugin is a box. One manifest bundles skills, agents, hooks, and MCP servers. It is installed from a marketplace or loaded straight from a folder on disk, and one command validates the box before anything runs.
A skill is prose the model reads when it needs it. The body loads only when a matching prompt arrives. It remains the cheapest way to change behaviour.
A Mod is the same box with one more file: a hooks manifest naming a module, and that module is TypeScript, typed, in process, on every engine event. That is the whole difference.
| 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 |
The types come from one slash command, which writes the full listing of what $ offers straight into your project. The old shell hooks are wrapped, not retired. On an early build, Spencer Morley watched the wrapper fail to load and stay declared. The rule of thumb: to change what Claude knows, write a skill; to run a script at a moment, a shell hook; to ship a bundle, a plugin; to sit inside the engine, a Mod. The shell hook still works everywhere the flag is off.
Anthropic's own three, read from source
Three Mods ship inside the binary and their source is on GitHub: a security default, a diff pane, and telemetry.
The security default sits outermost. On a machine with managed settings, or in a Team or Enterprise organisation, nothing a person installs gets above it. It hooks 12 events, and every hook makes one of three moves: continue past the user tier, refuse a caller from the user tier by name, or pass. It fails closed, and the doc comment says so in two words. That is the part the thread cared about: an admin removes an affordance from $, and nothing registered below can invoke it. In one commenter's words, that is categorically different from asking a plugin not to do something.
Diff is a pane beside the transcript, showing the session's uncommitted changes file by file, refreshed as Claude edits. It is registered on session start and spans 27 helper files, not a toy.
Telemetry adds a noun to $ from inside engine creation. It awaits what is beneath and returns that plus itself. It runs in internal builds only.
The README says to run one from source and test one from source. The help on today's build lists validate, eval, and details. There is no test in the list, even though the test help still answers. The built-in tier also refuses your copy: ship a plugin with one of those names, and the binary loads its own.
Forty-two lines: a Mod that hides secrets from the model
The slash command that writes the types produces, on this build, 11,700 lines: 84 events across 23 nouns. The tool call hook answers with a result or a deny, never the text. That part is set by core.
The Mod is three files: the plugin manifest, the hooks manifest with its one line, and the module. The module is 42 lines. It awaits what is beneath, scrubs the result, and hands it back. Four patterns cover two vendor key shapes, a GitHub token, and anything assigned to a variable called key, secret or token.
Validate reads the source before it runs. It names the event the module hooks and the one thing it calls on $. The only warning is a missing author. Loaded from disk with the flag on, the test file holds two keys, both fake by construction, and the model reads "redacted". In its own words, the values came back as redacted, so it cannot see what is in them.
| Measure | Value |
|---|---|
| Module length | 42 lines |
| Hop latency, worker included | 28 ms |
| Tokens added to the session | 0 |
The engine logs the hop as resolved by a hooks module. The inventory shows no skills, no agents, nothing always on. One limit remains: hidden from the model is not hidden from the screen. The transcript still shows what the tool printed. That is a different Mod, as Max at Ship Notes noted in one line.
Break it: a slow guard is a bypassed guard
Same Mod, one added line: a 15-second sleep before the call to what is beneath. Ten seconds later, the engine gives up on it, reports that the hook exceeded its budget and was skipped, and what is below it runs in its place. The command runs anyway and prints "hi".
Replace the sleep with a throw: 574 milliseconds, same verdict, skipped, and the command runs.
| Case | Time | Verdict |
|---|---|---|
| Healthy hook | 28 ms | Resolved |
| Throw | 574 ms | Skipped, command ran |
| Hang | over 10 s | Skipped, command ran |
Both failures end in the same word: skipped. The thread had measured the asymmetry a week earlier. A capability missing at load fails closed. A hook past its budget fails open: loud but bypassed, in Spencer Morley's words. A block with no reason just sends the model to another tool. Pratham watched it pick a different tool and write the file anyway.
The answer on the table is a catch. Alice Poteat proposes a catch on the hook's return, which runs if you take too long or throw. A rewritten write still needs a note to the model: it sees what it asked to write, for caching reasons, so you append a context line. The budget is also the isolation. The hooks worker runs apart, and when it crashes, the engine respawns it and turns hooks off for the session. The fix is not a longer budget but a declared catch.
Forty-eight hours of Mods, and what one sentence buys
Two days in: Tetris above the prompt and seven other games, playable while Claude works, at zero tokens. Doom, the 1993 original, runs in its own process; the Mod reaches it over local HTTP and redraws 10 times a second. There is a breathing pacer in the spinner, and a story model with 260,000 parameters running inside the hooks worker, with zero API tokens.
The registry scanned 31 Mods with validate. 14 can run host processes. 13 see every tool call.
Demo 8 of the community thread promised that one sentence writes a plugin that hides secrets before the model reads them. We asked for one.
| 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 |
It labels what it hides by kind, validates clean, and needs no API key and no model call. One reply put it this way: allowlists are the product, Tetris is the demo.
Verdict: build one now, ship one later
The registry's own numbers are the warning. 14 of 31 Mods can run host processes, and the only vetting is a static footprint. The eval help says so itself: a passing suite is not a security vetting.
| 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 |
The 10-second budget lives in the runtime, not in the types, as Marat noted. There is no changelog line, no docs page, no launch post. A rival says Anthropic copied it: Ahmad Awais points at Command Code's mods, and he writes their example mod, so weigh that. The "early access, APIs may change" post drew 357 likes.
Build one now if you already write hooks and want audit, redaction or a pane. Wait if you are shipping to a team before the contract is written. The same openness is why the budget that fails open, the MCP call type mismatch and the wrapper failure were found by users in days.
AIDive