用桌面角色提醒 Claude Code 等待确认
开源工具 Mascot 通过 Claude Code 的通知钩子接收事件,在 Windows 桌面持续提醒用户处理等待中的交互。实现采用 Electron、WinAPI 和本地 HTTP 服务,并在应用未运行时让钩子静默退出。
AI 深度解读
给 Claude Code 派完长任务,切到别的窗口,十分钟后才发现它一直卡在权限确认上,这类等待很容易被误认为还在执行。作者做了一个 Windows 桌面应用 Mascot:Claude 等你回答时,橙色小人从屏幕角落探头,没人理就变红、跺脚,直到你回来处理。
这个免费、MIT 开源的小工具,值得看的不只是动画。它把 Claude Code hooks、Windows 通知记录和 Electron 透明窗口接在一起,也暴露出终端与桌面端事件不一致、便携版更新受限等实际问题。
怎么分清 Claude 在工作,还是在等你?
作者没有用计时器猜测任务状态,而是接收 Claude Code 的事件。应用在 127.0.0.1:47821 启动 HTTP 服务,配置在 ~/.claude/settings.json 里的 hook 把标准输入中的 JSON 转发过去:
{
"hooks": {
"Notification": [
{ "hooks": [ { "type": "command",
"command": "curl -s -m 2 --data-binary @- http://127.0.0.1:47821/hook || exit 0" } ] }
]
}
}
注意命令末尾的 || exit 0:Mascot 没启动时安静退出;-m 2 限制请求最长耗时。这条命令可用于 bash 和 cmd。服务端会拒绝带 Origin 请求头的请求,用来阻挡普通网页向它发送请求。
应用启动时自动安装 hooks,并保留最近五份 settings.json.mascot-*.bak 备份。但作者实测发现,Claude desktop 的 Code 标签页请求权限或提问时,不会触发 Notification,终端版能跑通的配置搬过去就漏报了。因此还要接入 PermissionRequest,以及 matcher 为 AskUserQuestion|ExitPlanMode 的 PreToolUse。如果希望每次回复结束也提醒,可以选配 Stop。
另一条通道是每秒读取 Windows 通知数据库 %LOCALAPPDATA%\Microsoft\Windows\Notifications\wpndatabase.db,查找符合 Claude_*!Claude 的应用 ID。代码通过 require('node:sqlite') 获取 DatabaseSync,以 { readOnly: true } 打开数据库,从 NotificationHandler 查询 PrimaryId。这条路径也能覆盖已经运行中的 Claude。
先找到可靠的等待信号,提醒才有资格谈体验。
桌面小人怎样可见,却不抢操作?
窗口要透明、无边框、置顶、不出现在任务栏,也不能抢焦点。鼠标点击还得穿过去,只有小人自身可以点击。作者用的是:
win = new BrowserWindow({
frame: false, transparent: true, backgroundColor: '#00000000', hasShadow: false,
skipTaskbar: true, alwaysOnTop: true, focusable: false,
});
win.setAlwaysOnTop(true, 'screen-saver');
win.setIgnoreMouseEvents(true, { forward: true });
注意最后一行的 forward: true:忽略点击时,鼠标移动事件仍能到达页面。光标进入小人区域,页面通知主进程恢复点击;离开后再次穿透,不必手写坐标命中判断。
窗口与工作区等宽,高 190 px,位于任务栏上方。动画由 SVG 和 CSS 完成,嘟囔声用 WebAudio 合成,嘴巴按音节开合。没有用户手势也要播放声音,需要设置 autoplayPolicy: 'no-user-gesture-required'。

提醒会逐级升级:先探头三轮,每轮三句话,间隔 7 秒;前两轮平静,第三轮不耐烦。随后完整现身 20 秒,变红、跺脚、挥拳,再离开并循环。台词随机选择,连续两次不重复。作者先写 HTML demo 调整角色表现,再开发完整应用。
应用通过 koffi 调用 user32.dll,无需 node-gyp,每 300 ms 检查前台窗口。它把进程为 claude.exe 或标题包含 claude 的窗口视为 Claude;窗口变为前台,或者用户点击小人,提醒就结束并重置。点击还会尝试把 Claude 窗口带到前台。

真正麻烦的,是提醒之外的收尾
为了避免 Windows 横幅和小人同时出现,默认开启的「Replace Claude pop-ups with the mascot」会通过 reg.exe,把 HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\<AUMID> 下的 ShowBanner 设为 0。操作中心记录与数据库行仍然保留,小人还能继续检测。
关键在恢复。应用保存原值,也记录此前是否根本没有这个值;关闭选项、退出应用、Windows 会话结束,以及崩溃后的下一次启动,都会恢复旧状态。
分发也有两套行为。electron-builder 生成 NSIS 安装包和便携 exe。安装版通过 electron-updater 对接 GitHub Releases,启动 15 秒 后检查更新,此后每 6 小时 检查,后台下载、重启安装。便携版运行于临时解压目录,只提示新版本。
作者还踩过两个坑:electron-builder 并行上传可能创建重复 release,因此工作流先执行 gh release create;便携版自启动必须使用 PORTABLE_EXECUTABLE_FILE,不能使用指向临时目录的 process.execPath。
我的判断
我更看重这套实现对运行环境的处理:它没有假设所有 Claude 入口都发送相同事件,也考虑了修改用户设置后的恢复责任。这些经验对桌面辅助工具很实用。
但「更不容易漏看」还只是作者的设计目标。原文没有提供与普通 toast、声音提醒或持续状态指示的对照数据,无法判断小人究竟能缩短多少等待。逐级升级的动画也可能打断专注,不能仅凭演示就断言适合整个团队。
另外,窗口进入前台只代表用户回来了,不代表问题已回答;标题包含 claude 的识别也比较宽泛。原文没说明多个会话同时等待时如何准确对应。读取系统通知数据库则依赖 Windows 的具体实现,跨版本兼容性没有展开。
作者称 node:sqlite 已内置、无需原生模块,但没给出 Node 或 Electron 版本。准备复用时仍要核对运行时,不能直接推断所有项目都可用。
能拿来做什么
- 给日常 AI 编程流程加提醒时,先验证权限请求、提问和执行结束分别触发什么事件,尤其要分别测试终端与桌面入口。
- 用 Electron 做桌面悬浮工具时,可以复用透明窗口与鼠标穿透方案,并检查点击小人、切换窗口和恢复焦点的完整流程。
- 工具需要修改用户配置或系统设置时,把原值备份、正常退出恢复和崩溃后恢复一起实现,避免留下永久副作用。
- 发布 Windows 便携应用时,单独检查更新与自启动路径,确认保存的是实际 exe 路径,而不是临时解压目录。