概述
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 的响应,与 deny 和 instruct 响应方式相同):
- 退出码:
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返回,输出 deny 响应。 - 若收集到任何
instruct返回,输出单个 instruct 响应,所有消息拼接在一起。 - 否则,输出 allow 响应(stdout 为空,退出码 0)。
内置策略
src/hooks/builtin-policies.ts 将全部 39 条内置策略定义为 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——更快的首屏加载,无需客户端数据获取 bundle。
- 仅在需要交互性时使用 Client 组件(策略切换、活动搜索、日志查看器)。

