@zhiliangtech/deskshell
v0.18.7
Published
OS runtime for agents: protocol-first kernel with declared capabilities, post-assertions, undo and audit
Maintainers
Readme
30 秒:它搞砸了,而且一点痕迹都不留
这张图是用命令的真实输出渲染的(scripts/make-terminal-svg.ts)——重跑一次,它就跟着代码变。
node apps/cli-demo/thirty-seconds.ts五步跑在一个沙盒里。第四步成功,第五步失败,然后全部自动退回:
[1-mkdir] ok
[2-write-a] ok
[3-write-b] ok
[4-move] ok
[5-write-c] FAIL 后置断言失败:{"kind":"path.exists","path":".../this-will-never-exist"}
↩ 自动回滚(逆序):5 处
undo 4-move move b.txt → .../done/b.txt
undo 3-write-b write b.txt (1 chars)
undo 2-write-a write a.txt (1 chars)
undo 1-mkdir mkdir .../uploads
目录状态 before: 空
after : 空 ✅ 逐字节一致注意最后那条日志:失败的那一步也在日志里。失败的任务仍然是可审计的任务。
这不是承诺,是测试——scripts/thirty-seconds-test.ts 会在三种情况下让构建失败:退出码非零、日志不是正好 5 行、目录没有逐字节还原。
R0 —— 别人不报的那个数
所有 computer-use 项目都报成功率,没有人报"失败之后留下了什么"。
node scripts/recovery-bench.tsR0-残渣 100.0%(15 次失败注入)
R0-回滚 100.0%
R0-可追溯 100.0%
正常路径撤销后逐字节还原:4/4| 面 | 量的是什么 | 现在 | | --- | --- | --- | | 文件 | 逐字节还原、每步都撤销、每步都入账 | 100% / 100% / 100%(15 次失败注入) | | UI | 窗口几何、控件值,以及拦住不可逆步骤 | 100%(5 次失败注入) |
UI 那个 100% 之所以成立,是因为"动手前就拒绝"也算零残渣——判据见 docs/zh-CN/recovery.md。
R0 = 失败后副作用归零率:给每个场景的每一步都注入一次失败,然后逐字节比对目录、核对已执行步骤是否全部撤销、核对每一步是否都在日志里。定义与"如何加场景"见 docs/zh-CN/recovery.md。
从你的 agent 里调用(MCP)
内核同时是一个 MCP server:agent 可以"先看计划 → 执行 → 需要时撤回",而不是凭感觉点鼠标。
node packages/mcp/server.ts # stdio JSON-RPC:initialize / tools/list / tools/call| 工具 | 作用 |
| --- | --- |
| deskshell_skills | 列出已安装技能 |
| deskshell_preview | 只读:能力申请单 + 步骤 + 汇总 |
| deskshell_apply | 执行,返回 taskId |
| deskshell_undo | 撤销那个 taskId |
不引 SDK、不引依赖。scripts/mcp-test.ts 会真的起进程按客户端方式对话(14/14)。详见 docs/zh-CN/mcp.md。
它是什么,不是什么
| | | | --- | --- | | 是 | agent 操作机器时调用的那层运行时:能力 → 动作 → 后置断言 → 撤销 → 审计日志 | | 不是 | 一个 agent、一个聊天界面、一个 RPA 录制器,或一层模型 API 的包装 | | 为什么需要它 | "只会点鼠标"的 agent 既不知道点没点中,也没法把点到的东西还回去 |
证明(你自己跑)
node scripts/recovery-bench.tsR0-残渣 100.0%(15 次失败注入)
R0-回滚 100.0%
R0-可追溯 100.0%
正常路径撤销后逐字节还原:4/4所有 computer-use 项目都在报成功率。这是另一个数:失败之后留下了什么。
它和别的方案的区别
| | 普通 agent / 自动化脚本 | deskshell |
| --- | --- | --- |
| 动手前 | 直接开干,你不知道它会做什么 | preview 先给计划,标出风险与是否可撤销 |
| 动手后 | "应该成功了吧" | 每步执行后跑断言,失败即停 |
| 出错时 | 留下半个烂摊子 | 先撤失败动作自身,再逆序回滚全部已成功步骤 |
| 事后 | 没人知道发生了什么 | JSONL 审计:谁、何时、改了什么、怎么撤 |
| 模型 | 绑死某个厂商 | 内核零模型依赖,模型只是 skill 内部的可替换件 |
实际跑起来是这样

动图由真实命令输出生成(scripts/make-assets.py),不是手绘示意图。
三个场景,一次撤销——文件移动、UI 写入、窗口几何走同一个事务:

[撤销] 22 步回滚,失败 0 步
文件 0 → 13(起点 13)
标签清单 0 份
窗口 627,551 2880x1538 ← 逐像素还原架构
- Skill 只描述意图(
plan() → Action[]),不碰系统 API、不写回滚逻辑; - Kernel 负责权限、预览、执行、断言、回滚、审计——接口冻结的那一层;
- Driver 按平台实现(Windows UIA / macOS AX / Mock),可整体替换。
安装
需要 Node >=22.18(或 >=23.6)——CLI 直接运行 TypeScript。
安装脚本(github.com 打不开的网络也能用,它走 GitHub API 下载):
irm https://raw.githubusercontent.com/ZhiliangTech/deskshell/main/install.ps1 -OutFile install.ps1
.\install.ps1它会检查 Node/npm、拉最新发行版、安装、然后自动跑 deskshell doctor。
GitHub Packages(需要带 read:packages 的 token):
npm config set @zhiliangtech:registry https://npm.pkg.github.com
npm i -g @zhiliangtech/deskshell从源码:
git clone https://github.com/ZhiliangTech/deskshell && cd deskshell
node bin/deskshell.ts doctor部分网络打不开 npmjs.com 的网页,但 registry API 是通的——安装脚本因此走 API 下载。公共 npm 上的
@zhiliangtech/deskshell实测latest=0.18.6,npm i -g @zhiliangtech/deskshell直接可用。也可以走安装脚本、GitHub Packages,或从 Git 装:npm i -g github:ZhiliangTech/deskshell。
30 秒装好跑通
node bin/deskshell.ts doctor # 环境自检
node scripts/make-fixture.ts # 造 13 个文件的下载目录
node bin/deskshell.ts run downloads-cleanup --root .demo/downloads # 只预览,不动手
node bin/deskshell.ts run downloads-cleanup --root .demo/downloads --mode apply
node bin/deskshell.ts run downloads-cleanup --root .demo/downloads --mode undo不需要 API key,不需要联网,不需要模型。
想亲眼看失败回滚:
node bin/deskshell.ts story --fail命令
| 命令 | 用途 |
| --- | --- |
| deskshell list | 列出可用 skill |
| deskshell run <name> | 预览 / 执行 / 撤销(默认预览) |
| deskshell story | 三场景跑一遍并整体撤销 |
| deskshell journal | 审计日志时间线 |
| deskshell undo --task <id> | 撤销某一次任务(幂等) |
| deskshell add <path> | 安装外部 skill(先打印它要的能力) |
| deskshell verify | 检查平台驱动能力 |
| deskshell doctor | 环境自检 |
| deskshell version | 版本信息 |
平台
| 平台 | 状态 | 验证方式 |
| --- | --- | --- |
| Windows | 已验证(UI Automation) | deskshell doctor |
| macOS | 已验证(原生 Swift AX 桥,20 个窗口 36ms) | deskshell doctor |
| Linux | 窗口层已实现(xdotool + wmctrl);控件层(selector)待 AT-SPI2 | deskshell verify |
macOS 需要先编译桥:packages/drivers/macos/build.sh(Xcode Command Line Tools),并在「系统设置 → 隐私与安全性 → 辅助功能」给终端授权。
写一个 skill
node scripts/new-skill.ts --name my-skill
node bin/deskshell.ts run my-skill --mode preview三条硬规则:每步都要有 post 断言;每步都要有 undo;skill 里不准直接调系统 API。
更多
- STATUS.md:每条能力配一条可复现命令与实测输出
- CHANGELOG.md:0.1.0 归档与已知限制
- docs/:协议、写 skill、撤销语义、录制器、驱动、版本策略、路线图(英文;中文在 docs/zh-CN)
node scripts/build-docs.ts→site/index.html(本地文档站)
已知限制
- Linux 还没有可访问性树:窗口层驱动(xdotool + wmctrl)可用,但 selector 级的
invoke/click会明确报不支持,不会假装点成功。 - 录制器是 300ms 轮询,快速切换可能漏采;只捕获左键。
- 撤销覆盖文件与窗口几何;网络请求等外部副作用不可撤销(协议层会拒绝
undo: null的动作)。 - 项目处于
0.x,破坏性变更走 RFC 并在 CHANGELOG 给迁移说明。
设计红线
- skill 不准直接调用系统 API,只能产出
Action。 - 每个
Action必须有post断言;不可撤销的动作必须显式标记,内核会拒绝。 - 能力必须声明、必须带人话理由、必须落在作用域内。
- 内核不依赖任何模型;模型只允许出现在"理解屏幕"和"拆解任务"两个可替换接口后面。
文档站
协议、快速开始、设计红线都有网页版:https://zhiliangtech.github.io/deskshell/。
一起把它做出来
deskshell 先是协议,其次才是产品——最硬的部分还没人认领:
| 待认领 | 从哪里下手 |
| --- | --- |
| Linux 控件层(AT-SPI2) | 窗口层驱动已有;补可访问性树后端,让 selector 级 click/invoke 可用 |
| 录制器事件钩子(干掉 300ms 轮询) | packages/drivers/windows/recorder.ps1 |
| dry-run diff · 撤销时间线 · 文档站搜索 | 已拆成带验收标准的 issue |
| 新 skill | node scripts/new-skill.ts --name x,然后只改 plan() |
每个任务都自带 fixture、一个会失败的测试,和 48 小时内的首次响应。任务板、贡献者阶梯、治理与拉人手册在 outreach/,已合并的贡献记在 CONTRIBUTORS.md;提问和路线图投票在 Discussions。注意:bounty 只表示「可认领」,没有现金。
MIT License.
