按智能体划分的集成模型
Stdin hook 子进程智能体
对这九种智能体来说,保护由运行时hook <flag> 命令提供,该命令从 stdin 读取 JSON。各智能体对执行前事件和命令工具的命名各不相同,要求的 stdout deny 形式也不同:
由于这些智能体使用不同的事件和 deny 格式,CC Safety Net 会按智能体发出正确的形式。例如,Gemini CLI 要求以 0 退出并返回
decision/systemMessage 对象,而不是 Claude Code 的 hookSpecificOutput。无需配置输出格式,传入的标志会决定使用哪种格式。使用共享 Coding CLI hook
hook --coding-cli(短标志 -cc)是 Claude 形式 hook 的规范名称。名称使用 Coding CLI,不使用 Claude Code,因为该入口点接受任何智能体发来的这种形式的 payload。
hook --claude-code 作为旧别名仍被接受,但不会在 hook --help 中列出。不要在新配置中使用。
另有三个智能体保留了省略 hook 一词的旧顶层形式:cc-safety-net -cc / --claude-code、-gc / --gemini-cli 和 -cp / --copilot-cli。规范 --coding-cli 有意不是顶层标志,单独运行 cc-safety-net --coding-cli 会报 Unknown option: --coding-cli。
Hook 配置位置
九种智能体中有五种由 CC Safety Net 直接写入文件:其中四种写为 hook 配置条目,Hermes Agent 写为托管插件。另外四种通过各自的插件或扩展分发渠道接入,再由其调用 stdin hook:
对于 Kimi Code
Bash 调用,如果存在 tool_input.cwd,它会成为执行目录。该值必须是非空字符串,且解析结果必须位于会话 cwd 内;无效或越出该目录的值会 fail closed。GitHub Copilot CLI 会把 powershell 和 PowerShell 调用路由到 PowerShell 分析器。
对于 Grok Build 调用,受信任的根目录是 workspaceRoot;没有 workspaceRoot 时用 cwd 作为根目录。cwd 必须规范化为该根目录内的某个目录,cwd 缺失或为空时按 . 处理。根目录无法规范化,或 cwd 位于根目录之外,都会 fail closed。toolInputTruncated: true 同样 fail closed:Grok Build 在 128 KB 处截断工具输入,被截断的命令无法分析。
Codex 如何到达 hook
Codex 从cc-marketplace marketplace 加载 cc-safety-net@cc-marketplace 插件。该插件按 Codex 自己的格式打包,其 manifest 指向 hooks/codex.json,由后者注册 PreToolUse hook。同一个插件还附带 cc-safety-net 技能。
Codex 不会运行未受信任的 hook,因此在 Codex 内把它标记为受信任之前,hook 一直不生效。该步骤见安装。
Hermes Agent 如何到达 hook
Hermes 不通过 hook 配置运行 hook 命令。CC Safety Net 会安装一个由 Hermes 在进程内加载的托管 Python 插件,该插件注册pre_tool_call handler。每次受支持的工具调用,handler 都会运行 npx -y cc-safety-net hook --hermes-agent,并把调用作为 JSON 写入其 stdin。空 stdout 表示允许;{ "action": "block", "message": … } 表示阻止,Hermes 会把消息作为工具结果显示给模型。
插件转发四个工具:用于命令分析的 terminal、用于受保护写入的 write_file 和 patch,以及用于受保护读取的 read_file。其他 Hermes 工具不转发,也不获得判定。
Hermes 会忽略抛出异常的插件 callback,因此插件自己把每种失败都显式转为阻止:PATH 中缺少 npx、spawn 失败、超时(30 秒,并终止分析器的整个 process group)、非零退出,或输出无法读取或不符合预期。插件读不到 Hermes 会话目录时同样会阻止,因为分析错误的目录会使所有路径范围的保护失效。
两个目录细节很重要。对 terminal 调用,插件先读取 Hermes 的每会话 cwd 记录,其中保存会话的 cd 状态。第一个命令执行时,如果该记录尚不存在,则依次使用 TERMINAL_CWD 和 Hermes 进程目录。terminal 调用带有不可用的 workdir 时会 fail closed。分析器子进程从主目录启动,而不是 Hermes 的工作目录,因此 npx 无法解析到仓库本地的 cc-safety-net 来顶替真正的那个。
每个托管文件首行都有标明其属于 CC Safety Net 的 header,安装程序拒绝覆盖没有该标记的文件。卸载会先运行 hermes plugins disable cc-safety-net 再删除文件,因为 Hermes 只能解析仍在磁盘上的插件。安装和卸载都要重启 Hermes 后才生效。设置和删除命令见安装。
与 Pi 不同,doctor 完全从磁盘检测 Hermes Agent:检查托管插件目录和 Hermes config.yaml 中的 plugins.enabled 列表,不做 runtime probe。
智能体加载的插件
OpenClaw
OpenClaw 把 CC Safety Net 作为原生插件进程内加载。插件以包含三个文件的打包目录形式分发:运行时入口index.js(所有依赖内联的自包含 bundle,因为本地目录安装没有 node_modules)、OpenClaw 在加载任何代码前验证的 openclaw.plugin.json manifest,以及 openclaw.extensions 指向该入口的 package.json。没有 hook 标志,也没有 JSON-over-stdio。
插件为 exec 工具注册 before_tool_call handler。只分析没有标签的 shell exec。带 toolKind 区分标记的 exec 事件(如 Code Mode 的 JavaScript exec)不会得到判定,因为其 command 字段并非已证实的 shell 命令映射。其他 OpenClaw 工具都不会转发给防护。Handler 要么不返回判定(允许),要么返回 { block: true, blockReason },绝不改写工具参数。
插件通过 OpenClaw runtime API 解析智能体的 workspace 目录,并把它同时用作策略目录和执行目录;调用中的 workdir 会在解析后限定在该 workspace 内。遇到格式错误的事件、缺失或为空的命令、无法解析的 workspace、workspace 之外的 workdir,或已取消的调用时,CC Safety Net 都会 fail closed。host 不是 auto 或 gateway 的 exec 调用同样会被阻止。gateway 已证明为本地。host: "auto" 或完全没有 host 的调用按本地 Gateway 语义分析,但插件不会检查 OpenClaw 实际把它路由到哪里。沙箱情况见已知限制。
插件状态由 OpenClaw 自己掌管,因此安装过程通过 OpenClaw 自身的 CLI 完成:openclaw plugins install <packaged dir> --force,然后 openclaw plugins enable cc-safety-net。执行任何 --force 命令前,CC Safety Net 都会验证目标扩展目录只含自有的托管文件,因此绝不会覆盖或删除无法证明属于自己的插件。安装后它会运行 openclaw plugins inspect cc-safety-net --runtime --json,并且只把 loaded 状态视为成功:bundle 损坏的插件即使已启用,安装过程也不会报错,之后却静默地不提供任何保护。
安装副本位于 <state dir>/extensions/cc-safety-net/。其中 state dir 为 OPENCLAW_STATE_DIR(若已设置);否则为 OPENCLAW_CONFIG_PATH 所指文件的所在目录;两者都未设置时为 ~/.openclaw。启用状态位于 OpenClaw 自身的配置中(state dir 中的 openclaw.json,或 OPENCLAW_CONFIG_PATH 指向的文件):全局 plugins.enabled 开关、plugins.allow 和 plugins.deny 列表,以及针对单个插件的 plugins.entries.cc-safety-net.enabled 条目都会起作用。设置了 plugins.allow 时,其中必须也列出 cc-safety-net。
安装或卸载后要重启 OpenClaw Gateway。Manifest 在启动时激活插件(activation: { onStartup: true }),因此正在运行的 Gateway 不会应用该更改。设置和删除命令见安装。
OpenCode
OpenCode 把 CC Safety Net 作为实现自身@opencode-ai/plugin 约定的插件对象进程内加载。插件在 ~/.config/opencode/opencode.json(或 .jsonc)的 plugin 数组中声明,并执行两项工作:
- 实现
tool.execute.before,OpenCode 在每次工具执行前都会调用它。CC Safety Net 分析该调用,并在命令具有破坏性时抛出拒绝。没有 JSON-over-stdio。 - 实现
confighook,把 CC Safety Net 的内置命令注入 OpenCode 命令集,同时不覆盖你已定义的命令。
bash 工具,插件根据 OpenCode 的 shell 设置选择分析方言。如果该设置不是字符串,Windows 上默认使用 PowerShell,其他系统使用 SHELL。识别到的 powershell 和 pwsh 可执行文件选择 PowerShell;识别到的 POSIX shell 选择 POSIX;其他值使用自动检测。只有在给定的 workdir 解析为可读、可搜索的目录时,它才会成为执行目录。在 Windows 上,会归一化文档化的 /C:、/C、/cygdrive/C 和 /mnt/C 形式,其他以斜线开头的路径保持不变,交由 OpenCode 解析。
OpenCode 可能提供插件的过期缓存副本,因此更改接入方式后,可能要清除缓存才会生效,见安装。
Pi 扩展
Pi 把 CC Safety Net 作为进程内扩展加载。扩展由软件包pi.extensions 字段声明,并在 ~/.pi/agent/settings.json 中记录为软件包来源 npm:cc-safety-net。它执行两项工作:
- 注册
tool_call事件 handler(pi.on('tool_call')),在 Pi 工具运行前检查调用。命令或路径违反策略时返回阻止结果,不跨进程边界。 - 注册
/cc-safety-net内置命令,用于在 Pi 内交互管理 rulebook。
Pi 保护的工具
Pi 的命令工具适配器只有内置的bash 工具。它的 command 在会话 cwd 下执行。已不支持旧的自定义 Shell 适配器。Pi 的非命令工具仍会进入路径保护和机密保护。其中,find 被分类为只读 glob 工具,因此会检查其 pattern 和路径值,但不会把搜索本身当作写入。命令调用或会话 cwd 格式错误时,CC Safety Net 会 fail closed。
检测 Pi
没有可检查的 hook 配置文件,因此doctor 通过 runtime probe 检测 Pi:启动 pi 并询问扩展是否已加载和启用。这就是 Pi 已安装但 probe 无法运行时,doctor 中 Pi 状态可能为 n/a 的原因。
Amp Code 事件插件
Amp Code 把 CC Safety Net 作为个人插件加载:Amp 账户托管的 Personal Plugins 仓库中一个名为cc-safety-net 的目录,里面是自包含的入口文件 index.ts。插件通过 @ampcode/plugin API 订阅 Amp 的 tool.call 事件,返回 allow 或带消息的 reject-and-continue。它和 Pi、OpenClaw、OpenCode 一样在进程内运行。个人插件跟随账户而不是单台机器,因此也覆盖在 Amp Orb 等远程执行器上运行的线程。
Amp 的 workspace 根目录(amp.system.workspaceRoot)就是配置目录。shell 工具调用带有字符串 dir 时,该值成为执行目录:相对路径基于 workspace 根目录解析,结果再经过 realpath,并且必须是已存在的目录。Windows 命名空间路径会被拒绝。无法解析的 dir 会 fail closed,也不会再对该调用做破坏性命令分析。拒绝原因不再报告分析器的意外失败,而是指明起因是工作目录,并让智能体改用已存在且可访问的目录,或先创建缺失的目录。与 OpenClaw 的 workdir 不同,解析结果不要求留在 workspace 内:Amp 把它指向自己的技能缓存或同级仓库都是正当用法,而同样的操作写成 cd <dir> && … 本来就在那里执行。配置目录仍是 workspace 根目录,因此项目自身的规则配置照常生效。Git 元数据防护同时以执行目录和配置目录为锚点,所以命令在别处执行时,workspace 自身的 .git 仍受保护。见Git 元数据。
install --amp 把 artifact 发布到该仓库:确认账户有可写的 Personal Plugins 仓库(amp plugins repositories --json),把仓库克隆到一次性 checkout(amp clone user-plugins),写入 cc-safety-net/index.ts,然后提交并推送。暂存使用明确的 pathspec(git add -- cc-safety-net/index.ts)而不是整个目录,这样插件路径被 gitignore 时会中止安装,而不是什么都不暂存。安装和卸载写入或 git rm 的始终只有这一个入口文件,因此你放在同一目录里的其他文件不会被改动。
该入口带有托管 header,标明它属于 CC Safety Net,可以安全替换。安装和卸载都会拒绝符号链接或非目录的 cc-safety-net 条目,也会拒绝符号链接、非普通文件或不带托管 header 的 index.ts。在改用目录结构之前,插件以 cc-safety-net.ts 的形式发布在仓库根目录:托管的旧文件会在同一次提交中删除,非托管的旧文件会使安装失败。
本地插件会遮蔽个人插件,因此安装还会清理 ~/.config/amp/plugins/ 下的残留:托管的旧文件 cc-safety-net.ts,以及手动复制过来、其中只有一个托管 index.ts 的 cc-safety-net/ 目录。这两个路径上的其他任何本地条目都会使安装失败。设置和删除命令见安装。
嵌入的策略快照
发布的 artifact 携带用户策略的快照:文件末尾追加一条globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = … 赋值,策略在写入前先归一化。运行时只有在自身没有策略文件的机器上(Orb 的空 home 目录)快照才生效;有策略文件的机器即使文件无效,也保持自身行为。审计保留期、用户 rulebook 和项目范围策略不会嵌入,策略修改要在下一次 install 或 update 时才发布。
Amp 启动时读取插件,因此新发布或删除的插件要重新加载 Amp 才会影响当前会话。
检测 Amp Code
doctor 通过解析 amp plugins list 输出检测插件;个人范围插件显示为 ✓ cc-safety-net (User Plugins) <status>。该输出不含版本号,因此 doctor 不会报告 Amp 的版本偏差。cc-safety-net update 始终重新发布当前 artifact。
Amp Code 覆盖限制
- Amp 不定义订阅同一
tool.call事件的多个插件之间的执行顺序。CC Safety Net 只评估它收到的输入;如果另一个插件在 CC Safety Net 允许该调用之后改写了输入,CC Safety Net 无法重新评估。
验证集成
npx cc-safety-net doctor 会报告每个智能体检测到的集成和配置路径,并在保护处于活动状态的地方运行自检。选项和退出行为见 CLI 命令。
某个智能体的 hook 未触发时,见故障排除中按智能体划分的步骤。
后续阅读
技术指南先讲用户看到的流程,再讲设计依据。本页是第 2 步。- 上一页:工作原理从头到尾说明一次工具调用的相同拦截过程。
- 下一页:架构说明本页各集成进入的防护,包括有序阶段表。
- 然后:分析引擎说明命令到达分类器后的准确分类方式。
- 最后:设计原则说明集成模型和防护顺序的设计依据。