Agent 工程对照
← 返回框架对照

运行时 · 第 8 章

沙箱与权限

模型要执行一条 shell 命令,什么东西挡在它和操作系统之间?

Codex 与 DeepSeek 把隔离下沉到操作系统,openJiuwen 与 Pi 停在策略层。

隔离落在哪一层

策略层

操作系统

场景建议

编辑判断

按你的需求,倾向哪种做法

借鉴的是那一家的设计,不等于选用那个框架。

场景

要在开发者本机上真正挡住危险命令

只有这两家下沉到操作系统层;openJiuwen 与 Pi 停在策略层或目录信任。

场景

每次放行或拒绝都要能说清理由

它的规则引擎返回 ALLOW / ASK / DENY 以及命中的规则名和理由,多条命中时取最严格的一档。

场景

已经跑在容器里,不想重复造隔离

Pi 只问「你信任这个目录吗」,OS 级沙箱只以示例扩展形式存在,把隔离交给运行环境。

容易踩的坑

  • Codex 与 DeepSeek 用的模式名一模一样,含义却不同层:一个是协议枚举,一个是事件折叠结果。借名字之前先看它落在哪一层。

四家怎么做

差异与源码

openJiuwen

策略层规则引擎,三档判定 allow / ask / deny

没有操作系统级沙箱(仓库内检索不到 seatbelt / landlock / bwrap)。防线是一套分级权限引擎:内置 YAML 规则库、shell AST 解析(shell_ast.py)、路径匹配器与参数规则命中,最终把每次工具调用归结为 ALLOW / ASK / DENY 三档,并返回命中的规则名与理由。多条规则命中时取最严格的一档。

适合
需要可审计的规则、并且要返回命中理由的企业流程。
代价
只有策略层,没有 OS 级隔离;规则漏判的命令会直接落到系统上。
Codex

协议里的类型枚举,落到 seatbelt / landlock / Windows

沙箱模式是协议层的一个带数据的枚举,序列化为 kebab-case 传给所有前端。它不是描述性标签——codex-rs/sandboxing 下有 seatbelt(macOS,含 .sbpl 策略文件)、landlock 与 bwrap(Linux)、windows.rs 的真实实现,以及独立的 execpolicy 与 shell-escalation。注意 WorkspaceWrite 分支携带 writable_roots 和 network_access:权限边界是有结构的数据,不是一个布尔开关。

适合
在开发者本机上跑、必须跨 macOS / Linux / Windows 真隔离的编码 Agent。
代价
每个平台一套实现(seatbelt、landlock、bwrap、Windows),维护面最大。

此后的变化

  • 2026-W40 →

    回合级授权与严格审查状态改为挂在发起请求的回合上,后台 code-mode cell 跨回合继续运行时不会丢掉授权,也不会借用新回合的权限;会话级授权仍跨回合共享。

  • 2026-W35 →

    两处变化:授权有效性与对话历史解耦;Guardian 分类转为异步,Node REPL 首次 js 执行不等分类直接放行,后续按正常策略审查。

DeepSeek Harness

同样三个模式名,但状态是会话事件的折叠结果

模式名与 Codex 逐字相同,实现哲学却相反:切换沙箱模式不写配置文件,而是往会话日志里追加一条 sandbox/mode 事件;当前生效值等于「折叠所有事件的结果 ?? 部署默认值」。源码注释点破了这样做的收益——重启后靠重放日志恢复,不需要任何追赶机制;两个会话永远看不到对方的状态;也就不存在外部配置存储。这是「事件日志即状态」用在权限上的一个样本。

适合
权限切换本身要可追溯、可重放的系统。
代价
要接受「状态等于事件折叠」的心智模型,排查时得看事件日志而不是配置文件。
Pi

不做沙箱,改问「你信任这个目录吗」

内核里没有沙箱:OS 级隔离只以示例扩展形式存在于 examples/extensions/sandbox/,bash-executor.ts 全文检索不到 sandbox 字样。取而代之的是目录级信任——首次进入一个项目目录时弹出确认,用户授权后才加载该目录的配置、安装缺失依赖、执行项目扩展。这是把隔离责任显式交还给用户和运行环境(容器、CI)的选择,与其「内核要小到能读懂」的主张一致。

适合
本来就跑在容器或 CI 里、隔离已由外部环境提供的场景。
代价
内核不隔离,把责任交给用户和运行环境;直接在本机跑时风险自负。
横向读这一行

分成两个层次而不是四种方案:Codex 与 DeepSeek 真正下沉到操作系统(seatbelt / landlock / bwrap / Windows ACL),openJiuwen 与 Pi 停在策略层(规则引擎 / 目录信任)。更有意思的是 Codex 与 DeepSeek 用了完全相同的三个模式名 read-only / workspace-write / danger-full-access,但一个把它定义成协议里的类型枚举,另一个把它定义成会话事件日志的折叠结果。

设计空间分析

codex 和 deepseek harness 用的是同一套三档模式名,但格子显示出的是完全不同的实现哲学;openJiuwen 和 pi 都没有内核级 OS 沙箱,却分别选择了「建规则引擎」和「问用户信不信」两条相反的路。

openJiuwen 没有 OS 级沙箱(格子说明仓库内检索不到 seatbelt / landlock / bwrap),防线是一套策略层规则引擎:内置 YAML 规则库、shell AST 解析(shell_ast.py)、路径匹配器与参数规则命中,最终把每次工具调用归结为 PermissionLevel 的 ALLOW / ASK / DENY 三档,PermissionResult 带 matched_rule 和 reason,多条规则命中时取最严格的一档。

codex 的沙箱模式是协议层的带数据枚举 SandboxPolicy,序列化为 kebab-case 传给所有前端,不是描述性标签——codex-rs/sandboxing 下有 seatbelt(macOS,含 .sbpl 策略文件)、landlock 与 bwrap(Linux)、windows.rs 的真实实现,另有独立的 execpolicy 与 shell-escalation。WorkspaceWrite 分支携带 writable_roots 和 network_access 两个字段,权限边界是结构化数据,不是一个布尔开关。

deepseek harness 的 SANDBOX_MODES 是 ['read-only', 'workspace-write', 'danger-full-access'],与 codex 的三个模式名逐字相同,但状态模型是反过来的:切换沙箱模式不写配置文件,而是往会话日志追加一条 sandbox/mode 事件;当前生效值等于 fold(events) ?? 部署默认值。源码注释点出这样做的收益:重启后靠重放日志恢复,不需要追赶机制;两个会话永远看不到对方的状态;也就不存在外部配置存储。

pi 的内核里同样没有沙箱:OS 级隔离只以示例扩展形式存在于 examples/extensions/sandbox/,bash-executor.ts 全文检索不到 sandbox 字样。取而代之的是目录级信任:formatProjectTrustPrompt 在首次进入项目目录时弹出确认,用户授权后才加载该目录配置、安装缺失依赖、执行项目扩展——隔离责任被显式交还给用户和运行环境。

编辑判断

codex 和 deepseek harness 共享同一套模式命名,容易让人误以为两家的沙箱实现是同一件事,但格子里能看到的落地方式完全不同:codex 的三档背后是 seatbelt / landlock / bwrap / windows.rs 这些真实的操作系统级实现,deepseek harness 的三档背后是一套事件日志折叠出来的状态值,格子本身没有写明这个状态值最终如何在操作系统层面被强制执行。名字相同不代表防线的位置相同。另外,openJiuwen 与 pi 都没有内核级 OS 沙箱,但选择的补偿方式相反——前者建一整套规则引擎自己判定,后者把判断交还给用户的一次性信任决定——这也是编辑判断,不是任一项目的官方表述。

还没有定论:deepseek harness 的 sandbox/mode 事件折叠机制只说明了「模式值如何被记录和读取」,格子本身没有说明这个值最终靠什么去约束进程能不能读写文件或联网——是否存在与 codex 的 seatbelt/landlock 对等的强制执行层,目前没有读到对应源码,不能假定两者在「强制执行」这一步是等价的。

这个问题为什么存在

第 8 章

运行时、可靠性与安全

生产级 Agent:幂等、隔离、身份与网关