内部实现

各部分到底怎么咬合,哪条规则在哪一层执行。写给要扩展它的人,不只是要跑它的人。

完整流程

checkCapabilities(caps, granted, root)     声明的能力必须全部被授予
        ↓
skill.plan(input, ctx) → Action[]          由受信技能代码生成计划
        ↓
checkAction(action, root, ids, caps)       逐动作:路径逃逸、窗口作用域、可撤销性
        ↓
preview  ─ 打印后停止
apply    ─ 每个动作:前置断言 → 执行 → 后置断言 → 写日志
undo     ─ 读日志 → 逆序回放撤销 → 标记 rolled-back

以上全是同步的文件系统操作加驱动调用。没有调度器、没有重试循环、没有模型。

规划约定为只读,但技能当前运行在宿主进程中,可以直接访问文件系统和 driver;该约定不是沙箱。预览和执行还会分别调用一次 plan()。固定计划与可信授权边界见 RFC 0001 草案。

策略层到底查什么

| 检查 | 位置 | 挡住什么 | | --- | --- | --- | | 能力是否被授予 | checkCapabilities | 拿用户没给过的权限干活 | | fs.* 作用域在 root 内 | checkCapabilities | 声明 C:\ 当作用域 | | 动作被声明的能力覆盖 | checkAction | 声明 ui.read 却去点鼠标 | | 路径词法在 root 内 | checkAction → isInside | .. 穿越、绝对路径 | | 路径真实位置在 root 内 | checkAction → isInsideReal | root 内指向外部的 junction / 软链接 | | 窗口落在声明作用域内 | checkAction | 声明"记事本"却操作"计算器" | | 动作可撤销 | checkAction | fs.delete 配 undo: null |

真实路径检查会沿最近的存在祖先解析,所以目标还不存在也能查;对 fs.move 的源只查父目录——搬走一个快捷方式本身是合法操作。

失败语义

动作失败时,内核依次做四件事:

  1. 把失败写进日志(status: "failed" + detail);
  2. 撤掉失败动作自身的副作用——但只有真的进入过执行阶段、且效果确实存在时才撤(selfUndoSafe),避免"前置断言失败却把别人的文件搬走"这类事故;
  3. 逆序回滚所有已完成的步骤;
  4. 只把确实撤销成功的步骤标成 rolled-back。

如果撤销本身失败(比如文件被改过),那一步在日志里保持未撤销状态。日志不会谎报回滚。

日志是唯一事实来源

<root>/.deskshell/journal.jsonl,一行一个 JSON 对象:

{"ts":1793281142815,"taskId":"task-1793281142815","skill":"photo-sort","actionId":"move:IMG_0001.jpg",
 "kind":"fs.move","summary":"move IMG_0001.jpg → …/2026-03/IMG_0001.jpg","status":"ok",
 "undo":{"kind":"fs.move","from":"…/2026-03/IMG_0001.jpg","to":"…/IMG_0001.jpg"}}

deskshell history 汇总任务,deskshell show <taskId> 打印单次任务时间线。

并行执行

deskshell run a b c --parallel 在同一个进程里并发跑多个 skill:各自保留自己的计划和上下文,共用一份日志。日志写入是同步的,所以追加不会交错丢行;markRolledBack 的读-改-写也在同一个 tick 内完成。

一个 skill 失败会让 CLI 以非零退出,但不会中断其它 skill——有测试专门把"必然失败"的 skill 和 photo-sort 放在一起跑。

skill 放在哪

  1. packages/skills/ —— 内置,随包发布;
  2. ~/.deskshell/skills/(或 $DESKSHELL_SKILLS_DIR)—— 通过 deskshell add 安装。

同名时用户目录优先;因为它在包外,升级 deskhell 不会把它冲掉。

扩展点

尚待建立的能力

上文描述的 v0 内核本身不提供持久任务队列或常驻服务。新 agent 已在其外建立常驻宿主、SQLite 固定计划/批准/认领、逐步效果与有限恢复,并接入独立记事本任务和固定授权多轮;旧 CLI/Shell/MCP 尚未迁移。数据库仍不能将系统效果与日志提交变成同一原子事务,未知结果不自动重放;第三方插件沙箱尚未实现。当前实现与边界见任务运行时及路线图。