Claude Code Mods 入门:从零构建你的第一个插件

Mod 是运行在 Claude Code 会话中的小型 JavaScript 或 TypeScript 文件。它可以观察会话中发生的事、修改 Claude Code 的行为、在终端或桌面应用里绘制自定义界面。关键是不用先学 API——在 claude 会话里描述想要的 mod,允许热重载,结束时它就会出现。2.1.287 或更高版本默认开启,无需配置。

Claude Code 原本已经支持通过 settings、权限规则、slash commands、skills 和 status line 调整行为。Mod 走得更远:它能重写或替换 Claude Code 的默认行为,并绘制自定义 UI。底层实现上,mod 是随插件分发的 hooks,每个 hook 都能实时看到会话中的每个事件。

一个 mod 就是一个标准 Claude Code 插件:.claude-plugin/plugin.json 清单加上 hooks/hooks.json 指向的模块。模块导出 register(on),在内部用 on(event, matcher?, hook) 注册回调。每个 hook 接收三个参数:$(mods API:ui、session、state、store、fs、process、clock、http、tool、command、model 等)、e(当前事件的数据)、next(把事件传给下一个插件,最后传给 Claude Code 自身)。Hooks 形成类似中间件的链条,可以执行三种操作:观察(调用 next 后检查返回值)、重写(返回修改后的 e)、应答(不调用 next,直接返回 deny 或自己处理)。事件覆盖工具调用、提示词、回合开始/结束、会话开始/结束、slash commands 和 ui.render。模块在独立的沙箱里运行,没有 DOM 也没有 Node,所有外部交互都走 $。与 settings hooks 不同——后者每次事件都运行一个 shell 命令并通过 stdin/stdout 传 JSON——mod 加载一次并常驻会话,可以保持状态、随事件更新 UI,还能回调 Claude Code:打开窗格、运行进程、注册 slash command 或工具。Claude Code 自己的 AGENTS.md 支持和 /diff 窗格就是作为 mod 实现的,源码在 anthropics/claude-code 仓库的 mods/ 目录下。

教程用一个约 80 行的 Token Weather 演示完整流程:在提示框上方绘制一条上下文窗口的实时预测带,显示天气图标、百分比、已用 tokens / 窗口大小、最近 12 回合的迷你图表,以及上一回合新增量。阈值是:低于 25% 显示 ☀ Clear,25–49% ☁ Cloudy,50–74% ☂ Showers,75–89% ☇ Storm,90% 及以上 ↯ Compact soon。构建步骤包括:创建标准插件目录;在 hooks/token-weather.mjs 中通过 ui.render 事件、resolve 出 Box 和 Text 组件绘制 AbovePrompt 区域;用 $.session.usage() 读取上下文占用数据;把历史读数放进 $.state 而不是模块级变量,因为热重载会重新执行 register 和 session.start,模块变量会重置。$.state 由宿主持有,能跨热重载存活,而且 render 钩子中调用 $.state.get 会自动订阅重绘,之后每次 $.state.set 都会让界面更新,无需手动 invalidate。文中还特别提醒:绘制区域要按 e.props.bodyColumns 的真实宽度来布局,没有内容可画时返回 next(e);使用 ☀ ☁ ☂ ☇ ↯ 这类单宽符号而不是 emoji,确保终端对齐。最后用 claude plugin validate 和 claude plugin test 做校验和测试——测试运行在真实运行时上,可以通过 on 注册桩钩子来控制 $.session.usage() 的返回值。

两个更大的示例展示了 Mod 的介入能力。Blast Radius 会在 Claude 调用 rm -rf、git reset –hard、git clean、force push 或数据库迁移这类高风险命令时拦截调用,先用工具的只读命令(git status、git clean -n、du 等)算出命令会改动什么,再打开带 Proceed 和 Cancel 按钮的窗格。它的核心是 hook 链中的 answer 动作:不调用 next(e),直接返回 { deny: … } 拒绝调用。这个示例还展示了如何用 $.process.run 做干跑(参数以 argv 数组传入,避免路径被当 shell 代码执行)、如何用短 sleep 循环等待用户决定而不消耗 hook 的 10 秒时间预算、以及终端太窄无法打开窗格时如何把报告降级绘制到提示框上方。Replay Theater 则记录每个 Edit 和 Write 调用的前后文本,回合结束后按 r 或输入 /replay 打开窗格,一步一个 diff 地回放上一次回合的编辑。它全程只观察不干预,用 turn.start 和 turn.complete 成对事件把编辑归组为每个回合一段回放,并用 e.agentId 排除子代理回合。

分享 mod 的方式与分享插件完全一致:放进带 marketplace.json 的 GitHub 仓库,别人在 Claude Code 里用三条命令就能安装。官方提醒,mod 是发布者写的代码,运行在你的机器上,拥有 Claude Code 本身的权限,安装前应先阅读仓库、只装可信来源。最后给出的习惯清单:依赖 Claude Code 每次加载时自动写入的类型声明;所有组件 props 从 e.props 读取;为热重载做规划,把数据放在 $.state;界面没显示时用 claude –debug 查看日志中关于 hook 返回无效树的提示。文章末尾列举了几个可继续构建的方向:用 $.session.usage() 做成本/限速仪表、prompt.submit 钩子附加团队约定、列出 Claude 本次会话读过的文件等。

Getting started with Claude Code mods

查看原文