mod 是什么:插件里的事件处理函数

按官方文档,mod 是一个改变 Claude Code 外观和行为的插件,由 JavaScript 或 TypeScript 写的事件处理函数组成:Claude 准备调用工具、你提交提示词、界面某个部分要绘制时,Claude Code 就调用对应的函数。 文档把这些函数叫 hook;原来写在 settings 文件里、跑 shell 命令或 HTTP 请求的 hooks,现在改叫 settings hook。

hook 在 Claude Code 处理事件之前运行,由它决定接下来发生什么:

  • 观察:记下发生了什么,事件照常继续,比如统计工具调用次数;
  • 改写:先改动事件再放行,比如在 spinner 文字后面加上计数;
  • 接管:自己处理事件,原本的行为不再运行,比如拒绝一条命令。

hook 要做自身代码以外的事(画界面、加命令、调用模型、读文件、联网等)只能通过 mods API,也就是代码里的 $;正因为只有这一个出口,Claude Code 才能在安装前列出一个 mod 会做什么。 几个 mod 处理同一事件时按加载顺序执行:最先加载的最先看到事件、最后拿到结果,不同作者的 mod 因此可以叠加。

Claude Code 自己的部分功能也已经是 mod,比如 /diff 由内置的 cc-plugin-diff 绘制面板,可以在 /plugin 里停用(/diff 会退回原来的内置版本),也可以换成你自己的。Anthropic 表示会逐步把更多内置功能改成 mod。

mods 能做、hooks / Skills / MCP 做不到的事

settings hook、skill、状态栏和 MCP 服务器都在 Claude Code 外部工作:要么跑一个脚本,要么给 Claude 一段文字或几样工具。mod 在 Claude Code 内部运行,所以多了这些本事:

  • 画一个能操作的界面:对话旁的面板或提示框上方的信息带,带标签页、按钮和输入框;
  • 重画 Claude Code 自己的界面:比如工具调用那一行、spinner、Claude 向你提问的对话框;
  • 介入工具调用或请求:先扣住工具调用问你、不运行工具直接给结果,或把某次请求发给另一个模型;
  • 在命令上跑自己的代码:/命令直接执行你的函数,不占 Claude 的回合,Claude 干活时也能用;
  • 在 hook 之间共享数据:同一文件里的变量共用,一个 hook 记录,另一个 hook 展示。

官方博客举的例子还有:在提示词送到模型前改写它、重试一次工具调用、批准或拒绝权限请求、在 Claude 读到工具输出前抹掉其中的密钥。官方文档的对比表:

ModSettings hookSkillMCP 服务器
是什么插件里的函数,由 Claude Code 在自己的进程里调用在生命周期事件上运行的 shell 命令、HTTP 请求或提示词一份写给 Claude 读的 SKILL.md 说明给 Claude 提供工具的外部进程或服务
能改什么工具调用、提示词、命令、回合,以及界面画什么工具调用或提示词放不放行、工具调用的参数和结果、补充给 Claude 的上下文Claude 知道什么、做什么Claude 有哪些工具
能在界面上画东西能不能不能不能
用什么写JavaScript 或 TypeScript一个脚本加 settings.json 里的一条配置Markdown任意语言写的服务
什么时候选它想要面板、提示框上方的信息带、自定义命令,或要改写事件手上已有脚本,想拦截、放行或记录事件同样的说明总在反复粘贴进对话Claude 需要连上外部系统

一个插件可以同时装这几样,mod 可以和 skill、MCP 服务器放在同一个插件里发布。官方建议:settings hook、skill 或 MCP 已经能做到的,先对照上表再决定写不写 mod。 不熟悉这几样,可以先看 Hooks 与 Subagents、Skills 和 MCP 教程。

开始之前:版本要求

  • 终端:Claude Code v2.1.287 或更高,运行 claude --version 查看,版本低就先更新。
  • 桌面 App:App 自带一份 Claude Code,从 v2.1.286 起支持 mods;在 Code 标签页的本地会话里输入 /status,看 Claude Code 那一行。
  • 默认开启:早期体验时设置过 CLAUDE_CODE_ENABLE_FUNCTION_HOOKS 的,把它删掉——v2.1.287 起会忽略这个变量,设成 0 也关不掉 mods。
  • 看加载了哪些 mod:输入 /plugin,标签页下方的灰字会写 1 mod active · first-mod 这样的数量和名字(不含内置 mod)。

先玩官方示例:三个现成的 mod

Anthropic 在 GitHub 仓库 anthropics/claude-code-playground 的 claude-code/mods 目录放了示例 mod,每个都是完整插件,README 写了它是怎么做出来的。仓库按原样提供,不提供支持。

  • token-weather:在提示框上方画出你上下文窗口的「天气预报」
  • blast-radius:遇到有风险的 shell 命令(比如 rm -rf 或强制推送)先扣住,显示它会改动什么,再给你继续或取消两个按钮
  • replay-theater:新增一个 /replay 命令,一步步回放 Claude 上一轮对文件做的修改

想试一个,clone 仓库后用 --plugin-dir 加载某个 mod 的目录,只在本次会话生效;想长期用,把 clone 下来的 claude-code/mods 目录添加为插件市场,再从 claude-code-playground-mods 安装:

# 试一次:clone 仓库,只在本次会话加载某个示例
git clone https://github.com/anthropics/claude-code-playground
claude --plugin-dir ./claude-code-playground/claude-code/mods/token-weather

# 长期用:在 Claude Code 会话里把目录添加为插件市场,再安装
/plugin marketplace add ./claude-code-playground/claude-code/mods
/plugin install token-weather@claude-code-playground-mods

市场指向你本地的副本,副本移走或删掉,mod 就不再加载。示例同样以你的权限运行,加载前先按后文「安全」一节看看它要做什么。

最省事:让 Claude 帮你写

在交互式会话里用你自己的话描述想要的 mod,Claude 就会写。它依据内置的 plugin-authoring skill,里面写明了 mod 放在哪、你的版本有哪些事件和方法、怎么加载;需要时会自动加载,也可以输入 /plugin-authoring 手动加载。

  1. 描述需求,比如「做一个在提示框上方显示当前 git 分支的 mod」。Claude 会把它写进本会话专属的目录 ~/.claude/dev-mods/(后接会话 ID)。~/.claude 是受保护路径,default 和 acceptEdits 模式下每建一个文件都会先问你。
  2. 决定热重载:Claude 保存第一个文件时,Claude Code 会问是否为本会话开启热重载。选 Enable for this session,mod 在本轮结束时加载,之后每轮改动都自动重载;选 Not now,文件留着,下次启动这个会话时再加载。
  3. 确认并试用:/plugin 里按 Tab 切到 Installed 能看到它,也能在这里关掉;效果不对就告诉 Claude 改哪里,本轮结束即重载。

注意:Claude 写的 mod 只在写它的会话里加载,目录超过 cleanupPeriodDays 会被清掉,想保留就复制出来(如 ~/mods/git-branch),以后用 claude --plugin-dir ~/mods/git-branch 加载。 没人能批准的会话(claude -p、dontAsk 模式)、未信任的工作区、用 --safe-mode 或 --bare 启动、设了 disableAllHooks 或被组织托管设置禁止时,它不会加载。让 Claude 写 mod 本身也在消耗你的套餐额度。

自己写第一个 mod:三个文件

照官方教程做一个 first-mod:统计 Claude 调用工具的次数,显示在 spinner 旁边,再加一个 /tally 命令。不需要 Node.js、打包工具或构建步骤,Claude Code 直接加载 .js 和 .ts 文件。 最小的 mod 就三个文件:.claude-plugin/plugin.json、hooks/hooks.json、hooks/register.js。

first-mod/
├── .claude-plugin/
│   └── plugin.json
└── hooks/
    ├── hooks.json
    └── register.js

第 1 步,建目录:

mkdir -p first-mod/.claude-plugin first-mod/hooks

第 2 步,插件清单 first-mod/.claude-plugin/plugin.json,mod 不需要额外字段;名字别像 Anthropic 自己的(比如以 claude- 开头),否则校验不通过:

{
  "name": "first-mod",
  "version": "0.1.0",
  "description": "Counts Claude's tool calls, shows the count beside the spinner, and adds a /tally command",
  "author": { "name": "Your Name" }
}

第 3 步,first-mod/hooks/hooks.json 里的 modules 指向代码文件(相对 hooks.json,只写一个)。有这个键,插件才算 mod:

{
  "description": "The first-mod hooks module",
  "modules": ["./register.js"]
}

第 4 步,写代码 first-mod/hooks/register.js。mod 加载时,Claude Code 调用你导出的 register 并传入 on,每调用一次 on 就给一个事件注册一个 hook:

// 几个 hook 共用的计数
let calls = 0

// mod 加载时,Claude Code 调用一次 register
export function register(on) {
  // 会话开始时注册 /tally 命令,然后照常放行(观察)
  on('session.start', async ($, e, next) => {
    await $.command.register({
      name: 'tally',
      description: 'Show how many tool calls Claude has made',
    })
    return next(e)
  })

  // Claude 每次要用工具时加 1,并请界面重画(观察)
  on('tool.call', async ($, e, next) => {
    calls += 1
    $.ui.invalidate('ui.render')
    return next(e)
  })

  // 只在输入 /tally 时运行,自己返回文字(接管)
  on('command.run', { command: 'tally' }, async () => {
    return { text: 'Claude has made ' + calls + ' tool calls since this mod loaded' }
  })

  // 保留原来的 spinner,在后面加上计数(改写)
  on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
    return next({ ...e, props: { ...e.props, suffix: ' · tool calls: ' + calls + '…' } })
  })
}

每个 hook 拿到三个参数:$ 是 mods API,e 是事件内容(比如工具名和参数),next 把事件交给后面的 mod 和 Claude Code 自己的处理并返回结果。session.start 和 tool.call 是观察,最后都 return next(e);command.run 是接管,自己返回结果、不调用 next,{ command: 'tally' } 是只对 /tally 生效的过滤器;ui.render 是改写,把加了计数的事件副本交给 next。

第 5 步,加载并试用:

# 只在这一次会话加载 first-mod
claude --plugin-dir ./first-mod

# 不进交互界面,直接测 /tally
claude -p "/tally" --plugin-dir ./first-mod
# 输出:first-mod: Claude has made 0 tool calls since this mod loaded

让 Claude 做几件要用工具的事(比如 list the files here and read the README),spinner 会显示 Thinking · tool calls: 2… 这样递增的数字;再输入 /tally,会看到 first-mod: Claude has made 2 tool calls since this mod loaded(数字以你的为准)。命令列表里没有 /tally,就是模块没加载上。

第 6 步,边跑边改:会话别关,把 ' · tool calls: ' 改成 ' · tools used: ' 并保存,对话里会提示 first-mod 已重载,下一次 spinner 就是新文字。用 --plugin-dir 加载的目录一改就热重载,重载会重新运行 register,所以计数归零。

想用 TypeScript:文件改名为 register.ts,modules 写成 ["./register.ts"] 即可。用 --plugin-dir 加载时,Claude Code 会在 mod 目录的 .claude-plugin/types/ 里写入与你当前版本一致的 .d.ts 类型声明,编辑器就能补全和类型检查。事件和方法会随版本变化,网页文档和类型文件不一致时,以类型文件为准。

安装、校验、测试、关闭与分享

安装。mod 以插件形式从插件市场安装:会话里用 /plugin install <plugin>@<marketplace>,终端里用 claude plugin install <plugin>@<marketplace>。在终端装好时会话还开着,就在会话里运行 /reload-plugins,否则下次启动生效。

校验。claude plugin validate 不运行你的代码,只做 Claude Code 加载 mod 时同样的检查和静态分析:hooks: 一行列出处理的事件(花括号里是过滤条件),calls: 一行列出调用的每个 mods API 方法,读写环境变量的还会多出 env reads: / env writes:。first-mod 的结果:

claude plugin validate ./first-mod

  ❯ ./register.js hooks: session.start, tool.call, command.run{command=tally}, ui.render{component=Spinner}
  ❯ ./register.js calls: $.command.register, $.ui.invalidate

✔ Validation passed

想处理的事件没出现在 hooks 一行,那个 hook 就不会被调用,多半是事件名拼错(会报 "tool.calls" is not an event 这样的错)。另外 $ 的调用要写全(如 $.store.get('notes')),不要赋给变量或解构,事件名要写成字符串字面量,否则校验不过。

测试。claude plugin test 不需要会话、登录或网络,就能跑 mod 的自动化测试:触发事件,再检查 hook 做了什么。

关闭。按范围选:

  • 关一个:在 /plugin 的 Installed 标签页停用或卸载它所在的插件;
  • 本次会话全关:用 --safe-mode 启动,其他自定义也会一起关;
  • 所有会话全关:在 ~/.claude/settings.json 里设 "disableAllHooks": true,settings hooks 和自定义状态栏也会停,组织托管的照常运行。

这些开关不影响内置 mod(如 /diff),内置的要在 /plugin 里单独停用。

分享。给几个人用就发目录或 zip;团队放进自己的插件市场(比如一个私有仓库);全组织由管理员用托管设置安装;公开就公开市场仓库,或提交到 Anthropic 的插件目录。 开发时一直用 --plugin-dir 指向目录:已安装的插件按版本缓存,不升版本号重装,改动不会生效。分发细节见 Claude Code Plugins 指南。

安全:一个 mod 能碰到什么

官方博客说得很直接:mods 和 Claude Code 本身一样能访问你的电脑,不在沙箱里,只装信任来源的,就像在电脑上装任何代码一样。文档列出 mod 加载后能做的事:

  • 以你的身份操作电脑:读写你的账户能访问的任何文件、启动程序、发网络请求;
  • 读到你的密钥:环境变量和设置文件,包括放在里面的 API key;
  • 看到整个会话:你发的每条提示词、Claude 的每一次工具调用;
  • 改动会话:改写提示词或工具调用、像你亲手输入一样提交提示词、给你的另一个会话发消息;
  • 不问你就行动:在你被询问之前批准一次工具调用;
  • 花你的额度:用你的套餐或 API key 调用模型。

开了 sandboxing 也一样:沙箱只隔离 Claude 运行的 Bash 命令,mod 启动的进程在沙箱外(见沙箱指南)。会批准工具调用的 mod,能批准本该由 ask 规则弹窗询问、或被你自己的 PreToolUse hook 拦下的调用。 mod 唯一改不了的是权限确认框:它能重画大部分界面,但改不了权限提示显示给你的内容。

  1. 只从信任的作者和插件市场安装。
  2. 装之前先拿到插件文件(比如 clone 仓库),运行 claude plugin validate ./some-mod,看 hooks、calls 两行列出的事件和调用,和它声称的功能对不对得上。
  3. 留意 API key:mod 读得到环境变量;另外帮助中心提醒,设置了 ANTHROPIC_API_KEY 时 Claude Code 会改用这个 key、按 API 计费,而不走订阅额度。
  4. 怀疑某个 mod 有问题,先用 --safe-mode 启动排查。

mod 在哪些地方生效

hook 在任何加载了这个插件的会话里都会运行;但 mod 画出来的面板、信息带和替换过的行,只有终端和桌面 App 会显示:

在哪里运行 Claude Codehook 会运行mod 画的界面会显示
终端里的 claude(含编辑器内置终端、JetBrains 插件)是是
桌面 App 的 Code 标签页(WSL 会话除外)是是,标为仅限终端的元素除外
桌面 App 里的 WSL 会话否,WSL 会话不支持插件否
VS Code 扩展的聊天面板是否
claude -p 与 Agent SDK是否
从 claude.ai 或手机 App 用 Remote Control是,在你电脑上的会话里运行显示在你电脑的终端里
云端会话是,前提是插件能带到云端会话否

会画界面的 mod 可以判断自己跑在哪个应用里,在不显示界面的地方退回成对话里的一行文字或命令的文字回复。所以给 VS Code 用户或 CI 里的 claude -p 写 mod 也有意义:拦截、记录这类不靠界面的逻辑照样运行。

团队和企业:管理员怎么管

  • 沿用插件管控:管理员可以放行或拦截插件市场;Team 和 Enterprise 由所有者在管理后台设置,用 Claude API 或第三方 API 的,由管理员把托管设置推送到成员电脑。
  • 内置守卫 sec-default:在 Team、Enterprise 和有托管设置的电脑上,这个内置 mod 最先加载,阻止用户自己装的 mod 做高风险的事,比如绕过权限 deny 规则;管理员让自己的 mod 先加载时,要把 sec-default 加进列表才能保留它的限制。
  • 只允许组织的 mod:组织设置 allowManagedModsOnly 后,用户自己的 mod 不再加载;它和 disableAllHooks 一样只停 mod,插件里的 skills、命令、agents 和 MCP 服务器照常加载。
  • 团队用法:官方举的例子有对话旁的面板显示 CI/CD 状态、命令碰生产配置前必须确认、一个最先加载的 mod 记录其他 mod 的每次调用用于审计。

托管设置的写法可参考Claude Code 企业配置指南。

该用哪档套餐:谁该买什么

mods 不单独收费,官方文档对它只写了版本要求。但它跑在 Claude Code 里,而按 Anthropic 定价页,Claude Code 包含在所有付费套餐里(个人用户就是 Pro 和 Max),Free 没有;它和网页、桌面、手机端共用一份额度——写代码、让 Claude 写 mod、mod 调用模型,扣的都是这一份。

本站 Claude 现价(随下单页实时更新)
  • 想试 mods、平时偶尔用 Claude Code:Pro 就够,代充 ¥249。写个 first-mod、装一两个示例,用不了多少额度。
  • 每天让 Claude Code 跑任务、Pro 常撞上限:帮助中心建议升 Max 5x(官方 $100/月,每个会话的额度约为 Pro 的 5 倍),代充 ¥999。
  • Max 5x 也常不够:再升 Max 20x(官方 $200/月,约为 Pro 的 20 倍),代充 ¥1,799。Max 的会话额度每 5 小时重置,另有每周上限。
  • 公司团队:要统一管控插件市场和 mod,走官方 Team / Enterprise。

代充还是成品号。代充开通在你自己的账号上:下单页粘贴 claude.ai 的 Cookie-Editor JSON,付款前系统预检,通常 5–30 分钟到账,凭证只用一次、交付后清除。Max 代充要求账号能正常登录、没被封;从没用银行卡开过会员的 Free 账号不能买 Max;新注册的号要等 3–15 天才能充 Max 20x。 不符合就买成品号:一单一个账号、只给你一人用,按商品说明可绑定自己的邮箱;付款后填收件邮箱并点击 Cloudflare 发来的验证邮件,Max 成品号人工发货,订单页显示 30 分钟到约 4 小时;Pro 成品号收到后在订单页提交 Organization ID。 之后在 Claude Code 里用同一个 Claude 账号登录即可。详见成品号怎么买、靠不靠谱和Max 5x 还是 20x。

续订与退款。每单 30 天,到期前 7、3、1 天提醒;成品号在个人中心 → 订单历史 →「续订」,按同档代充价计费;代充到期直接下新单。因 Anthropic 区域政策调整导致服务不可用的,按未使用天数退款;因违反 Anthropic 使用政策被封号的不退款;退款 1 个工作日内处理。 有问题请及时联系右下角在线客服(8:00–23:00),也可以发邮件到 support@claudemax.shop。

ClaudeMax 不是 Anthropic 官方,也不是授权经销商;自 2024 年 11 月运营至今,累计服务超过 20,000 名用户(我们自己的统计),有 ICP 备案。本文按 2026-10-07 核对的官方文档写成,mods 的事件和接口以官方最新文档为准。