Claude Code 状态栏小兽 —— 一只会随状态切换姿势的像素小兽,外加上下文 / 用量 / 模型 / 花费一目了然。
cchud 是给 Claude Code 用的 statusLine 脚本。它从 stdin 读取 Claude Code 传入的会话 JSON,输出三行带颜色的终端状态栏。
上图为同一脚本在六种状态下的实际输出:思考中 / 跑命令 / 翻找文件 / 联网搜索 / 敲键盘(橙色,小兽站立,头顶 badge 区分在干什么)与等你输入(绿色,小兽蜷缩低头打盹)。
显示内容:
- 小兽姿势 + 颜色 + 头顶 badge —— 当前在干什么:思考
?/ 跑命令>_/ 翻找⌕/ 搜索@/ 敲键盘I/ 等你zᶻ,注册实时状态源后还有黄色的等确认!。默认读会话日志的最后一个有意义事件推断(比看文件 mtime 更准,详见状态推断的原理与限制);注册实时状态源后改由 hooks 即时驱动。 - ctx —— 上下文窗口占用百分比。
- 5h / 7d —— 5 小时 / 7 天用量额度,带重置倒计时(
↻)。 - 进度条颜色 —— 绿(<60%) / 黄(60-85%) / 红(≥85%)。
- 尾行 —— 待办完成数(
✓3/5)、模型名、本次花费、累计时长。待办兼容两套机制:新版 Task 系统(TaskCreate/TaskUpdate事件流,正序重放重建任务与状态)优先,没有再回落老版 TodoWrite 快照。此外若有「比主日志更新的活动子代理日志」(<主会话id>/subagents/agent-*.jsonl),优先取它的待办,否则用主会话自己的。
需要本机有 Node.js(任意较新版本即可,脚本无依赖)。
把仓库克隆到任意位置:
git clone https://github.com/x-wink/cchud.git然后编辑 ~/.claude/settings.json,加入 statusLine 字段。
记得给启动器加可执行权限:chmod +x /path/to/cchud/hud.sh。
直接用 node 调用 hud.js(注意 JSON 里反斜杠要转义):
{
"statusLine": {
"type": "command",
"command": "node \"C:\\path\\to\\cchud\\hud.js\"",
"refreshInterval": 2
}
}保存后重启 Claude Code(或新开会话)即可生效。
notify.js 可在 Claude Code 需要你时弹桌面通知 + 播提示音,方便你挂着别的事时被叫回来。它借助 Claude Code 的两类钩子,并用不同提示音区分场景,凭声音即可分辨:
| 钩子 | 触发时机 | 提示音(Windows) |
|---|---|---|
Stop |
答完、把控制权交还给你 | 完成铃声 Ring01.wav |
Notification |
需要你授权 / 等待你输入 | 前台提示音 Windows Foreground.wav |
Notification 事件的具体事由(如「需要授权使用 Bash」)由 Claude Code 通过 stdin 的 message 给出,直接作通知正文。
跨平台:Windows 用 PowerShell WinRT Toast + 系统提示音,macOS 用 osascript,Linux 用 notify-send + paplay。
在 settings.json 里和 statusLine 同级加入 hooks(两类指向同一个脚本,脚本内部按事件类型自动区分):
{
"hooks": {
"Stop": [
{ "hooks": [{ "type": "command", "command": "node \"C:\\path\\to\\cchud\\notify.js\"" }] }
],
"Notification": [
{ "hooks": [{ "type": "command", "command": "node \"C:\\path\\to\\cchud\\notify.js\"" }] }
]
}
}通知里会带上当前项目目录名,多个会话同时跑时一眼能认出是哪个项目在叫你。Windows 上若通知没弹出,检查「设置 → 系统 → 通知」与「专注助手 / 勿扰模式」是否屏蔽了通知(提示音不受勿扰影响,仍会响)。
默认的状态推断靠扫会话日志,受「落盘时机」限制——比如思考内容要整块结束才写入,思考期间状态栏拿不到任何新信息。state.js 提供另一条实时链路:注册为一组 Claude Code 钩子后,Claude Code 会在事件发生的瞬间同步调用它,它把「此刻在干嘛」写进 ~/.cchud/state/<会话id>.json,hud.js 发现该文件后即优先采用(日志推断退为兜底)。收益:
- 按下回车立刻进入「思考中」——不用等任何内容落盘;
- 工具执行前就切好姿态——
PreToolUse带确切工具名,长命令全程姿态正确; - 新增黄色「等确认
!」状态——等你授权 / 等你输入时整只小兽变黄提醒你,这是日志推断给不了的。
在 settings.json 的 hooks 里把下列事件都指向 state.js(Stop / Notification 与 notify.js 并存,同一事件的 hooks 数组可以放多个命令)。全部加 "async": true:钩子在后台跑、完全不阻塞 Claude Code 主流程——代价是极小概率相邻事件写入乱序、状态短暂偏差,下个事件自然纠正,对状态展示这种「尽力而为」的用途是正确取舍:
{
"hooks": {
"UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "node \"C:\\path\\to\\cchud\\state.js\"", "async": true }] }],
"PreToolUse": [{ "hooks": [{ "type": "command", "command": "node \"C:\\path\\to\\cchud\\state.js\"", "async": true }] }],
"PostToolUse": [{ "hooks": [{ "type": "command", "command": "node \"C:\\path\\to\\cchud\\state.js\"", "async": true }] }],
"SessionStart": [{ "hooks": [{ "type": "command", "command": "node \"C:\\path\\to\\cchud\\state.js\"", "async": true }] }],
"SessionEnd": [{ "hooks": [{ "type": "command", "command": "node \"C:\\path\\to\\cchud\\state.js\"", "async": true }] }],
"Stop": [
{ "hooks": [
{ "type": "command", "command": "node \"C:\\path\\to\\cchud\\notify.js\"" },
{ "type": "command", "command": "node \"C:\\path\\to\\cchud\\state.js\"", "async": true }
] }
],
"Notification": [
{ "hooks": [
{ "type": "command", "command": "node \"C:\\path\\to\\cchud\\notify.js\"" },
{ "type": "command", "command": "node \"C:\\path\\to\\cchud\\state.js\"", "async": true }
] }
]
}
}细节与兜底(实现见 state.js / hud.js 的 resolveState):
- 用户中断 / 秒取消不触发任何钩子,hook 状态会停在忙态。
hud.js用日志里的中断标记(比 hook 事件新即回休息)和 60 秒悬挂超时兜底,行为与纯日志推断一致。 - 状态文件比日志旧超过 10 分钟视为钩子失联(如中途卸载),自动退回日志推断;超过 24 小时的陈旧状态文件会被顺手清理。
- 状态目录可用
stateDir配置(CCHUD_STATE_DIR/ 配置文件同名字段)。
小兽的称呼、状态栏两种状态文本、通知标题/正文都可自定义。称呼默认为 小螃蟹。解析优先级:CLI 参数 > 环境变量 > 配置文件 > 默认值。
| 字段 | 默认值 | 用途 |
|---|---|---|
name |
小螃蟹 |
称呼,用于通知标题里的 {name} |
busyLabel |
吭哧吭哧 … |
状态栏「忙碌」文本 |
idleLabel |
zᶻ ✓ 等你 |
状态栏「等你」文本 |
waitLabel |
等确认 … |
状态栏「等授权/等输入」文本(需注册实时状态源) |
doneTitle |
{name} · 等你了 |
通知标题(答完) |
doneBody |
答完了,回来看看 ✓ |
通知正文(答完) |
needTitle |
{name} · 需要你 |
通知标题(需要授权/等待输入) |
needBody |
需要你处理一下 |
通知正文兜底(Claude 未给 message 时) |
配置文件(推荐,一次配置两个脚本共用):把 cchud.config.example.json 复制为 cchud.config.json(脚本同目录)或 ~/.cchud.json,按需修改。也可用 --config <path> 或环境变量 CCHUD_CONFIG 指定路径。
命令行参数(写进 settings.json 的 command 里):
"command": "node \"C:\\path\\to\\cchud\\hud.js\" --name 大龙虾 --idle-label \"钳子等你~\""环境变量:CCHUD_NAME、CCHUD_BUSY_LABEL、CCHUD_IDLE_LABEL 等(字段名大写下划线)。
未注册实时状态源时,小兽的姿态通过读取会话日志(transcript)的最后一个有意义事件推断——而非看文件 mtime:
- assistant 调
Bash→ 跑命令>_;调Read/Grep/Glob等 → 翻找中⌕;调WebSearch/WebFetch→ 搜索中@;调Edit/Write等 → 敲键盘I;仅思考或调其他工具 → 思考中?;给出完整文字回复 → 休息中zᶻ。 - 工具结果(
tool_result)会被跳过、回溯到对应的工具调用判断姿态;中断标记[Request interrupted by user…]会被识别为「休息中」。 - 同一轮里「开场白文字」与随后的工具调用是分开落盘的两条记录:只有
stop_reason为收尾(end_turn)的文字才算「答完 → 休息中」;若仍是tool_use(或记录尚未写完),说明后面还要继续调工具,判为忙——避免长任务里开场白先落盘、工具调用还没落盘时误判成休息。
Claude Code 的状态栏默认只在「有新助手消息」时刷新——你提交消息这个动作本身不触发刷新。所以不加配置时,从你发消息到 Claude 开始响应的这段时间,状态栏会冻结在上一帧(看起来像「装睡」)。在 statusLine 里加上 refreshInterval(单位秒,最小 1)让它定期重绘即可解决(安装示例里已包含)。
- 短操作的姿态只会一闪而过:assistant 消息要整条生成完才落盘,读一个文件、跑一条快命令这类毫秒级动作,对应姿态往往来不及显示。只有长任务(耗时命令、大范围检索)才会稳定停在对应姿态。
- 「正在等待响应」与「提交后秒取消」无法即时区分:Claude Code 取消时既不触发任何 hook,也不在日志留下可识别痕迹,两者的日志状态完全一致。为避免秒取消后永久卡在「思考中」,脚本采用兜底——一条用户输入悬挂超过 60 秒仍无任何响应跟进,即判定为已取消 / 久挂并回到「休息中」(
claude --resume回来也借此自愈)。代价是秒取消后需等这段时间才回休息;阈值在hud.js的IDLE_AFTER_MS可调。
不接 Claude Code 时,可手动喂一段假 JSON 预览效果:
echo '{"context_window":{"used_percentage":42},"rate_limits":{"five_hour":{"used_percentage":63}},"model":{"display_name":"Opus 4.8"},"cost":{"total_cost_usd":1.23}}' | HUD_FAKE_STATE=busy node hud.js环境变量 HUD_FAKE_STATE=busy|idle|bash|read|web|edit|wait 可强制小兽进入指定状态,方便调试。
模拟钩子事件验证实时状态源(CCHUD_STATE_DIR 可把状态文件指到临时目录):
echo '{"hook_event_name":"PreToolUse","session_id":"test","tool_name":"Bash"}' | node state.js
cat ~/.cchud/state/test.json # {"state":"bash","event":"PreToolUse","tool":"Bash","ts":…}生成预览页面(README 顶部的 preview.png 即截自此页面的终端元素):
node tools/preview.js # 输出 tools/preview.html,用浏览器打开即可预览两种状态状态栏用到真彩色 ANSI(38;2;r;g;b)和 Unicode 方块字符。在 Windows Terminal、VS Code 集成终端、iTerm2 等现代终端显示最佳;老式 conhost(cmd.exe 默认窗口)可能配色或对齐不理想。
MIT

{ "statusLine": { "type": "command", "command": "/path/to/cchud/hud.sh", "refreshInterval": 2 } }