tiesa.tech · random

Claude Mods

Official Claude Code plugin feature from v2.1.287. In-process JavaScript or TypeScript handlers that can watch, rewrite, or answer events.

A Claude Code mod is an official plugin feature, on by default from v2.1.287. It is not sandboxed. It runs with the user’s permissions. This page is a full topic landing built from researched twins dated 3–4 October 2026 — not a teaser, and not a mod implementation.

Provenance. Landscape and gateway comparison fetched 3 October 2026. Official mods spec fetched 4 October 2026. GitHub star counts are unaudited (API returned 403). Where a gap is marked unverified, that label stays visible.

What a mod is

A mod is a plugin that changes how Claude Code looks and behaves. It is JavaScript or TypeScript event handlers. Claude Code calls one when an event happens. The handler can watch, change, or take over.

On the docs, hook means a mod handler. A settings-file hook is a settings hook. Both are called.

Require v2.1.287 or newer. Mods are on by default. Check with claude --version.

Changelog 2.1.287: “Added Claude Mods: plugins may now modify deeper behavior.” Current changelog top when fetched was 2.1.288, which adds $.ui.selection() (fullscreen selection text, and the row when the selection is inside one transcript row). That method is not in the reference method list, which says it describes v2.1.287. When the pages and the installed types disagree, the docs say trust the types Claude Code writes for that version.

Plugin → mod → watch / change / take over
flowchart TB
  plugin["Plugin"]
  mod["Mod: JS or TS event handlers"]
  event["Claude Code calls a handler when an event happens"]
  watch["Watch"]
  change["Change"]
  takeover["Take over"]
  settingsHook["Settings-file hook"]
  bothCalled["Both are called"]
  plugin --> mod
  mod --> event
  event --> watch
  event --> change
  event --> takeover
  mod --> bothCalled
  settingsHook --> bothCalled
Diagram source
flowchart TB
  plugin["Plugin"]
  mod["Mod: JS or TS event handlers"]
  event["Claude Code calls a handler when an event happens"]
  watch["Watch"]
  change["Change"]
  takeover["Take over"]
  settingsHook["Settings-file hook"]
  bothCalled["Both are called"]
  plugin --> mod
  mod --> event
  event --> watch
  event --> change
  event --> takeover
  mod --> bothCalled
  settingsHook --> bothCalled

Behaviour

Watch, rewrite, or answer

The handler receives $, e, and next. e is deeply frozen. Assigning to it throws.

e.surface is terminal or desktop.

Three exits: watch, rewrite, answer
flowchart LR
  handler["Handler receives the mods API, e, and next"]
  watch["next of e: watch"]
  rewrite["next with a changed field: rewrite"]
  answer["Return without next: answer and short-circuit"]
  handler --> watch
  handler --> rewrite
  handler --> answer
Diagram source
flowchart LR
  handler["Handler receives the mods API, e, and next"]
  watch["next of e: watch"]
  rewrite["next with a changed field: rewrite"]
  answer["Return without next: answer and short-circuit"]
  handler --> watch
  handler --> rewrite
  handler --> answer

Permissions — not sandboxed

A mod is code that runs with your permissions. It can read and write your files, start processes, and make network requests. Mods aren’t sandboxed. If you turn on sandboxing, the sandbox isolates the Bash commands Claude runs, and a process that a mod starts runs outside it. None of the org controls sandbox a mod: a mod you allow runs as the user.

Once loaded a mod can: act as you; read secrets in env and settings including an API key; see every prompt and tool call; rewrite a prompt or tool call, submit a prompt, or message another session; approve a tool call before you are asked; spend usage.

Once loaded, the mod runs as you
flowchart TB
  loaded["Once loaded, the mod runs as you"]
  files["Read and write files"]
  proc["Start processes"]
  net["Make network requests"]
  secrets["Read secrets in env and settings, including an API key"]
  see["See every prompt and tool call"]
  rewrite["Rewrite a prompt or tool call, submit a prompt, or message another session"]
  approve["Approve a tool call before you are asked"]
  spend["Spend usage"]
  loaded --> files
  loaded --> proc
  loaded --> net
  loaded --> secrets
  loaded --> see
  loaded --> rewrite
  loaded --> approve
  loaded --> spend
Diagram source
flowchart TB
  loaded["Once loaded, the mod runs as you"]
  files["Read and write files"]
  proc["Start processes"]
  net["Make network requests"]
  secrets["Read secrets in env and settings, including an API key"]
  see["See every prompt and tool call"]
  rewrite["Rewrite a prompt or tool call, submit a prompt, or message another session"]
  approve["Approve a tool call before you are asked"]
  spend["Spend usage"]
  loaded --> files
  loaded --> proc
  loaded --> net
  loaded --> secrets
  loaded --> see
  loaded --> rewrite
  loaded --> approve
  loaded --> spend

Where hooks run and where drawing works

Drawing works in the terminal (including editor terminals and JetBrains) and the Desktop Code tab. Hooks also run in VS Code chat, claude -p, the Agent SDK, and a cloud session the plugin reaches, but nothing draws there. Desktop WSL loads no plugins.

SurfaceHooksDrawing
claude in a terminalyesyes
editor integrated terminalyesyes
JetBrains pluginyesyes
Desktop Code tab except WSLyesyes, except terminal-only elements
Desktop WSLno (plugins unavailable)no
VS Code extension chatyesno
claude -p and Agent SDKyesno
Remote Controlyes, on your machinein that terminal
Cloud sessionyes, if a plugin reaches itno
Hosts: hooks vs drawing
flowchart TB
  host["Where the session runs"]
  term["Terminal, editor terminal, JetBrains: hooks yes, drawing yes"]
  desk["Desktop Code tab except WSL: hooks yes, drawing yes except terminal-only"]
  wsl["Desktop WSL: hooks no, drawing no"]
  vsc["VS Code extension chat: hooks yes, drawing no"]
  pipe["claude -p and Agent SDK: hooks yes, drawing no"]
  remote["Remote Control: hooks on your machine, drawing in that terminal"]
  cloud["Cloud: hooks if a plugin reaches the session, drawing no"]
  host --> term
  host --> desk
  host --> wsl
  host --> vsc
  host --> pipe
  host --> remote
  host --> cloud
Diagram source
flowchart TB
  host["Where the session runs"]
  term["Terminal, editor terminal, JetBrains: hooks yes, drawing yes"]
  desk["Desktop Code tab except WSL: hooks yes, drawing yes except terminal-only"]
  wsl["Desktop WSL: hooks no, drawing no"]
  vsc["VS Code extension chat: hooks yes, drawing no"]
  pipe["claude -p and Agent SDK: hooks yes, drawing no"]
  remote["Remote Control: hooks on your machine, drawing in that terminal"]
  cloud["Cloud: hooks if a plugin reaches the session, drawing no"]
  host --> term
  host --> desk
  host --> wsl
  host --> vsc
  host --> pipe
  host --> remote
  host --> cloud
Drawing works / does not work
flowchart LR
  mod["In-process mod"]
  termOk["Terminal drawing works"]
  deskOk["Desktop Code tab drawing works"]
  vscNo["VS Code chat no drawing"]
  pipeNo["claude -p no drawing"]
  cloudNo["Cloud no drawing"]
  mod --> termOk
  mod --> deskOk
  mod --> vscNo
  mod --> pipeNo
  mod --> cloudNo
Diagram source
flowchart LR
  mod["In-process mod"]
  termOk["Terminal drawing works"]
  deskOk["Desktop Code tab drawing works"]
  vscNo["VS Code chat no drawing"]
  pipeNo["claude -p no drawing"]
  cloudNo["Cloud no drawing"]
  mod --> termOk
  mod --> deskOk
  mod --> vscNo
  mod --> pipeNo
  mod --> cloudNo

Packaging

  • .claude-plugin/plugin.json — no extra required mods fields.
  • hooks/hooks.json with "modules": ["./register.js"].
  • A module that exports register(on).
  • No bundler. Bare import allowed is only claude-code.
  • claude plugin validate lists hooks and API calls without running the code.
Plugin directory layout for a mod
flowchart TB
  root["Plugin directory"]
  manifest[".claude-plugin/plugin.json"]
  hooks["hooks/hooks.json modules array"]
  reg["exports register of on and options"]
  esm["ES module, no Node bundler, no require"]
  root --> manifest
  root --> hooks
  hooks --> reg
  reg --> esm
Diagram source
flowchart TB
  root["Plugin directory"]
  manifest[".claude-plugin/plugin.json"]
  hooks["hooks/hooks.json modules array"]
  reg["exports register of on and options"]
  esm["ES module, no Node bundler, no require"]
  root --> manifest
  root --> hooks
  hooks --> reg
  reg --> esm

Organisation controls

allowManagedModsOnly (managed pluginConfigs on cc-plugin-sec-default@builtin only) blocks every user-brought mod, including one Claude writes mid-session. Organisation mods and built-ins still run. Users cannot undo it.

disableAllHooks in managed settings stops installed mods and settings-file hooks, including a managed PreToolUse, plus status lines and /goal. Skills, commands, agents, and MCP still load. Built-ins are not stopped by disableAllHooks, --bare, or --safe-mode.

CLAUDE_CODE_ENABLE_FUNCTION_HOOKS is ignored from v2.1.287, so 0 does not turn mods off.

Anthropic can turn installed mods off remotely, and no local setting turns them back on.

allowManagedModsOnly blocks user-brought mods
flowchart TB
  brought["Who brought the mod"]
  yours["Counts as yours"]
  orgmod["Organisation mod"]
  blocked["allowManagedModsOnly: a user-brought mod does not load"]
  still["Organisation mods still load"]
  brought --> yours
  brought --> orgmod
  yours --> blocked
  orgmod --> still
Diagram source
flowchart TB
  brought["Who brought the mod"]
  yours["Counts as yours"]
  orgmod["Organisation mod"]
  blocked["allowManagedModsOnly: a user-brought mod does not load"]
  still["Organisation mods still load"]
  brought --> yours
  brought --> orgmod
  yours --> blocked
  orgmod --> still
unverified · GAP allowManagedHooksOnly detail page was not fetched. Named only; do not invent its controls.

Built-ins and samples

NameNote
cc-plugin-agents-mdLoads AGENTS.md.
cc-plugin-diffTakes over /diff.
cc-plugin-plugin-authoringSkill only, no mod code. Off when Anthropic turns installed mods off remotely.
cc-plugin-sec-defaultUsers cannot turn it off.
cc-plugin-telemetryNamed. No further behaviour spelled in the fetch (~).
cc-plugin-you-should-knowOff by default. Enable with /plugin enable cc-plugin-you-should-know@builtin.

Samples, unsupported: token-weather, blast-radius, replay-theater in claude-code-playground. Sample READMEs were not fetched — unverified.

Four layers (3 Oct 2026 landscape)

Products (claude.ai, Cowork, Desktop, Claude Code, API) → official surfaces (CLAUDE.md, skills, settings hooks, MCP, plugins, mods, Agent SDK) → community packs via marketplaces → routers under the client.

Product and surface stack
flowchart TB
  products["Products"]
  surfaces["Official extension surfaces"]
  packs["Community packs via those surfaces"]
  routers["Routers under the client, not Anthropic"]
  products -->|"clients"| surfaces
  surfaces -->|"install through"| packs
  products -->|"may sit under"| routers
Diagram source
flowchart TB
  products["Products"]
  surfaces["Official extension surfaces"]
  packs["Community packs via those surfaces"]
  routers["Routers under the client, not Anthropic"]
  products -->|"clients"| surfaces
  surfaces -->|"install through"| packs
  products -->|"may sit under"| routers

Star counts · unaudited · 3 October 2026

Integers as shown that day. GitHub API returned 403, so no pushed_at or reliable fork counts. Label: unaudited.

RepoStarsNote
anthropics/claude-plugins-official37 348Official marketplace
anthropics/claude-code149 161Official repo
obra/superpowers294 849Author repo named in survey
affaan-m/everything-claude-code272 104Author repo named in survey
wshobson/agents40 174Author repo named in survey
anthropics/skills179 515Marketplace anthropic-agent-skills
agentskills/agentskills25 880Skills spec repo
modelcontextprotocol/servers90 983MCP servers
modelcontextprotocol/mcpb2 129MCPB
thedotmack/claude-mem95 479Persistent memory plugin
musistudio/claude-code-router37 524Community router (CCR)

Gateway versus Claude Code Router

Do not merge. Both can sit in front of Claude Code. They are not the same product.

Two different hops under Claude Code
flowchart TB
  cc["Claude Code"]
  gw["Claude apps gateway"]
  ccr["CCR on 127.0.0.1 port 3456"]
  orgUp["Organisation upstream"]
  prov["Provider the user configured"]
  cc -->|"gateway sign-in"| gw
  cc -->|"ANTHROPIC_BASE_URL"| ccr
  gw --> orgUp
  ccr --> prov
Diagram source
flowchart TB
  cc["Claude Code"]
  gw["Claude apps gateway"]
  ccr["CCR on 127.0.0.1 port 3456"]
  orgUp["Organisation upstream"]
  prov["Provider the user configured"]
  cc -->|"gateway sign-in"| gw
  cc -->|"ANTHROPIC_BASE_URL"| ccr
  gw --> orgUp
  ccr --> prov
Gateway sign-in vs ANTHROPIC_BASE_URL
flowchart TB
  subgraph gateSign["Gateway sign-in"]
    flm["forceLoginMethod gateway"]
    flu["forceLoginGatewayUrl"]
  end
  subgraph otherGw["Other gateway including CCR"]
    base["ANTHROPIC_BASE_URL"]
    keep["Does not replace a saved claude.ai login"]
  end
  flm --> flu
  base --> keep
Diagram source
flowchart TB
  subgraph gateSign["Gateway sign-in"]
    flm["forceLoginMethod gateway"]
    flu["forceLoginGatewayUrl"]
  end
  subgraph otherGw["Other gateway including CCR"]
    base["ANTHROPIC_BASE_URL"]
    keep["Does not replace a saved claude.ai login"]
  end
  flm --> flu
  base --> keep

Claude apps gateway

  • Anthropic’s binary: claude gateway --config gateway.yaml.
  • Organisation-run, OIDC only.
  • Claude Code from v2.1.195; Desktop from server v2.1.203.
  • Upstreams: Bedrock / Claude Platform on AWS / Google Agent Platform / Foundry / Anthropic API.
  • Not a claude.ai session.
  • Spend caps in USD cents need Postgres.
  • Linux server.
  • Sign-in: forceLoginMethod gateway plus forceLoginGatewayUrl.

Claude Code Router (CCR)

  • MIT, musistudio/claude-code-router.
  • Local community router.
  • Default model gateway http://127.0.0.1:3456.
  • Management UI http://127.0.0.1:3458.
  • Routes many agents to many providers, including non-Claude.
  • Anthropic does not support routing Claude Code to non-Claude models through any gateway.
  • ANTHROPIC_BASE_URL points Claude Code at some other gateway, including CCR; that variable alone does not replace a saved claude.ai login.
  • npm @musistudio/claude-code-router 3.1.1 (16 Sep 2026). Tag v3.0.22 was 24 Aug 2026 and is not that npm version.
  • Live CCR config is config.sqlite, not a JSON schema in the current README.

Gaps kept visible

Do not fill these from memory. Each stays labelled unverified.

Spec gaps labelled unverified
flowchart TB
  gaps["Labelled unverified or incomplete"]
  gaps --> classic["classic star list not fetched"]
  gaps --> page["allowManagedHooksOnly page not fetched"]
  gaps --> days["cleanupPeriodDays has no number here"]
  gaps --> guard["Guard hooked event names not given"]
  gaps --> readme["Sample READMEs not fetched"]
  gaps --> shape["Several UI events have no return shape"]
  gaps --> sel["selection is not in the method list"]
Diagram source
flowchart TB
  gaps["Labelled unverified or incomplete"]
  gaps --> classic["classic star list not fetched"]
  gaps --> page["allowManagedHooksOnly page not fetched"]
  gaps --> days["cleanupPeriodDays has no number here"]
  gaps --> guard["Guard hooked event names not given"]
  gaps --> readme["Sample READMEs not fetched"]
  gaps --> shape["Several UI events have no return shape"]
  gaps --> sel["selection is not in the method list"]

Primary sources

Only sources already cited in the research pack. Landscape & gateway: 3 Oct 2026. Mods spec: 4 Oct 2026.

Downloads

Research pack and markdown twins. Gaps and unverified labels are not stripped.

This is a topic landing for the Random carousel. It restates researched facts with dates attached. It is not the mod source and not a complete API catalogue.