概述
failproofai 包含两个独立的子系统:- 钩子处理器 - 一个高速 CLI 子进程,Claude Code 在每次 Agent 工具调用时调用它。负责评估策略并返回决策结果。
- Agent 监控器(仪表板) - 一个 Next.js Web 应用,用于监控 Agent 会话和管理策略。
~/.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 的响应,与 deny 和 instruct 响应的方式相同):
- 退出码:
0(操作被允许) - 当多个策略返回带消息的
allow时,其消息将以换行符拼接为一个additionalContext字符串 - 若没有策略提供消息,stdout 为空(与之前行为相同)
处理流水线
src/hooks/handler.ts 实现了完整的处理流水线:
配置加载
src/hooks/hooks-config.ts 实现了三级范围的配置加载。
enabledPolicies- 三个文件取去重并集policyParams- 按策略名称为键,第一个定义该键的文件完全优先customPoliciesPath- 第一个定义它的文件优先llm- 第一个定义它的文件优先
readHooksConfig()(仅全局)进行读写。
策略评估
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 将全部 26 条内置策略定义为 BuiltinPolicyDefinition 对象:
params 的策略会声明一个 PolicyParamsSchema,为每个参数指定类型和默认值。策略评估器在调用 fn 前将解析后的值注入 ctx.params。策略函数读取 ctx.params 时无需空值判断,因为默认值始终会被预先应用。
策略内部的模式匹配使用已解析的命令 token(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——加快首次加载速度,数据获取无需客户端包。
- 仅在需要交互的地方使用客户端组件(策略切换、活动搜索、日志查看器)。

