配置作用域
共有三个配置作用域,按优先级顺序依次评估:| 作用域 | 文件路径 | 用途 |
|---|---|---|
| project | .failproofai/policies-config.json | 每个仓库的配置,提交到版本控制 |
| local | .failproofai/policies-config.local.json | 个人的仓库级覆盖配置,已加入 gitignore |
| global | ~/.failproofai/policies-config.json | 适用于所有项目的用户级默认配置 |
合并规则
enabledPolicies — 取三个作用域的并集。任意级别启用的策略均处于激活状态。
policyParams — 最先为某个策略定义参数的作用域完全优先。策略参数内部的值不会进行深度合并。
customPoliciesPath — 最先定义的作用域优先。
llm — 最先定义的作用域优先。
配置文件格式
字段参考
enabledPolicies
类型:string[]
要启用的策略名称列表。名称必须与 failproofai policies 显示的策略标识符完全匹配。完整列表请参阅内置策略。
不在 enabledPolicies 中的策略处于非激活状态,即使它们在 policyParams 中有条目也是如此。
policyParams
类型:Record<string, Record<string, unknown>>
各策略的参数覆盖配置。外层键为策略名称,内层键为各策略专属的参数。每个策略的可用参数详见内置策略。
如果某个策略有参数但你未指定,则使用该策略的内置默认值。未配置 policyParams 的用户与之前版本的行为完全一致。
策略参数块中未知的键在 hook 触发时会被静默忽略,但在运行 failproofai policies 时会以警告形式标出。
hint(通用参数)
类型:string(可选)
当策略返回 deny 或 instruct 时,附加到原因说明中的消息。使用它可以在不修改策略本身的情况下,为 Claude 提供可操作的指导。
适用于任何类型的策略——内置策略、自定义策略(custom/)、项目约定策略(.failproofai-project/)或用户约定策略(.failproofai-user/)。
hint,行为保持不变(向后兼容)。
customPoliciesPath
类型:string(绝对路径)
包含自定义 hook 策略的 JavaScript 文件路径。此路径由 failproofai policies --install --custom <path> 自动设置(路径在存储前会被解析为绝对路径)。
每次 hook 事件触发时都会重新加载该文件,不使用缓存。自定义策略的编写详情请参阅自定义策略。
基于约定的策略
除了显式指定的customPoliciesPath 外,failproofai 还会自动从 .failproofai/policies/ 目录中发现并加载策略文件:
| 级别 | 目录 | 作用域 |
|---|---|---|
| 项目级 | .failproofai/policies/ | 通过版本控制与团队共享 |
| 用户级 | ~/.failproofai/policies/ | 个人使用,适用于所有项目 |
*policies.{js,mjs,ts} 的文件(例如 security-policies.mjs、workflow-policies.js),目录中的其他文件会被忽略。
无需配置: 约定策略不需要在 policies-config.json 中添加任何条目。只需将文件放入对应目录,下次 hook 事件触发时即会自动加载。
联合加载: 项目级和用户级约定目录都会被扫描。两个级别的所有匹配文件都会被加载(与 customPoliciesPath 遵循先定义者优先的规则不同)。
更多详情和示例请参阅自定义策略。
llm
类型:object(可选)
供需要进行 AI 调用的策略使用的 LLM 客户端配置。大多数场景下无需配置。
通过 CLI 管理配置
policies --install 和 policies --uninstall 命令会写入 Agent CLI 的 hook 设置文件(hook 入口点),而 policies-config.json 是你直接管理的文件。两者是相互独立的:
- Agent CLI 设置 — 指示 Agent 在每次工具调用时执行
failproofai --hook <event>:- Claude Code:
~/.claude/settings.json(用户级)、<cwd>/.claude/settings.json(项目级)、<cwd>/.claude/settings.local.json(本地级) - OpenAI Codex:
~/.codex/hooks.json(用户级)、<cwd>/.codex/hooks.json(项目级)—— Codex 没有local作用域 - GitHub Copilot CLI (beta):
~/.copilot/hooks/failproofai.json(用户级)、<cwd>/.github/hooks/failproofai.json(项目级)—— Copilot 没有local作用域。Hook 条目使用 Copilot 的操作系统键化bash/powershell命令字段(含timeoutSec);文件顶层包含version: 1标记。Copilot CLI 支持目前处于 beta 阶段,我们正在对照更多真实场景验证events.jsonl记录的 schema(公开文档中未予说明)。 - Cursor Agent (beta):
~/.cursor/hooks.json(用户级)、<cwd>/.cursor/hooks.json(项目级)—— Cursor 没有local作用域。Hook 条目使用 Claude 格式的{type, command, timeout}(无bash/powershell分割),但按照 Cursor 的 hooks schema 以驼峰式事件键(preToolUse、beforeSubmitPrompt等)存储在平铺数组中;文件顶层包含version: 1标记。处理程序通过CURSOR_EVENT_MAP将驼峰式名称规范化为 PascalCase,因此现有内置策略无需改动即可正常触发。Cursor Agent 支持目前处于 beta 阶段,我们正在对照更多真实安装验证 Cursor 的转录文件磁盘格式(公开文档中未予说明)。 - OpenCode (beta):
~/.config/opencode/opencode.json+~/.config/opencode/plugins/failproofai.mjs(用户级),<cwd>/.opencode/opencode.json+<cwd>/.opencode/plugins/failproofai.mjs(项目级)—— OpenCode 没有local作用域。与其他六个 CLI 不同,OpenCode 没有外部命令 hook 系统:它通过opencode.json中plugin: []数组显式注册来加载进程内 JS/TS 插件(从.opencode/plugins/自动发现不是 opencode v1.14.33 插件的加载方式)。安装时会生成一个小型插件 shim,以子进程方式调用 failproofai 二进制文件,并将二进制文件的 Claude 格式 JSON 响应转换为插件语义:工具事件拒绝时throw new Error()(取消工具调用);instruct 以及Stop/SubagentStop拒绝时调用client.session.prompt(...)(将拒绝原因作为下一条用户消息提交——这是唯一的强制重试通道,因为session.idle仅用于通知,从中抛出异常无效);allow 时为空操作。shim 在转发给二进制文件之前,会将工具名称(小写 → PascalCase,通过OPENCODE_TOOL_MAP)和工具输入参数键(驼峰式 → 下划线式,通过OPENCODE_TOOL_INPUT_MAP,适用于Read/Write/Edit,例如filePath→file_path、oldString→old_string)进行规范化,因此block-read-outside-cwd、block-env-files、block-secrets-write等路径检查内置策略在 OpenCode 工具调用时无需修改即可正常触发。会话保存在 OpenCode 的 SQLite 数据库~/.local/share/opencode/opencode.db中;仪表盘的会话查看器通过opencode db --format json和opencode export <id>读取这些数据。OpenCode 支持目前处于 beta 阶段,我们正在对照更多真实场景跨版本验证其行为。详见 OpenCode 插件文档。 - Pi (beta):
~/.pi/agent/settings.json(用户级)、<cwd>/.pi/settings.json(项目级)—— Pi 没有local作用域。Pi 在启动时加载 TypeScript 扩展包;设置文件是一个平铺的字符串数组{"packages": ["./relative/path", …]}。failproofai 会写入一个 packages 数组条目,指向其捆绑的pi-extension/目录。扩展内部订阅 Pi 的tool_call/user_bash/input/session_start事件,并调用failproofai --hook <Event> --cli pi;处理程序通过PI_EVENT_MAP将下划线小写命名规范化为 PascalCase,因此现有内置策略无需改动即可正常触发。工具输入参数也通过PI_TOOL_INPUT_MAP进行规范化(Pi 的 Read / Write / Edit 使用path而非file_path;映射顶层键可使block-env-files和block-secrets-write正常触发——block-read-outside-cwd已有path回退逻辑)。Pi 支持目前处于 beta 阶段,等待 Pi 的扩展 API 和会话日志格式趋于稳定。 - Gemini CLI (beta):
~/.gemini/settings.json(用户级)、<cwd>/.gemini/settings.json(项目级)—— Gemini 没有local作用域(其文档中有位于/etc/gemini-cli/settings.json的system作用域,failproofai 不对外暴露该作用域)。Hook 条目使用 Claude 的{type, command, timeout}格式,包裹在 Gemini 的{matcher, hooks: [...]}matcher schema 中,默认matcher: "*"。事件名称为 PascalCase(SessionStart、BeforeAgent、AfterAgent、BeforeModel、AfterModel、BeforeToolSelection、BeforeTool、AfterTool、PreCompress、Notification、SessionEnd);处理程序通过GEMINI_EVENT_MAP映射到 Claude 规范名称。工具名称为 snake_case(run_shell_command、read_file、write_file、replace等)——处理程序通过GEMINI_TOOL_MAP规范化,使现有内置策略无需改动即可正常触发。策略评估器输出 Gemini 的平铺{decision: "deny", reason}格式(符合 Gemini 的”黄金规则”退出码 0 约定),在 BeforeAgent / AfterTool / SessionStart 时输出{hookSpecificOutput: {hookEventName, additionalContext}}进行上下文注入,在 AfterAgent 时输出{decision: "block", reason}以实现强制重试语义。Gemini CLI 支持目前处于 beta 阶段,我们正在扩大真实场景的覆盖范围。详见 Gemini CLI hooks 文档。
- Claude Code:
policies-config.json— 告知 failproofai 要评估哪些策略及其参数(在所有 Agent CLI 之间共享)
--cli claude|codex|copilot|cursor|opencode|pi|gemini 指定目标 Agent(空格分隔或重复指定,可选任意组合):
--cli 时,failproofai 会自动检测已安装的 Agent CLI(which claude / which codex / which copilot / which cursor-agent / which opencode / which pi / which gemini):
- 检测到一个 CLI — 自动选择该 CLI,无需提示。
- 检测到多个 CLI(交互式终端)— 显示方向键单选提示,分组展示:
已检测 (N)部分(包含一个”为所有 N 个已检测 CLI 安装”的聚合选项,以及各已检测 CLI 的单独选项)和未安装 (M) · 提前安装 hooks部分(列出每个未检测到的受支持 CLI 作为预安装选项;↑↓ 移动,Enter 选择,^C 退出)。卸载流程只显示已检测部分。 - 检测到多个 CLI(非交互式运行,如 CI 或无 TTY)— 为所有已检测 CLI 安装,无需提示。
- 未检测到任何 CLI — 回退至
claude,并警告 PATH 中未找到 Agent 二进制文件;hook 命令仍会写入,待安装后即可激活。
policies-config.json,更改在下次 hook 事件触发时立即生效,无需重启。
示例:包含团队默认配置的项目级配置
将.failproofai/policies-config.json 提交到代码仓库:
.failproofai/policies-config.local.json(已加入 gitignore),用于个人覆盖配置,而不会影响其他团队成员。
