跳转到主要内容
自定义规则用你写的原因,阻止内置规则放行的命令,例如 git push 或 npm install -g。规则写在 rulebook 文件中,每个范围的 rule.json 列出要加载的 rulebook。自定义规则只会新增阻止,绝不放宽内置规则。
旧版内联配置文件(.safety-net.json 和 ~/.cc-safety-net/config.json)已不再加载。在迁移之前,其中的规则不起任何作用。
/cc-safety-net 技能可以替你编写规则。说明你想要什么即可,例如 /cc-safety-net block terraform destroy in this project。

规则配置文件位置

CC Safety Net 从两个范围加载 rulebook 并合并:
  1. 用户范围:~/.cc-safety-net/rules/rule.json(用 rule init --global 创建)。用于适用于所有项目的个人默认规则。
  2. 项目范围:项目根目录下的 .cc-safety-net/rules/rule.json。用于可提交到版本控制的团队或项目专属规则。
两个文件都不存在时,只有内置规则生效。在存放用户 .cc-safety-net/ 的目录(通常是主目录)中,项目路径就是用户配置,因此写入项目范围的 rule 子命令在那里会拒绝运行。参见在用户配置目录中运行 rule。

范围合并行为

  • CC Safety Net 先加载用户范围,再合并两个范围的 rulebook。
  • 两个范围列出同名 rulebook 时,以用户范围的为准,项目范围的那个不贡献任何规则。CC Safety Net 会报告警告,运行时显示 degraded。重命名其中一个即可解决。
  • 每个范围的 overrides 只作用于本范围的规则,因此项目配置无法关闭或改写用户规则。指向用户规则的项目覆盖,以及不匹配任何规则的覆盖键,都会被忽略并报告警告。
  • 两个范围的 transparent_wrappers 和 command_tools 会合并。

管理 rulebook 来源

rule.json 的 rules 数组中的每个条目都是一个 rulebook 来源: 请用 rule 命令管理来源,不要手动编辑 rule.json:
加上 --global(-g)即可修改用户范围而不是项目范围。--only 和 --ref 的说明见官方 rulebook,每个子命令及其输出和错误见 rule。

rulebook 是实时文件

运行时在每次工具调用时从磁盘读取每个 rulebook.json,因此保存的修改从下一条命令起生效。缺失、不可读或无效的 rulebook 不贡献任何规则,运行时报告 degraded。对于从未获取过的 GitHub 来源,请运行 npx -y cc-safety-net rule update。参见配置恢复。

透明包装器

透明包装器是运行另一条命令的命令,例如 timeout 5 git push。CC Safety Net 会穿过透明包装器,看到它实际运行的命令,因此内置规则和自定义规则对 timeout 5 docker system prune 的作用与对 docker system prune 相同。 有八个包装器是内置的,无需配置:caffeinate、exec、nice、nohup、setsid、stdbuf、time 和 timeout。 如果团队通过 rtk 等其他包装器运行命令,请添加它:
  • 包装器名称必须匹配 ^[a-zA-Z][a-zA-Z0-9_-]*$,且在文件内唯一。
  • 保留命令不能作为包装器:git、busybox、rm、find、xargs、parallel、所有 shell 包装器、所有解释器以及 awk 解释器。
  • 只添加按原样运行子命令的包装器。
你添加的包装器保存在 rule.json 中,因此 rule.json 不可读时它们会失效。参见 rule.json 中声明的覆盖范围。

社区 shell 工具

插件可以为智能体添加自带的 shell 工具,例如 dsh-ops 插件会加入 ops_bash 和 ops_run_background。CC Safety Net 不认识这些名称,因此只检查它们的路径参数,从不把它们的 command 当作 shell 命令解析。在你声明之前,ops_bash 执行 git reset --hard 不会被阻止。 声明该工具后,CC Safety Net 就会分析它的命令:
这会写入 command_tools 数组:
从下一次工具调用起,已声明工具的调用会和内置 shell 工具一样,适用相同的内置规则、自定义规则和安全级别。此时 ops_bash 执行 git reset --hard 会被 git.reset-hard 阻止。
  • 名称必须与智能体发送的工具名完全一致,包括大小写。rule tool add 会拒绝内置工具名。参见 rule tool add 名称错误。
  • cwd 指出由哪个参数承载工作目录。未指定时,CC Safety Net 读取 workdir、cwd 或 working_directory,都没有则使用会话工作区。工作目录为空白时,该调用以 tool-call.malformed 拒绝;目录不存在时,以 cwd.requested-unusable 拒绝。
  • "cwd": false 适用于在另一台机器(例如手机或远程主机)上执行命令的工具。CC Safety Net 不会为它读取工作目录参数,因此上述两种拒绝都不适用,每条命令都以会话工作区为基准检查。rm -rf build 这类相对路径在该工作区内判定,而不是在远程目录中。
声明保存在 rule.json 中,因此 rule.json 不可读时,该范围声明的工具会失效。手动编辑该文件后,请运行 npx -y cc-safety-net rule verify。

创建你的第一条自定义规则

1

创建 rule.json

这会创建一个空的 .cc-safety-net/rules/rule.json,其中没有任何 rulebook 来源:
rule init --example 还会在 .cc-safety-net/rules/example-rules/rulebook.json 写入一个示例 rulebook。在运行 npx -y cc-safety-net rule add example-rules 之前,它不会生效。
2

编写 rulebook

创建 .cc-safety-net/rules/project-rules/rulebook.json:
3

注册 rulebook

现在 rule.json 中列有 "rules": ["project-rules"]。从下一条命令起,CC Safety Net 会以你写的原因阻止 git add -A、git add --all 和 git add .。
4

验证 rulebook

rule verify 会检查两个范围的 rule.json,按运行时的方式加载每个来源,并运行版本 2 的 fixture。它从不获取远程内容。

rule.json schema

rule.json 选择生效的 rulebook、应用覆盖,并声明透明包装器和社区 shell 工具。安全级别、内置保护、允许路径和拒绝路径以及审计保留期在另一个文件中配置,参见策略。
integer
必填
Schema 版本,必须为 1。
array
rulebook 来源字符串列表,默认为空数组。来源名称在文件内必须唯一,文件最多列出 64 个来源。
object
以 <rulebook-name>/<rule-name> 为键的规则覆盖。值可以是 "off"(关闭该规则),也可以是一个对象(替换该规则的阻止消息)。对象形式必须包含 reason,可以带上可选的 intent;省略 intent 时,规则自身的意图保持不变。
array
在八个内置包装器之外,额外需要穿过的命令,默认为空数组。条目必须唯一,且不能是保留命令。参见透明包装器。
array
插件提供的 shell 工具,CC Safety Net 会像分析内置 shell 工具一样分析它的 command。每个条目可以是工具名,也可以是 { "name": "ops_bash", "cwd": "dir" } 这样的对象,其中 cwd 为参数名或 false。默认为空数组。名称必须唯一,且不能是内置工具名。参见社区 shell 工具。
同时替换消息和面向智能体的意图的覆盖如下:

rule.json 编辑器支持

CC Safety Net 为 rule.json 发布了一份 JSON Schema。把编辑器指向它,即可获得补全和校验:
对于缺少这一行的有效 rule.json,rule verify 会补上 $schema。policy.json 没有发布 schema。

Rulebook schema

每个 rulebook 都放在各自的 rulebook.json 文件中。
integer
必填
rulebook schema 版本,必须为 1 或 2。其他值会以 rulebook_version must be 1 or 2 校验失败。参见版本 2 规则。
string
必填
rulebook 名称,必须与本地目录名或 GitHub 来源名称一致。
string
必填
rulebook 版本字符串。
string
rulebook 的可读描述。
string
rulebook 作者。
array
必填
此 rulebook 可以为其定义规则的命令。
array
必填
自定义阻止规则。参见规则 schema。
array
可选的 rulebook fixture。参见 Fixture schema。

规则 schema

以下字段定义 rulebook_version 1 的规则。版本 2 用 match 对象取代了 subcommand 和 block_args,参见版本 2 规则。
string
必填
在 rulebook 内唯一的名称,最多 64 个字符。必须以字母开头,后跟字母、数字、连字符或下划线。
string
必填
要匹配的基础命令,必须列在 allowed_commands 中。
string
要匹配的子命令,例如 add 或 install。省略时匹配任何子命令。
array
必填
触发阻止的参数。至少需要一个,因此版本 1 规则无法阻止某个子命令的所有用法。这种需求请用版本 2 规则。
string
必填
规则阻止命令时 CC Safety Net 显示的消息,最多 256 个字符。
string
给智能体的意图,追加在阻止消息的页脚。取 hard_stop、use_alternative、scope_down、manual_only 或 stop_and_explain 之一,默认为 manual_only。

版本 2 规则

设置 "rulebook_version": 2,即可按精确的命令路径匹配,而不是子命令加一组参数。在 gcloud compute 下阻止 delete 的版本 1 规则,会在命令中任意位置查找该 token,因此也会阻止 gcloud compute instances create delete;命令路径为 ["compute", "instances", "delete"] 的版本 2 规则则不会。 版本 2 规则沿用版本 1 的 name、command、reason 和 intent,并用 match 对象取代 subcommand 和 block_args。
array
必填
必须按顺序跟在命令后面的命令词,是由非空字符串组成的非空数组。由于路径不能为空,没有规则能匹配某个命令的所有调用,例如所有 aws 调用。
array
参数中必须至少字面出现其中一个 token。由非空字符串组成、无重复的非空数组。省略时,命令路径匹配后不论参数如何都会命中。
array
参数中只要字面出现其中任意一个 token,规则就不匹配。由非空字符串组成、无重复的非空数组。
版本 2 不会忽略版本 1 的字段,而是直接拒绝。仍带有 subcommand 或 block_args 的规则会以 rules[0].subcommand: not supported in rulebook_version 2 和 rules[0].block_args: not supported in rulebook_version 2 校验失败。

Fixture schema

Fixture 用于记录预期行为。CC Safety Net 解析其中的命令,交给该 rulebook 的规则求值,但从不执行它们。
string
必填
Shell 命令 fixture。
string
必填
blocked 或 allowed。
string
预期会阻止该命令的规则。blocked fixture 必填。
版本 1 的 fixture 只校验结构。rule add、rule update 和 rule verify 会对版本 2 的 fixture 求值。blocked fixture 在它指定的规则第一个命中时通过,allowed fixture 在没有任何规则命中时通过。 rule add 和 rule update 会在写入之前拒绝 fixture 失败的来源。每条失败都以该 fixture 在 tests 中的下标标明:
rule verify 会在每条前面加上 rulebook 文件名,形如 example-rules/rulebook.json: tests[0]: ...。

匹配行为

两个版本都按字面匹配 token,区分大小写,不支持正则表达式、glob 或子串匹配。--all-files 不匹配 --all。规则按顺序求值,第一条命中的规则产生阻止。 规则同样作用于嵌套命令。为 rm 写了规则后,bash -c 'rm -r ./tmpdir'、eval 'rm -r ./tmpdir' 和被调用的函数正文都会被阻止,内置分析器同样覆盖的命令也不例外。

版本 2 的全局选项

CC Safety Net 只认识 aws、gcloud 和 az 的带值全局选项。对其他命令,取值分开书写的选项(如 git -C repo push)会导致规则匹配不上。Terraform 的 -chdir=DIR 是单个 token,会被跳过。 发布通道需要单独的规则。gcloud beta compute instances delete 不匹配 ["compute", "instances", "delete"],请另写一条 ["beta", "compute", "instances", "delete"] 的规则。
CC Safety Net 把 -Cfoo 视为 -C -f -o -o,而不是 -C foo。因此阻止 -f 的规则可能误匹配紧贴在选项后的取值。

规则匹配的是命令,不是文件路径

自定义规则匹配的是 shell 命令及其参数。它看不到智能体用自带的读取和编辑工具打开的文件,因此规则无法保护 ~/.zshrc 这样的文件。要阻止对某个文件或目录的一切访问,请把它加入 policy.json 的 secret_protection.deny_paths。拒绝路径也会阻止读取。

示例

阻止所有 git push

command_path: ["push"] 且不带 any_args 的版本 2 规则,会阻止带任何参数的 git push。版本 1 规则做不到这一点,因为 block_args 至少需要一个参数。
由于 timeout 是透明包装器,这条规则也会阻止 timeout 5 git push。它不会命中 git -C repo push。参见版本 2 的全局选项。

关闭单条规则

要关闭某条自定义规则,在列出该 rulebook 的那个范围的 rule.json 中,把它的 <rulebook-name>/<rule-name> 键加入 overrides,值设为 "off"。阻止消息中会打印这个键。
rulebook 文件本身保持不变,因此 rule update 不会撤销这条覆盖。要关闭 git.push-force 这样的内置规则,请改用 policy.json,参见允许被阻止的命令。

阻止全局 npm 安装

阻止消息格式

阻止消息的完整布局见阻止消息的形式。自定义规则会在原因前加上 rulebook 名称和规则名称,便于看出是哪个 rulebook 触发了阻止:
前缀 <rulebook-name>/<rule-name> 也是你在 rule.json 的 overrides 中用来关闭该规则或替换其原因的键。

迁移旧配置

CC Safety Net 不再加载旧版内联配置文件(.safety-net.json 和 ~/.cc-safety-net/config.json)。其中的规则不起作用,运行时也不会给出警告。npx -y cc-safety-net doctor 和 rule verify 会把残留的文件报告为 Legacy inline rule configs are ignored。
rule migrate 没有 --global,会同时迁移两个范围。在主目录中运行时,它会跳过项目范围。参见在用户配置目录中运行 rule migrate。 它会把内联文件转换为以下布局:

无效的自定义规则配置

CC Safety Net 会丢弃加载失败的自定义规则配置,而不是拒绝命令。其他来源和内置规则继续生效,运行时报告 degraded。阻止因此减少时不会有任何提醒,所以编辑规则或升级后,请运行 npx -y cc-safety-net status。参见配置恢复。
自定义规则配置不具备防篡改能力。智能体可以编辑 rule.json 和 rulebook 文件,只有 policy.json 是受保护路径。手动添加或修改自定义规则后,请用 npx -y cc-safety-net rule verify 验证。
最后修改于 2026年11月8日