ClaudeMods
☰
EN
● — online · Views — times
SponsorsSubmit a project
GitHub repositories · by sawzhang

hello-mod

A minimal working demo of Claude Code function hooks: self-registering the `/hello` command, drawing an interactive panel above the prompt, a real-time token and cost meter, a cross-session persistent counter, tool-call monitoring, and an independent drawing-thread animation.

Translated

About this mod

This plugin demonstrates the main capabilities of function hooks (Claude Mods): the plugin registers its own slash command, renders a panel above the prompt, reads session usage and cost, monitors tool calls, persists data via $.store, and provides button interactions and an independent drawing-thread animation. The repository contains a verified plugin manifest, hooks module, automated pty verification script, and installation/run instructions. Requires Claude Code 2.1.269+ and CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1.

Installation

Check the author's README for the marketplace and plugin name first. Commands may change as the repository evolves.

claude plugin marketplace add sawzhang/hello-mod
claude plugin install hello-mod
Original text / README

hello-mod

Claude Code function hooks(产品名 Claude Mods)的最小可运行演示:一个 /hello 命令,一条画在 prompt 上方的面板,面板里有实时 token / 成本计、可点击的按钮,和一个跑在独立绘制线程上的动画。

全程零 token —— 命令回复、按钮点击、动画重绘,模型一步都不参与。

❯ /hello
  ⎿  面板已打开 · 这条回复由插件直接生成,没有经过模型 · /hello off 关闭
hello-mod · function hooks 演示
上下文 █░░░░░░░░░ 5% 46.9k / 1.00M 本会话 $0.179 claude-opus-5
本会话 1 轮 · in 4 · out 101 · 缓存读 80.3k 写 13.4k · 工具 1 次(最近 Bash)
跨会话累计 1 轮 · $0.179 · 93.9k tokens(存在 $.store)
[  +1  ] [  -1  ] [  关闭  ] 点击 6 次 · 按钮不经过模型
⠋ 独立绘制线程 · 第 100 帧 · 10fps · 零 token · 主线程忙时照转
────────────────────────────────────────────────────────────────────────
❯

上面这段是 scripts/demo.py 从一个真实会话里截下来的,不是手写的示意图。

它演示了什么

| 能力 | 用到的 API | 在面板上的体现 | |---|---|---| | 插件自己注册斜杠命令 | $.command.register + command.run | /hello,immediate: true 所以回复不经过模型 | | 在 prompt 上方绘制 | ui.render + {component: 'AbovePrompt'} | 整条面板 | | 读会话用量与花费 | $.session.usage() | 上下文进度条、本会话美元数 | | 按轮结算 token | turn.complete 的 e.usage | in / out / 缓存读写四项计数 | | 监听工具调用 | tool.call | 工具次数与最近一次的工具名 | | 跨会话持久化 | $.store | 点击数、跨会话总账 | | 交互 | Button + onPress | +1 / -1 / 关闭 | | 独立绘制线程 | Client surface module | 底部转圈动画,主线程忙时照转 |

环境要求

  • Claude Code 2.1.269+(第一个能让 function hooks 画在 prompt 上方的版本),本仓库在 2.1.271 上验证过
  • CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1
  • 交互式终端。claude -p、桌面端、移动端都不绘制(hook 照常触发,只是不画)

function hooks 目前是早期访问,API 可能随 Claude Code 版本变化。

跑起来

git clone https://github.com/sawzhang/hello-mod
cd hello-mod
claude --plugin-dir .

仓库自带的 .claude/settings.json 只为这个目录打开 CLAUDE_CODE_ENABLE_FUNCTION_HOOKS,不动你的全局配置。进去之后输入 /hello。

  • /hello 打开面板
  • /hello off 关闭
  • /hello reset 清零点击数和跨会话总账

自动验证

function hooks 只在真 tty 里绘制,所以验证脚本用 pty + 终端仿真跑一个真实会话,自动点按钮、截屏:

python3 -m venv .venv && .venv/bin/pip install pyte
.venv/bin/python scripts/demo.py

它会依次验证:面板渲染 → 帧时钟在走 → 点击 +1 生效 → 重启会话后计数还在 → Claude 跑一个工具后 tool.call 计数 +1 → 回合结束后 token 与花费结算。

开发

claude plugin validate .claude-plugin/plugin.json   # 列出钩的事件、用到的 $ 能力、surface module
claude plugin test .                                # 7 个测试,含一个走引擎的 /hello 集成测试

类型检查需要先生成早期访问的类型定义:在本目录开一个会话,运行 /plugin-types(写入被 git 忽略的 .claude/types/),然后:

bunx -p typescript tsc -p .

结构

.claude-plugin/plugin.json   插件清单
.claude/settings.json        只对本目录开启 function hooks
hooks/
  hooks.json                 入口:{"modules": ["./register.tsx"]}
  register.tsx               5 个 hook:session.start / command.run / tool.call / turn.complete / ui.render
  cost.ts                    纯函数:token 累加与格式化(可单测)
  clock.tsx                  surface module,跑在独立绘制线程
tests/cost.test.ts           claude plugin test
scripts/demo.py              pty 自动化验证

踩过的坑

写 function hooks 插件时这几条目前没有文档,但会实打实咬人:

  1. surface module 里绝不能有名为 h 的局部变量 —— 每个 JSX 标签都编译成 h() 调用,撞了会在首帧崩掉。
  2. Client 的 module 必须写字符串字面量 —— 引擎从源码里静态读取路径,变量拼接找不到。
  3. hook 里未捕获的 Promise reject 会卸载整个模块 —— 所有 $.store 调用都要挂 .catch。
  4. prompt 上方这条带子大约占终端一半高度,重绘约 10fps(实测 1.5 秒走 14 帧)。
  5. band 里别设快捷键 —— 会吃掉用户在 prompt 里键入的第一个字符。
  6. tsconfig.json 需要 allowImportingTsExtensions ——/plugin-types 给的示例配置里没有,但带扩展名的相对 import 需要它。
  7. 改代码会热重载;重载失败一半会留着旧版本,要重启会话。

参考

License

MIT

Get a badge

Is this your project? Add this badge to your README or website. It links back to this page.

Featured on ClaudeMods
Size
Theme
Markdown
HTML

Other works with the same name

Similar projects