大数跨境

Claude Code Mods:当 AI 编程工具开始允许你改造运行机制

Claude Code Mods:当 AI 编程工具开始允许你改造运行机制 运维开发与AI实战
2026-10-06
6
导读:从四个官方内置 mod 出发,解释函数式 hooks 的调用链、它与 Skills 和 MCP 的关系,以及可定制工作台背后的权限与维护成本。

使用 AI 编程工具时,我们已经习惯给它写规则、安装 Skills、连接 MCP。但还有一些需求,靠这些办法很难自然地完成:让代码差异始终显示在对话旁边;在用户提交问题时加入选定文件的修改;把团队规定的检查放进每次操作的执行路径。

Claude Code 的 Mods 把扩展能力推进到了这些位置。开发者可以用 JavaScript 或 TypeScript 处理运行事件,介入工具调用、提示词和界面绘制。对使用者来说,它意味着工作台可以按任务改造;对维护者来说,它也意味着插件开始参与执行过程。

先交代一个容易踩坑的版本差异:截至 2026 年 10 月 6 日,官方 mods/README.md 仍保留 Early access 提示,当前官方文档已说明,终端从 v2.1.287 起默认开启 mods,Desktop 内置 Claude Code 从 v2.1.286 起支持。旧的 CLAUDE_CODE_ENABLE_FUNCTION_HOOKS 变量在 v2.1.287 及以后已被忽略。本文以当前官方文档解释使用方式,以仓库源码解释内置功能;具体 API 应以本机 /plugin-types 生成的声明为准。来源:仓库说明、当前启用方式、版本对应的 API

1. Mod 是什么?先把它放回插件体系

Mod 仍然用 Plugin 的方式组织和分发。它有普通插件的 .claude-plugin/plugin.json,在 hooks/hooks.json 中通过 modules 指向一个代码入口,入口导出 register(on, options),再用 on 注册事件处理函数。一个插件可以同时包含 mod、Skills 和其他组件,所以这些概念并不互斥。来源:Mod 文件结构

为了避免混淆,可以按“需要改动什么”来选择:

需求
优先考虑
工作方式
让 Claude 按团队流程做代码审查
Skill
提供模型读取的指令和参考材料
让 Claude 查询工单、数据库或外部系统
MCP
提供可调用的工具和数据连接
工具调用前后运行已有检查脚本
Settings hook
在生命周期事件上执行配置的处理器
在对话旁显示交互面板,改造命令或事件处理
Mod
在 Claude Code 内部执行函数式 hooks
把这些能力一起安装给团队
Plugin
作为组件的打包和分发单位

这张表是选型入口,不代表能力完全没有重叠。已有 settings hooks 也能阻止调用、改变参数或提供上下文;mods 的特别之处,在于内部事件、共享状态和界面扩展可以组合成一个持续运行的功能。来源:官方扩展机制对比

因此,如果只是把代码审查提示词重复输入的问题,写一个 Skill 通常就够了。只有当需求落在执行路径或工作台交互上,才值得承担 mod 的代码和兼容性成本。

2. 核心机制:事件经过一条可以介入的调用链

一个函数式 hook 通常接收三个参数:

  • $:mods API,用于读取文件、操作界面、注册命令等。

  • e:当前事件的输入,例如工具名及调用参数。

  • next:把事件交给后续处理器,并取得处理结果。

关键是 next。return next(e) 表示继续原有流程;传入修改后的副本,可以改写输入;不调用 next 而返回该事件允许的结果,则会在这一层处理事件,使后续链条不再运行。await next(e) 之后还可以处理返回值。e 本身是深度冻结的数据,不能直接修改。来源:函数式 hooks 与返回方式

下面的机制示意省略了组织层级和具体事件的权限检查。沿蓝色路径向下看,事件通过 mod 到达引擎;右侧橙色分支表示 mod 自己回答,流程在这里结束。

Mod 可以把事件传给后续处理器,也可以在本层回答并结束这条调用链。

对写过 HTTP 中间件的人来说,这个结构很熟悉。但它处理的对象更广:工具调用、用户输入、命令、模型请求和界面绘制都有对应事件。各事件允许返回的结构不同,不能把 tool.call 的拒绝格式随意搬到其他事件上。来源:事件参考

这会带来一个直接后果:插件加载顺序会影响最终行为。 前面的 mod 若改写了输入,后面的 mod 看到的是改写后的输入;前面的 mod 若直接回答,后面的处理器可能完全收不到事件。因此,把日志 mod 放在链条末尾,不等于它一定能记录每一次原始操作。

3. 四个内置 mod,展示了四种不同的改造

用户给出的官方仓库,目前原始 README 列出四个内置 mod:diff、agents-md、sec-default 和 telemetry。这里公开的是随 Claude Code 构建的源码;仓库说明明确说,它们没有列入该仓库的 marketplace,实际使用的是客户端随附的版本。来源:内置 mods 目录

diff:把检查修改接到正在进行的工作里

/diff 展示未提交的文件修改,并在 Claude 编辑文件或运行命令后刷新。在支持停靠的布局中,它可以显示在对话旁;界面和终端宽度会影响具体呈现。

一个尤其有意思的细节是文件的 ask 按钮:选中的文件差异可以随下一条输入加入上下文,用过一次后解除。这让“看到修改”和“针对修改提问”连接起来。它还支持不同的比较基准,以及查看某个较早回合的编辑。来源:diff 的行为与事件

这个例子的启发在于交互距离:用户不用在另一个窗口复制 diff,再切回对话解释自己在问哪一段。当然,差异面板展示了修改,并不意味着修改已经通过测试或审查。

agents-md:把项目指令文件接入上下文构建

agents-md 让 AGENTS.md 进入 Claude Code 的项目指令加载过程。当前源码提供四种 instructionFiles 模式:只用 CLAUDE.md、没有项目自身 Claude 指令文件时回退到 AGENTS.md、两者一起加载、以及 managed-only。

默认回退并非“每个目录里没有 CLAUDE.md 就自动补一个 AGENTS.md”那么简单。源码会判断项目自身是否已有 Claude 指令文件,其中也包括 .claude/CLAUDE.md 和 CLAUDE.local.md。选择共同加载后,也需要处理重复导入和两份规范内容冲突的问题。来源:agents-md 加载规则

对同时使用多种编程 agent 的团队,这提供了共享项目规范的入口。但统一文件名只是第一步;不同工具的加载时机和指令边界,仍需分别确认。尤其不能把 managed-only 理解为绝对不会出现项目指令:该 mod 的说明保留了引擎在 Read 时附加嵌套 CLAUDE.md 的限制。

sec-default:守住组织配置与个人插件之间的边界

当个人插件可以改写事件时,组织原本设定的规则也可能进入可改写的路径。sec-default 的职责是维持既有边界,让受保护的组织 hooks、指令、设置和工具政策不受个人插件改写;它本身不额外制定业务政策。

源码采用跳过个人插件层、拒绝特定来源以及放行等操作。它在有 managed settings 的机器,或相应 Team、Enterprise 组织场景中位于外层,具体还受 managed prependPlugins 配置影响。来源:sec-default 的保护范围与位置

这说明权限治理已经成为扩展设计的一部分。不过,这一层保护并不等于 mod 获得了操作系统沙箱,后文会解释这个区别。

telemetry:把内部观测能力做成可组合接口

telemetry 在需要时通过 engine.create 加入 $.telemetry,处理 log、mark 等事件,让其他内置功能记录使用情况。它还把接口类型保存在自己的 types/index.d.ts,供实现者和调用者使用同一份契约。

这里有两个边界:当前实现服务于内置插件,拒绝安装插件的调用;当 Claude Code 自身分析被关闭时,也不发送这些分析数据。因此,不宜把它介绍成第三方作者可以随意使用的通用埋点服务。来源:telemetry 的调用者限制和发送条件

四个例子放在一起,可以看到 mods 已经覆盖用户交互、上下文加载、组织政策和内部服务。我的判断是,Anthropic 正在把一部分原有产品行为放到同一种扩展结构里,让它们更容易被阅读、组合和维护;这并不足以证明整个 Claude Code 内核都能由插件替换。

4. 一个小例子:统计到达 mod 的文件编辑请求

下面用一个克制的示例说明代码形态:统计到达该 mod 的 Edit、Write 请求,用 /edit-count 显示计数。它不修改调用参数,也不调用文件或网络 API。

三个文件分别是:

.claude-plugin/plugin.json:

{
  "name": "edit-counter",
  "version": "0.1.0",
  "description": "Count Edit and Write requests received by this mod"
}

hooks/hooks.json:

{
  "modules": ["./register.js"]
}

hooks/register.js:

export function register(on) {
  let edits = 0;

  on('session.start', async ($, e, next) => {
    await $.command.register({
      name: 'edit-count',
      description: '显示本次模块加载后的编辑请求数',
    });
    return next(e);
  });

  on('tool.call', { tool: ['Edit', 'Write'] }, async ($, e, next) => {
    edits += 1;
    return next(e);
  });

  on('command.run', { command: 'edit-count' }, async () => ({
    text: '收到的编辑请求:' + edits,
  }));
}

这里统计的是请求数:后续拒绝或失败的调用仍可能计数,前面的 mod 已经截断的请求则不会到达这里。它也没有把主会话和子 agent 分开统计。模块重新加载后,内存计数归零,因此不能把它当作持久审计记录。接口依据:命令注册、matcher 和调用链

在支持 mods 的客户端中,可以先查看结构和能力声明,再加载目录:

claude --version
claude plugin validate ./edit-counter
claude --plugin-dir ./edit-counter

进入交互会话后,用 /plugin 确认加载,再运行 /edit-count。编写 TypeScript 时,在该会话执行 /plugin-types 获取本机声明;有测试文件时用 claude plugin test ./edit-counter 运行。validate 展示和检查声明的 hooks、API 调用,不替代行为测试或人工审查。来源:创建与加载流程、测试机制

这是按当前官方接口编写的教学示例。本文工作环境安装的是 v2.1.218,低于当前文档的终端门槛,因此没有在本机宣称运行验证,也没有自动升级客户端。

5. 扩展了运行机制,也扩大了信任范围

讨论 mods 时,最容易产生的误解是:“它只能通过 $ 调用宿主接口,所以应该很安全。”

源码声明的确说明,hooks 模块没有通常的 Node、DOM 环境,对外操作要走宿主 API。这让 Claude Code 能提前识别模块调用了哪些接口。但受控的接口入口和受限的操作权限,是两件事:能识别 $.fs.read,不代表只允许它读当前项目。来源:模块运行环境、mods API

看下面的边界示意:左侧蓝色路径表示 Claude 发起的工具调用;右侧橙色路径表示 mod 自己启动进程。两者最后都可能触及文件或网络,但经过的控制不同。图中的 Bash 沙箱仅指启用沙箱后 Claude 运行的 Bash 命令。

Claude 的工具调用与 mod 自己启动的进程经过不同控制,工具权限规则不能自动约束 mod 的全部行为。

官方管理文档明确指出,mods 没有沙箱,能以用户权限读写文件、启动进程和访问网络。sec-default 加载时默认守住 Claude 工具调用上的 deny 规则,但 Read(.env) 被禁止,不等于 mod 无法用 $.fs.read 读取同一文件。mod 启动的进程也不受 Claude Bash 沙箱隔离;要限制 mod 自身的 API 调用,需要阻止它加载,或用组织 policy mod 管理对应调用。来源:组织控制的实际边界

所以,选择 mod 时需要审查的对象包括源码、来源及更新,而不只是它在界面上展示了什么。一个看起来只显示 token 用量的面板,如果还声明了启动进程、读取环境变量或发送网络请求,应当有与功能相符的解释。

这也让 claude plugin validate 的 hooks、calls 输出有了实际价值:它可以帮助缩小审查范围。不过,接口列表不会自动判断外发的数据是否恰当、写文件的路径是否合理,或者业务规则是否正确。

6. 值得期待的,是更贴近任务的工作台

从这些已公开的机制出发,我认为 mods 的价值会首先出现在三类需求中。以下是基于能力的应用推演,并非都已成为官方内置功能。

第一类是把审查对象放到操作旁边。diff 已经展示了这种路径。类似地,团队可以把待审文件、测试状态或相关上下文放在面板里,让用户针对具体对象采取动作。收益取决于是否减少了查找和切换;面板越多,不代表工作越清楚。

第二类是让已有流程在正确时机出现。 一个 Skill 可以告诉 Claude:“部署前检查变更范围。”Mod 则可以在相关事件发生时执行程序逻辑,必要时停下来询问。代价是团队必须处理调用链顺序、失败、超时和不同调用入口,而不能只写一段理想情况下工作的代码。

第三类是根据项目塑造工作环境。 数据分析、基础设施变更和前端开发,适合看到的状态与操作入口并不相同。可编程界面让这种差异有机会直接进入工作台。但 UI 能力存在客户端差异:当前文档中,终端和 Desktop 可显示 mod 界面,VS Code 聊天面板以及 claude -p 等运行位置不显示这些绘制结果。面向团队的 mod 需要为这些场景提供文本或命令退路。来源:各运行位置的支持范围

同时还要留意一个成本:mod 的普通程序逻辑不必调用模型,但它可以通过 $.model.complete 额外使用模型,也可以改变发送给模型的上下文。它究竟节省多少操作、增加多少延迟和用量,要根据具体实现测量,不能由“用了 mods”直接推得。来源:mod 的模型调用

7. 从哪个需求开始,决定了它是否值得维护

如果准备试用,先找一个足够具体的问题:反复切换窗口检查 diff、希望在一次操作前展示影响范围,或者需要团队统一的交互入口。用一个只观察事件的小 mod 开始,通常更容易看清它收到什么、何时运行,以及在哪些客户端起作用。

如果已有 Skill、settings hook 或 MCP 能完整解决问题,继续使用它们就很合理。引入 mod 后,需要长期维护的是代码行为、加载顺序、数据访问和客户端兼容性;这些成本应当由明确的工作收益来承担。

对我来说,mods 最值得关注的变化,是 AI 编程工具开始允许开发者把自己的流程写进运行环境。团队既可以决定 Claude 应当读取哪些规范,也可以决定用户在操作时看到什么、哪些事件由程序处理、哪些步骤需要继续传给引擎。

接下来值得观察的,不只是出现多少新面板,而是团队能否把这些可定制行为做得可解释、可审查,并且在更新后仍然可靠。

【声明】内容源于网络
0
0
运维开发与AI实战
DevSecOps工程师,分享AI, Web3, Claude code开发的经验与心得。希望能帮大家解决技术难题,提升开发效率!自身从与大家的沟通中获得进步,欢迎留言交流,一起成长!
内容 2540
粉丝 0
运维开发与AI实战 DevSecOps工程师,分享AI, Web3, Claude code开发的经验与心得。希望能帮大家解决技术难题,提升开发效率!自身从与大家的沟通中获得进步,欢迎留言交流,一起成长!
总阅读68.5k
粉丝0
内容2.5k