在手机上审批 Claude Code 、DeepSeek Harness 的操作。局域网直连,零依赖。
安装
dsh plugin --profile web add github:laosji/clamicroGitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试
安装与环境配置指引、插件开发教程见 DSH 中文社区文档 ↗
安装即在你的机器上以你的权限运行第三方代码——它可读写文件、使用凭据、访问网络,DSH 的工具审批不会为插件代码加沙箱。「检测到 manifest」仅代表发现 dsh.bundle / dsh.plugin 清单,不构成兼容性或安全审查;安装前请审阅源码,不熟悉的插件先在不含密钥的环境试用。
README
目录
在手机上看 Claude Code 的状态、审批它要执行的操作。
跑任务时不用一直盯着终端——需要授权时 Mac 会弹通知,在手机上打开页面,看清命令和一句摘要,滑动批准或拒绝,Claude Code 随即继续。
| 运行中 | 有事等你 | 做决定 |
|---|---|---|
截图是真实界面,不是效果图。刘海那张是 Mac 上实拍的屏幕截图。
先说清楚默认行为,免得你以为它在拦一切:
| 等多久 | 到点怎么办 | 会不会提醒你 | |
|---|---|---|---|
| 普通操作 | 10 秒 | 自动通过 | 会 |
高风险(rm -rf、force push、动 ~/.ssh) |
3 分钟 | 自动拒绝 | 会 |
也就是说:日常操作它是「告诉你」,高危操作它才是「拦住你」。 两档的等待时长和到点行为都能在设置页改——普通操作的 10 秒改成 0 就是每条都等你;高风险的 3 分钟最长可设到 570 秒(再长就会撞上 hook 的系统超时,审批反而失效)。
零依赖:只需要 Node ≥ 18 和 curl(macOS 自带)。运行时不含任何 node_modules。
仅支持 macOS + iPhone。服务用到 macOS 专有能力(
scutil、osascript、Bonjour),界面是按 iOS Safari 做的。
安装
npx clamicro install
两步走完:
- 终端里:检查环境 → 展示将要对
~/.claude/settings.json做的改动 → 你确认 → 自动备份并写入 → 确认信任当前网络 → 启动服务 → 打印一个网址(不是二维码,理由见下) - 手机打开那个网址(同一 Wi-Fi):进到配对页,点「在 Mac 上显示二维码」。码只出现在 Mac 屏幕上,用手机相机扫它。
- 回到 Mac 确认:会弹出一个框问你要不要放这台设备进来,并显示这个请求从哪来。不按「允许」就不会发出任何凭证。
配对完走一遍内置演示:它会造一条假审批,让你在还没有任何真实风险的时候先滑一次。走完这遍就算装好了。
为什么给网址不给二维码? 终端里的二维码必须携带凭证,而终端恰恰是东西会被留下来的地方——回滚缓冲、录屏、投屏、旁边那位的手机镜头。更早的版本在这里印的是永久主令牌;后来那版印的是 60 秒的一次性配对券,安全没问题,但通常在你掏出手机之前就过期了。网址不带任何凭证、也不会过期;凭证是你在手机上点了按钮之后才生成的,而且只出现在 Mac 屏幕上。
装完即可用:需要审批时 Mac 会弹通知并响一声,终端状态栏显示 ⏳ N 条待审批,手机网页随时能看和批。
没有远程推送:提醒只有 Mac 本地通知这一条,完全不联网。离开电脑后不会有东西叫你——高风险操作会等到超时被自动拒绝。详见下方「近场只用 Wi-Fi」。
安装程序只追加不替换。你已有的 hook 配置会完整保留,
statusLine若已被别的工具占用则不覆盖、只提示。改动前自动备份。
卸载:
npx clamicro uninstall
只摘掉自己加的东西,实测与安装前的配置逐字节一致。配置和历史保留在 ~/.claude/clamicro/,可手动删除。
运行时装在哪
npm 包只是安装器。运行时文件会被复制到 ~/.claude/clamicro/app/,hooks 指向那里。
这不是多此一举:hooks 里写的是绝对路径,而 npx 每次跑在会变的缓存目录、全局安装路径又随 node 版本 / nvm / homebrew 变化。指向 npm 包意味着某天路径失效,所有 hook 会静默失败——你不会看到任何报错,只是再也收不到通知。实测删掉 node_modules 后服务与 hook 照常工作。
升级就是重跑一次 npx clamicro install。
它做了什么
| 你在手机上看到 | 来自 |
|---|---|
| 会话状态、子状态(Thinking/Searching/Editing) | hooks 事件流 |
| 5 小时 / 7 天用量、上下文占用、本次花费 | statusLine |
| 待审批操作 + 一句人话摘要 + 影响面标签 | PermissionRequest |
| 任务完成 / 出错通知 | Stop / StopFailure |
| 事件时间线(每个会话的完整流水) | 全部 hooks |
| 暂停 / 恢复 / 取消本轮 | PreToolUse 拦截点 |
| 额度接近上限预警 | statusLine |
这张表说的是 Claude Code。接了别的后端时,能做什么由那个后端的能力决定—— 见下面「不止 Claude Code」。
不止 Claude Code
2.14.0 起,同一块看板可以同时盯着多个后端。目前支持 Claude Code 和 DeepSeek Harness(DSH)。
首页按模型分区:每个模型一个标题,下面是它自己的状态、履历和用量。 顺序按「谁先连上」固定,不会因为谁刚有动静就换位置。
待审批不分区,永远在最上面、跨后端一起显示——它有倒计时,被分进某个 区块意味着你得先找到那个区块才看得见,而漏看一条等于一次静默的自动决策。
不同后端能做的事不一样
| Claude Code | DeepSeek Harness | |
|---|---|---|
| 手机审批 | ✓ | ✓ |
| 暂停 / 恢复 | ✓ | — |
| 取消本轮 | ✓ | —(协议支持,尚未接) |
| 从手机发消息 | ✓ | —(协议支持,尚未接) |
| 用量 | 5h / 7d 滚动窗口 | 累计 token |
界面按能力渲染:某个后端不支持的操作,入口直接不给。留一个点了没反应的 按钮比没有按钮更糟——你会以为暂停成功了,然后走开。
DSH 的用量只报 token、不折算金额:DSH 自己不算钱,折算需要一张按模型分档的 价目表,而它会在你不知情时过期,然后手机上安静地显示一个错的金额。
接 DSH
npx clamicro install 探测到 ~/.dsh 就会问一句要不要接上,同意后自动装桥接插件
和那只像素猫(点一下直接打开手机看板;没配对过的话那一页就是二维码入口)。
它写的是别人家的配置(~/.dsh/profiles),所以一定会先问,--yes 也不会
替你答应。卸载时会一并摘除。手动接法和三条硬约束见 plugins/。
手势
审批卡片左滑拒绝、右滑批准,详情页和首页列表都支持。批准有 3 秒撤销窗口。
高风险操作(rm -rf、git push --force、密钥文件、越界写入)在详情页需要划得更远,
在列表里则完全不能滑动批准——列表是快速分诊的地方,真要放行危险操作得点进去看清楚。
暂停的真实语义
Claude Code 没有「运行时暂停」原语,没法在任意时刻冻结它。「暂停」实际是
在下一个工具调用前把它挂住,当前这一步仍会跑完。UI 上有明确提示,
免得你以为点了没反应。取消同理,也是在下一个拦截点返回 {continue:false}。
审批链路:
Claude Code 要执行需授权的操作
→ PermissionRequest hook(HTTP,timeout 600)
→ 服务建审批记录,Mac 弹通知,然后阻塞住
→ 你在手机上批准 / 拒绝
→ hook 返回 decision → Claude Code 继续或被拒
安全
这是一个把 Claude Code 的执行权限交到手机上的工具,值得把边界写清楚。
网络信任闸门
服务只在你显式信任过的网络里暴露到局域网。换到陌生网络(咖啡厅、机场、酒店)时自动只绑回环,手机连不上,同时 Mac 弹通知让你确认。
npx clamicro networks # 看当前网络和已信任列表
npx clamicro trust # 信任当前网络
npx clamicro untrust # 撤销:不带参数撤当前网络,也可 untrust <id前缀> / untrust all
信任是可撤销的。误信任一个网络(比如在咖啡厅手滑点了「是」)不该是不可逆的——那个网络会永久留在列表里,下次再连上就自动暴露。
网络指纹用网关 IP + 网关 MAC + 网段 + SSID + DHCP 服务器 + 搜索域 + DNS 列表。
前三项不够:SSID 在新版 macOS 需要定位权限、走有线时根本没有;而 00:00:5e:00:01:xx 是 VRRP 虚拟 MAC,企业网里并不唯一。实测过一种会碰撞的组合——两个不同公司都用 192.168.1.0/24、网关都是 192.168.1.1、网关 MAC 都是 VRRP、又都拿不到 SSID,四个字段完全一样,于是 A 公司信任过之后 B 公司的网络被当成已信任。后面那三个信号来自 DHCP,不需要任何权限,在不同组织之间几乎不会全部相同。
已实现的防护
| 防护 | 挡住什么 |
|---|---|
| Host 头白名单 | DNS rebinding。恶意站点把域名重绑到你的局域网 IP 后浏览器视为同源,CORS 完全失效,能读看板、命令原文并批准操作——且攻击者不需要在你的 Wi-Fi 上 |
| hooks / statusLine 仅回环 | 同网段的人伪造 hook 事件:刷审批通知、注入假时间线、伪造额度 |
/api/pair 要求自定义头 |
CSRF。跨站「简单请求」浏览器会照发,副作用已发生——等于你访问的任何网站都能让这台 Mac 弹二维码 |
| hooks / statusLine / pair-new 只认本机 | 同网段的人伪造 hook 事件:刷审批通知、往时间线注入假记录、伪造额度读数——更要命的是给自己造一张配对券。「本机」是三件事同时成立:回环来源 且 回环 Host 且 没有代理转发头。只看来源地址不够:开着 Cloudflare 隧道时,公网流量正是从 127.0.0.1 进来的 |
| 配对要在 Mac 上确认 | 只是「看到」二维码的人——屏幕共享、投屏、旁边那位的镜头、拿到隧道 URL 的人——拿到设备令牌。看见码不再够用,得有人坐在 Mac 前面按一下。那个对话框出任何问题(超时、拿不到图形会话、崩了)一律算拒绝 |
| 终端里不出现任何形似凭证的东西 | 安装器印的是纯网址,不带令牌也不会过期,所以回滚缓冲、录屏、肩窥都拿不到东西。凭证在你点了手机上那个按钮之后才生成,且只在 Mac 屏幕上渲染 |
CSP frame-ancestors 'none' |
点击劫持:恶意页面把审批页嵌进 iframe 诱导你滑动 |
| 常数时间比较 | token 与审批 key 的时间侧信道 |
| SameSite=Lax + HttpOnly | CSRF;同时保证从别的 App 点链接进来仍是登录态(Strict 会导致每次都要重新扫码) |
| 单条审批专属 key | 拿到一条深链只能决定那一条;审批结束后 2 分钟失效(留这一小段是因为你点完之后结果页还要用它拉一次) |
说人话:配过对的手机等于你 Mac 的钥匙
设备令牌 = 批准任意操作的权限,包括 rm -rf、sudo、读你的 ~/.ssh/id_rsa。请像对待钥匙一样对待那台手机:
- 二维码本身已经不足以配对:它一次性、60 秒过期,而且还要在 Mac 上按「允许」。 拍到码的人没有你按那一下也配不上。话虽如此,还是别把它留在屏幕上
- 怀疑泄露了就立刻换发:
npx clamicro rotate-token。所有设备上的登录当场失效, 对运行中的服务即刻生效,不用重启;之后手机需要重新扫码配对。 只想吊销某一台就用npx clamicro forget <id>,其他设备不受影响 - 登录 cookie 30 天过期,到期重新扫一次
剩下的风险:HTTP 明文
局域网内是明文。同网络的被动嗅探者能拿到你的 token,进而获得完整控制权,包括批准 rm -rf。命令原文同样是明文。
这在保持「扫码即用」的前提下无解——自签证书会让 Safari 报警并破坏整个体验。网络信任闸门把它从「你得记得别在咖啡厅用」变成了「陌生网络默认就用不了」,但如果你确实需要在不可信网络上用:
装 Tailscale。 WireGuard 端到端加密,没有任何第三方看到明文,且不限于同一 Wi-Fi。服务会自动识别 100.64/10 地址并绑上去,且不受网络信任闸门限制——覆盖网自带加密,不关心底下是什么物理网络。
另一条路是内网穿透(clamicro tunnel on),但穿透服务终结 TLS,技术上看得到命令原文——所以它是应急选项,不是默认。
近场只用 Wi-Fi
控制面不出局域网。命令原文、审批指令、时间线、额度全部走 http://<局域网IP>:8765 直连。
按"人在哪儿"分两层,两层都不出局域网:
| 场景 | 提醒方式 | 联网范围 |
|---|---|---|
| ① 人在电脑边 | macOS 本地通知 + 提示音 | 完全不联网 |
| ② 离开电脑 | 没有提醒 | — |
② 为什么没有提醒:锁屏可达的通知只能走 APNs,那必然经过第三方服务器。
先后试过两条并都删掉了:ntfy 双 topic 中转(能在锁屏通知里直接点按钮批准,等于把控制面交给第三方)、Bark(只发一句「有个审批」,控制面留在局域网)。后者已经克制到极限,但它换来的仍然只是「离开电脑时能被叫一下」——而这个工具的前提本来就是你人在附近。为了这个把「有操作在等你审批」这个事实持续告诉一台外部服务器,不划算。
代价要说清楚:离开电脑后没有任何东西会叫你,高风险操作会等到超时(默认 3 分钟)被自动拒绝,那一轮任务失败。这是有意的默认——人不在就不该放行 rm -rf。想主动看的话,手机浏览器随时能打开看板。
设计要点
hook 必须先回包再提醒。 async: true 只对 command 类型有效,HTTP hook 一律阻塞等响应。所以所有端点立即返回 {},推送在响应之后异步发出。
自超时上限 570 秒。 不能走到系统 600s 超时——那会被当成「非阻塞错误」放行到正常权限流程,人不在电脑边时终端会空挂着等一个没人看的弹框。
四种终态:allowed / denied / expired(超时自动拒绝)/ abandoned(终端自己批了,或会话被 Ctrl-C)。同一条审批被多路重复决策时,第一个写入的赢,后到的返回当前真实状态而不报错。
Stop 的提醒阈值。 Stop 在每一轮回复结束时都触发,包括两秒就结束的对话。默认只有 turn ≥ 30s 才推送。turn_started_at 未知时(服务中途启动)按「要推」处理——宁可多推一次,也别漏掉一次任务完成。
状态栏由服务端渲染。 bin/statusline.sh 不解析 JSON,直接把载荷 POST 给服务,服务返回渲染好的文本。因此不依赖 jq,也不用付 Node 的 ~115ms 启动开销(实测 15ms)。有待审批时状态栏会显示 ⏳ N 条待审批。
子状态是推导的。 Claude Code 没有 Thinking/Searching/Editing 事件,全部从 PreToolUse.tool_name 推导;PostToolUse 到下一个 PreToolUse 之间视为 Thinking。
服务挂了不拖累 Claude Code。 回环端口拒绝连接是即时的,hook 拿到非阻塞错误后照常继续,只是收不到通知。而且 SessionStart 是个 command hook,会先把服务拉起来再转发事件——打开 Claude Code 就等于服务可用。
地址用 Bonjour 主机名而不是 IP。 macOS 已经在广播 <LocalHostName>.local,用它做基址,DHCP 换 IP 后旧链接依然有效,不必重新扫码。极少数路由器屏蔽组播,那种情况把 hostMode 改成 "ip"。
登录 cookie 必须是 SameSite=Lax 不能是 Strict。 从别的 App 点链接进 Safari(备忘录里存的地址、Mac 上弹的二维码)属于跨站导航,Strict 的 cookie 不会被带上,表现是每次都像没登录过。
额度是账号级的,不按会话存。 按会话存会出现旧会话的陈旧数字把最新数字顶掉。只认最新一次观测,并在界面上标出更新时间和来源会话。
审批与事件落盘。 ~/.claude/clamicro/history.json,防抖写入 + 临时文件原子替换。重启时仍挂起的审批一律转 abandoned——那些 hook 的连接早断了,再显示成「待审批」是在骗人。
hooks 是热加载的,statusLine 不是。 改完 hooks 当前会话立刻生效;statusLine 要新开会话。
吊销是即刻的,不用重启。 forget / rotate-token / untrust 都是独立的 CLI 进程,只改磁盘;而服务只在启动时读过一次配置。所以 2.14.0 之前这三条命令重启前全部无效——forget 却打印着「这些设备上的登录立即失效」。现在服务监听配置文件热加载 token / 设备簿 / 信任网络,那句话才是真的。
配置和 settings.json 都是原子写。 先写同目录临时文件再 rename。非原子写有两条会踩到的路径:热加载正好读到写了一半的 JSON;以及进程被打断时文件永久半截——config.json 半截等于令牌和已配对设备全没,settings.json 半截等于 Claude Code 起不来。权限也在 rename 之前设好,不留「文件已就位但还是 0644」的窗口。
杀进程之前先确认身份。 stop 和安装流程都会 kill 掉端口上的监听者,而 8765 不是保留端口。判据是 /healthz 回的 service: 'clamicro'(只对回环返回,局域网上的扫描者拿不到),不是匹配命令行——命令行的形状不稳定。不是我们的进程就拒绝并提示换端口,绝不硬抢。
风险判定不看工具名。 判据是「参数里有没有 command」。原来写的是 toolName === 'Bash',而 DSH 的工具名是小写 bash——精确匹配会让整套高危规则一条都不跑,rm -rf / 判普通风险、10 秒自动通过。名字差一个字母,安全核心静默失效且不报任何错。
常用命令
npx clamicro install # 安装 / 升级
npx clamicro uninstall # 卸载
npx clamicro qr # 打印登录二维码
npx clamicro status # 服务、网络、版本
npx clamicro trust # 信任当前网络
npx clamicro untrust # 撤销信任(untrust <id前缀> | untrust all)
npx clamicro networks # 当前网络 + 已信任列表
npx clamicro rotate-token # 换发访问令牌(令牌可能泄露时)
npx clamicro test-push # 发一条测试通知(Mac 本地)
npx clamicro logs # 跟踪日志
npx clamicro stop # 停止服务
平时不用手动启动——SessionStart hook 会在你打开 Claude Code 时自动把服务拉起来。
配置在 ~/.claude/clamicro/config.json(权限 600,含访问 token)。日常设置改手机网页即可,不用编辑这个文件。
ignoreCwds 里的工作目录不做阻塞审批——开发 clamicro 自身时用,正常使用应留空。
使用教程
第一次用、或者遇到「这是 bug 还是设计如此」的困惑,看 docs/guide.zh-CN.md · English。
维护笔记
踩过的坑和当时的判断依据记在 NOTES.md。
已知限制
- 需与 Mac 同一 Wi-Fi(或同一 tailnet);公司网络若开启客户端隔离或 VLAN 隔离则不通
- 局域网内明文传输,不可信网络请用 Tailscale,见上方「安全」
- 纯 HTTP 非 secure context,拿不到 Service Worker / Web Push
- 仅 iPhone + macOS
- Pause 为「下一个可拦截点暂停」,不是运行时冻结
- 手势为主的界面,VoiceOver 用户目前没有等价入口
- 审批与事件保留一天、上限 300/3000 条,超出滚动丢弃
原始 README: https://github.com/laosji/clamicro/blob/main/README.zh-CN.md ↗
同类插件
查看全部 →
dsh
将 DeepSeek Harness 的生命周期状态、错误与审批请求,桥接到本地运行的 OpenPets 桌面伙伴。

dsh-qqbot
让 QQ Bot 接入 DeepSeek Harness(dsh)的官方插件

dsh-open-in-vscode
从 Web GUI 一键在 VS Code 中打开工作区目录。

dsh-notification
回合完成桌面通知,按结果分控 + 关键词过滤。

dsh-notifier
DSH 统一通知推送与远程控制:一个 `notify()` API 打通 25+ 渠道(Telegram / 钉钉 / 飞书 / 企业微信 / QQ 机器人 / WxPusher / PushPlus / Server 酱 / Bark / Discord / Slack / ntfy / webhook 等),timeSensitive / active / passive 分级路由并重试;五通道反向审批(Telegram 按钮 / 飞书卡片 / QQ / WxPusher / 微信 iLink);QQ/钉钉/飞书官方扫码登录;本地 Web 管理台;多 agent 路由;系统桌面通知——以及**手机指挥中心**:在手机上发 `!status` / `!stop` / `!retry` 遥控 agent,通知带可操作按钮(查看结果 / 重试 / 日志,点击回调 agent)。密钥脱敏、工具限流、零运行时依赖。

chatccc
飞书(Lark)或微信(WeChat)聊天控制 DeepSeek Harness / Claude Code / Cursor / Codex / CCC Agent