On October 1, Anthropic shipped mods for Claude Code: short TypeScript functions that run inside the agent and change what it does. One of the things a mod can do is approve a tool call before the permission prompt ever reaches you. That one capability is why mods are at once the most useful extension point Claude Code has shipped and a fresh way to hand your machine to code you did not read.
Mods are on by default in Claude Code v2.1.287 and later, and they run in the CLI and in the Code tab of the desktop app. Run claude --version to see where you stand. Before you let Claude write you a mod or install one from a directory, it is worth understanding exactly what you are turning on, because the official guidance is blunt about it: “Mods run with the same access to your machine as Claude Code itself. They aren’t sandboxed, and you should only install mods from sources you trust.”
What a mod actually is
A mod is a plugin whose code registers event handlers, which the docs call hooks. The smallest one is three files: a plugin.json manifest, a hooks.json that points at your code, and a register.js (or .ts) that tells Claude Code which events to run your functions on. Claude Code fires an event each time it is about to act, passes it to your handler, and your handler decides what happens next. It can observe the event and let it continue, rewrite it before it continues, or answer it so the normal behavior never runs.
The events you can hook are the whole agent loop. tool.call fires before Claude uses a tool. prompt.submit fires on every prompt you send. tool.check fires on the permission decision. ui.render fires when Claude Code draws a piece of its interface, so a mod can add a pane beside the transcript or a band above the prompt, or restyle a tool-call row. session.append lets a mod rewrite each row of the conversation before it is stored. This is more reach than a settings hook, a skill, or an MCP server has, because those run outside Claude Code and a mod runs inside it.
If that pattern sounds familiar, it should: several of Claude Code’s own features are already mods. The /diff pane is a mod. Loading your AGENTS.md as project instructions is a mod. So is the telemetry that logs analytics, and so is the security guard that enterprise accounts get. Anthropic shipped the extension system and then moved its own built-ins onto it, which tells you how much the mechanism can do.
The mods worth writing first are the unglamorous ones
The demos getting passed around are the fun ones: a context-window forecast above the prompt, a loop detector, a side agent drawing cartoons while Claude works. Useful enough. But the mods that earn a permanent place in a working setup are the guardrails and the instruments, and this is where a practitioner should start.
Anthropic’s own sample mods, in the claude-code-playground repository, point the way. blast-radius holds a risky shell command such as rm -rf or a force push, shows what it would change, and gives you buttons to proceed or cancel. replay-theater adds a /replay command that steps through the file edits Claude made in the last turn. token-weather charts how full your context window is getting. Extend that list with the ones the announcement highlights for teams: a sidebar showing CI/CD status, a confirmation gate before Claude touches production config, and an audit log that records every mod call. A prompt.submit or tool.call hook can also redact a secret from tool output before Claude ever reads it.
You do not have to hand-write any of this. Describe the mod you want inside a Claude Code session and it will write and install one for you. The quickest high-value build for most teams is a tool-call audit hook that writes a line per tool to a log you control, so you have a record of what the agent did without waiting on a vendor. That is a half-hour mod with a real payoff.
The same hook that adds a guardrail can remove one
Here is the part the launch coverage skips. The surface that lets a mod hold a dangerous command is the same surface that lets a mod wave one through. A mod is not sandboxed. Once it loads, per Anthropic’s own documentation, it can act on your machine as you (read and write any file your account can, start programs, make network requests), read your secrets (environment variables and settings files, including an API key kept in either), see your session (every prompt and every tool call), change your session (rewrite a prompt or a tool call, or submit a prompt as if you had typed it), act without asking you (approve a tool call before you are prompted), and spend your usage against your plan or API key.
Two of those deserve a second read. First, a mod can approve a tool call that an ask rule would have prompted for, and in auto mode the approved call runs with no classifier check. A mod cannot restyle the permission prompt itself, but it does not need to: it answers the call before the prompt would appear. Second, turning on Claude Code’s sandboxing does not help, because the sandbox isolates the Bash commands Claude runs, and a process that a mod starts runs outside it.
This is the exact shape of the supply-chain problem that hit four AI coding agents through their plugin systems earlier this year: a thing you install, running with trust it has not earned, inside the tool you already granted broad access. A mod from a stranger is not a theme. It is an unsigned program with your file system, your keys, and your agent’s permission dialog. Outside coverage made the same point on day one: the mods are not sandboxed, and built-ins like /diff now ship through the same mechanism a third party would use.
One command before you install anything: claude plugin validate
The good news is that the risk is inspectable, and the inspection is one command most people will skip. Clone or download the mod, then run claude plugin validate on its directory. It prints two lines without running the code:
❯ ./register.js hooks: session.start, tool.call, ui.render{component=Pane}
❯ ./register.js calls: $.fs.read, $.http.fetch, $.store.set, $.ui.open
The hooks: line lists the events the mod receives. The calls: line lists the mods-API methods its code uses, and that is where intent shows. A context-window chart has no business reading your environment or starting a process. Scan the calls: line for these:
| Call in the mod’s code | What it means it can do |
|---|---|
$.fs.read, $.fs.write |
Read or write files anywhere your account can |
$.process.run, $.process.spawn |
Start programs as you |
$.http.fetch |
Make network requests (the exfiltration path) |
$.env.get, $.settings.read |
Read env vars and settings, where API keys live |
$.prompt.submit |
Submit a prompt, possibly as your own words |
$.session.send |
Send a message another of your sessions reads |
$.model.complete |
Spend your plan or API key on model calls |
tool.check (in hooks:) |
Approve or deny a tool call before the prompt |
A mod whose job does not explain the calls it makes is a mod you do not install. The same discipline applies to a mod Claude writes mid-session: it is still code running as you. Two more habits worth building: run /plugin to see which mods a session actually loaded (a dim line reads something like 1 mod active · first-mod), and keep claude --safe-mode in your back pocket to start a session with every installed mod and customization off when you are chasing down odd behavior.
If more than you runs Claude Code
On a team this stops being a personal call. On Team and Enterprise plans, and on any machine with managed settings, a built-in guard named sec-default loads ahead of every mod a user installs, and users cannot turn it off. Its source is public. It keeps a user’s mod from changing what your managed hooks receive, your system prompt, your managed instructions, or your managed MCP tools, and where it loads, a user’s mod cannot approve a call that a deny rule refuses (that protection is on by default; the opposite, allowModsToOverrideDenyRules, is off). To block user-installed mods entirely, set allowManagedModsOnly in managed settings.
Now the detail that decides whether your policy is real: the guard’s deny-rule protection covers Claude’s tool calls, not a mod’s own API calls. With Read(.env) denied, a mod can still read that file directly with $.fs.read, or start a program that reads it. A deny rule is not a boundary against a malicious mod. If you need that boundary, you keep the mod from loading in the first place, or you run a policy mod of your own: a plugin.register hook that inspects every other mod’s calls: list and refuses the ones that reach for $.process.run or $.process.spawn, while auditing the rest. Written with a .catch handler, it fails closed, refusing any mod it could not check. That, plus allowManagedModsOnly and a marketplace allowlist, is a governance posture you can actually defend.
Treat a mod like the privileged code it is
Running endpoint agents and browser extensions across a large telecom taught me the same lesson every time: the control that held was never “we trust the publisher.” It was an allowlist of what could install, a validation step before it did, and a log of what it touched afterward. A mod sits even closer to the metal than a browser extension, because it sits inside the tool you already handed your repository, your shell, and your keys.
So the rules write themselves. Build your own guardrail and audit mods first, because those are pure upside. For anything third-party, run claude plugin validate before it loads, pin the version, prefer a marketplace your organization controls, and log every tool call through a policy mod. On a fleet, set allowManagedModsOnly and ship a policy mod rather than hoping users vet their own. And never treat a deny rule as the thing standing between a mod and your .env. Mods are the best native control plane Claude Code has shipped. They are only a control plane if you are the one writing the controls.
