概述
failproofai 包含两个独立子系统:- 钩子处理器 - 一个快速的 CLI 子进程,Claude Code 在每次 Agent 工具调用时都会调用它。负责评估策略并返回决策结果。
- Agent 监控器(仪表板) - 一个用于监控 Agent 会话和管理策略的 Next.js Web 应用。
~/.failproofai/ 和项目 .failproofai/ 目录中的配置文件,但各自作为独立进程运行,仅通过文件系统进行通信。
钩子处理器
与 Claude Code 的集成
当你运行failproofai policies --install 时,它会将如下条目写入 ~/.claude/settings.json:
failproofai --hook PreToolUse 作为子进程调用,并通过 stdin 传递 JSON 载荷。
载荷格式
PostToolUse 事件,载荷还会包含 tool_result 字段,其中记录了工具的输出。
处理器对 stdin 强制限制为 1 MB。超出此限制的载荷将被丢弃,所有策略默认隐式放行。
响应格式
拒绝(PreToolUse):- 退出码:
2 - 原因写入 stderr(而非 stdout)
- 退出码:
0 - stdout 为空
allow(message) 允许策略在操作被放行的同时,向 Claude 发送信息性上下文。钩子处理器会将以下 JSON 写入 stdout(这不是配置文件——这是处理器对 Claude Code 的响应,与拒绝和指令响应的方式相同):
- 退出码:
0(操作被放行) - 若多个策略均返回附带消息的
allow,其消息将以换行符连接,合并为单个additionalContext字符串 - 若没有策略提供消息,则 stdout 为空(与之前的行为一致)
处理流水线
src/hooks/handler.ts 实现了完整的处理流水线:
配置加载
src/hooks/hooks-config.ts 实现了三级作用域的配置加载。
enabledPolicies- 对三个文件取去重并集policyParams- 按策略名称为键,首个定义该键的文件整体优先customPoliciesPath- 首个定义该字段的文件优先llm- 首个定义该字段的文件优先
readHooksConfig()(仅读取全局配置)进行读写,因为它不以项目的 cwd 调用。
策略评估
src/hooks/policy-evaluator.ts 按顺序运行各策略。
对于每条策略:
- 查找该策略的
params模式(如有)。 - 从合并后的配置中读取
policyParams[policy.name]。 - 将用户提供的值覆盖模式默认值,生成
ctx.params。 - 使用解析后的上下文调用
policy.fn(ctx)。 - 若结果为
deny,立即停止并返回该决策。 - 若结果为
instruct,累积消息并继续执行。 - 若结果为
allow,继续执行下一条策略。
- 若存在任意
deny结果,则输出拒绝响应。 - 若收集到任意
instruct结果,则输出单条指令响应,所有消息以换行符连接。 - 否则,输出放行响应(stdout 为空,退出码为 0)。
内置策略
src/hooks/builtin-policies.ts 将全部 39 条内置策略定义为 BuiltinPolicyDefinition 对象:
params 的策略会声明一个 PolicyParamsSchema,其中包含各参数的类型和默认值。策略评估器在调用 fn 之前,会将解析后的值注入 ctx.params。策略函数读取 ctx.params 时无需进行空值判断,因为默认值始终会被预先填充。
策略内部的模式匹配使用解析后的命令令牌(argv),而非原始字符串匹配。这可防止通过 Shell 操作符注入绕过规则(例如,针对 sudo systemctl status * 的模式,无法通过在命令末尾追加 ; rm -rf / 来绕过)。
自定义策略
src/hooks/custom-hooks-registry.ts 实现了基于 globalThis 的注册表:
src/hooks/custom-hooks-loader.ts 负责加载用户的策略文件:
- 从配置中读取
customPoliciesPath;若不存在则跳过。 - 解析为绝对路径;检查文件是否存在。
- 将所有
from "failproofai"的导入重写为实际的 dist 路径,使customPolicies能解析到同一个globalThis注册表。 - 递归重写传递性本地导入,以确保 ESM 兼容性。
- 写入临时
.mjs文件,并通过import()加载入口文件。 - 调用
getCustomHooks()获取已注册的钩子。 - 在
finally块中清理所有临时文件。
~/.failproofai/hook.log,加载器返回空数组。内置策略不受影响。
自定义策略在所有内置策略执行完毕后才会被评估。自定义策略的 deny 仍会短路后续自定义策略(但此时所有内置策略已经执行完毕)。
活动日志
每次钩子事件发生后,处理器会向~/.failproofai/hook-activity.jsonl 追加一行 JSONL 记录:
仪表板架构
仪表板是一个 Next.js 16 应用,使用 App Router,搭配 React Server Components 和 Server Actions。- 页面组件调用
lib/projects.ts和lib/log-entries.ts,直接从文件系统读取项目/会话数据(读取操作无 API 层)。 - 策略页面的所有变更操作(切换、参数更新、安装/移除)均使用 Server Actions。
- 会话查看器解析 Claude 的 JSONL 转录格式,并渲染消息和工具调用的时间线。
- 无数据库——所有持久化状态均存储于普通文件(
~/.failproofai/、~/.claude/projects/)中。 - 使用 Server Actions 进行变更操作——CRUD 操作无需 REST API。
- 读取页面使用 React Server Components——首次加载更快,无需为数据获取打包客户端代码。
- 仅在需要交互性的地方使用客户端组件(策略切换、活动搜索、日志查看器)。

