我们刚刚为 Claude Code 添加了 Mods(插件)功能。通过 Mod,你可以直接更改 Claude Code 本身的工作方式:改变其渲染内容、提示词输入、工具调用,甚至添加自定义的用户界面(UI)、技能和命令。你可以对这些功能进行极具创意的发挥。例如,我一直希望能更清晰地看到上下文信息,所以我制作了一个 Mod,在提示框上方实时显示上下文的详细分解。
我还希望看到项目中所有的智能体(Agent),而不仅仅是正在运行的那些。因此,我创建了一个 Mod,将所有 Agent 列在侧边栏中,只需单击一次即可启动它们。此外,我在录制视频时不希望屏幕上出现任何电子邮件地址,所以我制作了一个 Mod,在鼠标悬停前隐藏这些邮箱。
Mod 本质上就是一种插件。它使用相同的 plugin.json 和 hooks.json,唯一的区别是 hooks.json 多了一个名为 modules 的键。该键指向一个 TypeScript 文件,这个文件就是实际的 Mod。在这个文件中,你可以编写在 Claude Code 内部运行的函数。Claude Code 有几十个内部事件,例如工具调用、权限检查、消息渲染和提交提示词等。你可以将这些函数注册到特定事件上,每当该事件触发时(在 Claude Code 执行其默认操作之前),这些函数就会运行。
如果你曾经使用过 Express,这基本上就是内置在 Claude Code 中的中间件机制。这个函数始终接收相同的三个参数:第一个是 $(美元符号)对象,通过它你可以与 Claude Code 进行交互。渲染 UI、调用模型、读取文件等操作都挂载在这个对象上。第二个参数是事件本身,即当前正在发生的实际数据。你可以在函数体中修改这些数据,然后再将其传回给 Claude Code。
第三个参数是 next(下一个),用于传递数据。这就是中间件部分:你传递给 next 的内容就是 Claude Code 实际执行的操作。例如,如果你修改了命令,那么运行的是被修改后的命令。不过你不必调用 next;如果不调用 next 而是直接返回结果,则由你自己处理该事件,Claude Code 将采用你的答案而不是执行其默认操作。
综上所述:$对象是你与 Claude Code 的连接通道,事件告诉你发生了什么,而 next 决定 Claude Code 最终如何处理这些信息。要加载 Mod,你可以使用 --plugin-dir 标志指定文件夹来启动 Claude Code。桌面应用不支持命令行参数,因此你可以将该文件夹添加到全局设置文件中即可。该文件夹会被监听,每次保存文件时,当前会话都会立即生效。
现在我们来构建一个 Mod。让我们以开头提到的隐藏邮箱为例,实际演示如何开发它。我的需求是:每当 Claude 回复中包含电子邮件地址时,除非鼠标悬停,否则在屏幕上隐藏该地址。渲染回复是 Claude Code 的内部事件之一(render 事件),因此我将函数注册在该事件上。此时的事件数据是回复文本在显示到屏幕之前的原始内容。
对于每一个电子邮件地址,我通过 $对象构建一个小的代码块,使其仅在悬停时显示文本。我没有调用 next,而是直接返回这个新构建的代码块,这样 Claude Code 就会渲染我提供的版本。现在,当我询问 Claude Sam 的邮箱时,电子邮件地址仅在鼠标悬停时才显示出来。
然而,当我随后要求 Claude 撰写消息时,它仍然使用真实的电子邮件地址,因为模型渲染仅改变屏幕显示内容。这意味着模型从未看到过我隐藏的版本。Mod 只能访问 Claude Code 暴露的事件,并在其自己的沙箱中运行,所有操作都必须通过 $对象进行。由于 Mod 本质上就是插件,你也可以将其作为插件分享。你可以将它发布到市场仓库中,用户就可以像安装其他任何插件一样安装它。