概要
failproofai には独立した 2 つのサブシステムがあります。- フックハンドラー - Claude Code がエージェントのツール呼び出しごとに起動する高速な CLI サブプロセス。ポリシーを評価して判断を返します。
- エージェントモニター(ダッシュボード) - エージェントセッションの監視とポリシー管理のための Next.js ウェブアプリケーション。
~/.failproofai/ とプロジェクトの .failproofai/ ディレクトリにある設定ファイルを共有しますが、それぞれ独立したプロセスとして動作し、ファイルシステムを通じてのみ通信します。
フックハンドラー
Claude Code との連携
failproofai policies --install を実行すると、~/.claude/settings.json に以下のようなエントリが書き込まれます。
failproofai --hook PreToolUse をサブプロセスとして起動し、JSON ペイロードを stdin で渡します。
ペイロードの形式
PostToolUse イベントの場合、ペイロードにはツールの出力を含む tool_result も含まれます。
ハンドラーは stdin の上限を 1 MB に制限しています。この上限を超えるペイロードは破棄され、すべてのポリシーが暗黙的に allow となります。
レスポンスの形式
Deny(PreToolUse):- 終了コード:
2 - 理由は stdout ではなく stderr に書き込まれます
- 終了コード:
0 - stdout は空
allow(message) を使うと、操作が許可された場合でもポリシーから Claude に情報コンテキストを返すことができます。フックハンドラーは以下の JSON を stdout に書き込みます(設定ファイルへの書き込みではなく、deny や instruct と同様に Claude Code へのハンドラーレスポンスです)。
- 終了コード:
0(操作は許可される) - 複数のポリシーがメッセージ付きで
allowを返した場合、それらのメッセージは改行で結合されて単一のadditionalContext文字列になります - いずれのポリシーもメッセージを提供しない場合、stdout は空(従来と同じ動作)
処理パイプライン
src/hooks/handler.ts がパイプライン全体を実装しています。
設定の読み込み
src/hooks/hooks-config.ts が 3 スコープの設定読み込みを実装しています。
enabledPolicies- 3 つのファイルにわたって重複排除した和集合policyParams- ポリシーキーごとに、最初に定義したファイルが完全に優先customPoliciesPath- 最初に定義したファイルが優先llm- 最初に定義したファイルが優先
readHooksConfig()(グローバルのみ)を使用します。
ポリシーの評価
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 に注入します。デフォルト値は常に先に適用されるため、ポリシー関数は null チェックなしで ctx.params を読み取れます。
ポリシー内のパターンマッチングは生の文字列マッチングではなく、解析済みのコマンドトークン(argv)を使用します。これにより、シェル演算子インジェクションによるバイパスを防ぎます(例: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 はそれ以降のカスタムポリシーを短絡させますが(その時点ではすべての組み込みポリシーはすでに実行済みです)。
アクティビティのログ記録
各フックイベントの後、ハンドラーは JSONL の 1 行を~/.failproofai/hook-activity.jsonl に追記します。
ダッシュボードのアーキテクチャ
ダッシュボードは App Router を使用した Next.js 16 アプリケーションで、React Server Components と Server Actions を採用しています。- ページコンポーネントは
lib/projects.tsとlib/log-entries.tsを呼び出して、ファイルシステムから直接プロジェクト/セッションデータを読み取ります(読み取りに API レイヤーなし)。 - Policies ページはすべての変更操作(切り替え、パラメーター更新、インストール/削除)に Server Actions を使用します。
- セッションビューアーは Claude の JSONL トランスクリプト形式をパースし、メッセージとツール呼び出しのタイムラインを描画します。
- データベースなし - すべての永続状態はプレーンファイル(
~/.failproofai/、~/.claude/projects/)に保存 - 変更操作に Server Actions を使用 - CRUD 操作に REST API が不要
- 読み取りページに React Server Components を使用 - 初期表示が高速でデータフェッチのクライアントバンドルが不要
- インタラクティビティが必要な箇所にのみクライアントコンポーネントを使用(ポリシーの切り替え、アクティビティ検索、ログビューアー)

