三个宿主上的真实实例
DSHA 在 Codex、Antigravity、WorkBuddy 里到底跑到哪一步,留下了什么证据。
这一篇只写本机能查到证据的部分。查不到的,直接写"没有",不编。
每条实例都附证据路径,你可以自己打开看。
先说结论
| 宿主 | 装了吗 | 真跑过吗 | 拦截生效吗 |
|---|---|---|---|
| Codex | 是(适配器 2.3.0) | 是,有完整留痕 | 是——环境激活 + 门禁都在 |
| Antigravity(Anty) | 是(47 个文件) | 安装器跑过 | 否——钩子注册了,但 enabled: false |
| WorkBuddy | 否 | 否 | 否(只有配置契约) |
三行摆在一起,本身就是一条教训:装了不等于生效。
实例一:Codex —— 最完整的一个
它长在哪
~/.codex/tools/dsha/
host.json 宿主描述:版本、源码快照、解析出的解释器、激活的变量
source/ vendored 源码(VERSION 1.3.0,40 个文件)
sources/<commit>/ 按 commit 缓存的源码快照
python-env/ 自带 Python 环境
jdk/ 自带 JDK(host.json 里带 sha256)
verification/ 每次运行的证据文件
外加 ~/.codex/config.toml 里的一段:
[mcp_servers.rea]
command = "node"
args = [".../rea-agents/scripts/rea.mjs", "mcp"]
[mcp_servers.rea.env]
GHIDRA_INSTALL_DIR = "..."
JAVA_HOME = "~/.codex/tools/dsha/jdk/jdk-21.0.12.1+1"
REA_ANALYSIS_PROVIDER = "ghidra"
REA_GHIDRA_STARTUP_TIMEOUT_MS = "5400000"
注意最后两行的位置:变量是挂在 MCP 服务器的 env 块上,只注入那个子进程,不改系统环境。这就是协议里说的"单向封套"。
一次真实的环境探测
verification/environment-20261019T142903.local.json 记录了这一轮:
| 项 | 值 |
|---|---|
| scope | whitelisted tool version probes; absence means not discovered, not proven uninstalled |
| 探测项 | 27 项 |
| 结果 | 19 PASS / 8 NOT_DISCOVERED |
| 已解析 | python, node, npm, npx, git, gh, pwsh, bash, sh, rustc, cargo, rustup, dotnet, cmake, ninja, java, javac, msbuild, cl |
| 未发现 | Go、GCC、Clang、GNU Make、Docker CLI、SQLite CLI、uv、ADB |
那份报告里有一句话值得抄下来:
未发现:仅表示本轮配置、PATH 及 SDK 候选未发现,不证明未安装。
一次真实的 EnvFeel 运行
verification/envfeel-20261019T144705.local.json:
| 段 | 值 |
|---|---|
| status | COMPLETE |
| context | PASS / Windows / runtime-reported facts, not hardware attestation |
| tools | python 3.12.14、node 24.14.1,均 PASS |
| health | 两项都跑自制最小程序并 PASS |
| activation | PREPARED,scope = child mapping only |
| 注入变量 | PATH、PYTHONUTF8、PYTHONIOENCODING、DSHA_PYTHON、DSHA_NODE |
| task | PASS,stdout = ENVFEEL_EXEC_OK |
这里有两个细节,别的宿主上不一定看得到:
scope: child mapping only——它明说了注入只作用于子进程,不动宿主。想改系统环境?不在能力范围。- 只在有自定义样本通过后才叫 PASS。版本号对得上不算数,得真跑通一段自己的代码。
教训
Codex 这一侧把"证据"做成了文件,不是屏幕上的输出。所以你三天后再来看,还能查到当时探测了什么、结果是什么、注入了哪些变量。
实例二:Antigravity(Anty)—— 装了,但门没关
它长在哪
~/.gemini/config/plugins/dsh-permissions/ 47 个文件
hooks.json PreToolUse 钩子注册
tier.json 当前挡位
rules/AGENTS.md 注入给模型的规则(6,257 B,纯 ASCII)
scripts/gate.py 门禁本体(20,861 B)
scripts/englock.py 词表校验器(24,411 B)
lexicon.json 词表(7,421 B)
~/.gemini/config/_rollback/DSHA_*/ 安装时的回滚点(3 个)
拦截链路是:
模型要动工具
↓
Antigravity 触发 PreToolUse
↓
hooks.json → scripts/run-gate.cmd
↓
scripts/gate.py 读 tier.json + lexicon.json 判一次
↓
allow / deny
实际状态
hooks.json 里是这么写的:
"dsh-permissions": {
"enabled": false,
"PreToolUse": [ ... ]
}
enabled: false。
钩子注册了,命令路径是对的,脚本都在——但开关是关的。所以此刻 Anty 里的这条门禁不拦任何东西。
tier.json 同时显示挡位是 danger-full-access:
{ "tier": "danger-full-access", "auto_reviewer": "local", "audit_logging": true, "log_allow": false }
这是最容易误判的一条。
看到 ~/.gemini/config/plugins/dsh-permissions/ 有 47 个文件,很容易得出"已经装好了、在起作用"的结论。
不是。 开关在 hooks.json 的 enabled 字段里。装完不等于启用,启用不等于生效——这三件事得分开验。
正确的确认方式是:在只读挡位下让模型去写一个文件,看它会不会被拒。拒了才算生效。
教训
安装器会备份、会写回滚点、会注册钩子——这些都对。但它不会替你把开关打开。
这是设计选择,不是缺陷:门禁装上了应当默认不改变现有行为,让人自己决定什么时候启用。代价是"装了没开"这个状态很容易被忽略。
实例三:WorkBuddy —— 本机没有
它是什么
WorkBuddy 是 REA 支持的 MCP 客户端之一。REA 的 supportedClients 列表里有:
claude_code / claude_desktop / codex / cursor / gemini_cli /
windsurf / devin / opencode / antigravity / copilot_cli / workbuddy
它的配置位置按 REA 的约定是:
~/.workbuddy/mcp.json (跨平台一致)
本机状态
~/.workbuddy 不存在。
所以这一条没有运行实例——只有配置契约。能写的只有"如果装了,会接在哪儿",写了也不是实测。
为什么不编一个?
因为这一页开头说了:查不到的写"没有"。给你一段看着很真的假日志,比告诉你"这里缺一个实例"更糟——前者会让你以为验证过了。
如果你装了 WorkBuddy,运行一次:
dsha envfeel
再把 ~/.workbuddy/mcp.json 发出来,这一节就能补成真实例。
三个实例对照:同一套东西,三种成熟度
| Codex | Anty | WorkBuddy | |
|---|---|---|---|
| 规则注入 | AGENTS.md → 提示词 | rules/AGENTS.md 6,257 B | 未装 |
| 强制位点 | MCP 服务器 env + 适配器 | PreToolUse → run-gate.cmd | 未装 |
| 环境探测 | 有留痕(27 项 / 19 PASS) | 未单独留痕 | 未装 |
| 单向封套 | 明写 child mapping only | 由 run-gate.cmd 承担 | 未装 |
| 当前生效 | 是 | 否(enabled: false) | — |
结论不是"哪家做得好",而是:同一套协议落到不同宿主上,成熟度可以差很远。 所以协议里那些 scope、NOT_RUN、未发现不等于未安装 的措辞不是啰嗦——它们就是用来防"看起来装了"的。