Skip to main content
מסמך זה מסביר כיצד failproofai עובד באופן פנימי: כיצד מערכת ה-Hook מיירטת קריאות Tool של Agent, כיצד Config נטען ומוזג, כיצד Policies מוערכות, וכיצד ה-Dashboard עוקב אחרי פעילות Agent.

Overview

ל-failproofai יש שתי תת-מערכות עצמאיות:
  1. Hook handler - CLI subprocess מהיר שClaude Code קורא לו בכל קריאת Tool של Agent. מעריך Policies ומחזיר החלטה.
  2. Agent Monitor (Dashboard) - אפליקציית Next.js לעקיבה אחרי סשנים של Agent וניהול Policies.
שתי התת-מערכות משתפות קבצי Config ב-~/.failproofai/ ובתיקייה .failproofai/ של הפרויקט, אך הן רצות כתהליכים נפרדים ותקשרו רק דרך מערכת הקבצים.

Hook handler

Integration עם Claude Code

כאשר אתה מריץ failproofai policies --install, הוא כותב entries כמו זה ל-~/.claude/settings.json:
Claude Code קורא אחר כך ל-failproofai --hook PreToolUse כ-subprocess לפני כל קריאת Tool, ומעביר JSON payload על stdin.

פורמט Payload

עבור אירועי PostToolUse, ה-payload גם כולל tool_result עם Output של ה-Tool. ה-Handler אוכף מגבלת stdin של 1 MB. Payloads החוצים זאת מושלכים וכל Policies באופן implicit מאפשרים.

Response format

Deny (PreToolUse):
Deny (PostToolUse):
Instruct (כל אירוע למעט Stop):
Stop event instruct:
  • Exit code: 2
  • Reason כתוב ל-stderr (לא stdout)
Allow:
  • Exit code: 0
  • stdout ריק
Allow עם Message: allow(message) מאפשר לPolicy לשלוח Context informational חזרה ל-Claude גם כאשר הפעולה מותרת. ה-Hook Handler כותב את ה-JSON הבא ל-stdout (לא קובץ Config — זה ה-Response של ה-Handler ל-Claude Code, בדיוק כמו Deny ו-Instruct responses למעלה):
  • Exit code: 0 (הפעולה מותרת)
  • כאשר multiple Policies מחזירות allow עם Message, ה-Messages שלהם מצורפות עם newlines לתוך string additionalContext יחיד
  • אם אף Policy לא מספק Message, stdout ריק (כמו קודם)

Processing pipeline

src/hooks/handler.ts מיישם את כל ה-Pipeline:
כל התהליך רץ בפחות מ-100ms עבור Payloads טיפוסיים בלי LLM calls.

Configuration loading

src/hooks/hooks-config.ts מיישם שלוש-scope Config loading.
Merge logic:
  • enabledPolicies - deduplicated union על כל שלושת הקבצים
  • policyParams - per-policy key, הקובץ הראשון שמגדיר אותו מנצח לחלוטין
  • customPoliciesPath - הקובץ הראשון שמגדיר אותו מנצח
  • llm - הקובץ הראשון שמגדיר אותו מנצח
ה-Web Dashboard משתמש ב-readHooksConfig() (global only) לקריאה וכתיבה, מכיוון שהוא לא קרוא עם Project cwd.

Policy evaluation

src/hooks/policy-evaluator.ts מריץ Policies בסדר. עבור כל Policy:
  1. חפש את ה-params schema של ה-Policy (אם יש לו).
  2. קרא policyParams[policy.name] מה-Merged Config.
  3. Merge user-provided values על schema defaults לייצור ctx.params.
  4. קרא policy.fn(ctx) עם ה-Resolved Context.
  5. אם ה-Result הוא deny, עצור מיד וחזור בהחלטה זו.
  6. אם ה-Result הוא instruct, צבור את ה-Message והמשך.
  7. אם ה-Result הוא allow, המשך ל-Policy הבא.
לאחר שכל Policies רצים:
  • אם כל deny חזר, emit את ה-Deny Response.
  • אם כל instruct returns נאספו, emit Response instruct יחיד עם כל Messages מצורפות.
  • אחרת, emit Allow Response (stdout ריק, exit 0).

Builtin policies

src/hooks/builtin-policies.ts מגדיר את כל 39 ה-Builtin Policies כ-BuiltinPolicyDefinition objects:
Policies שמקבלות params מכריזות PolicyParamsSchema עם Types וDefaults עבור כל Parameter. ה-Policy Evaluator משדר Resolved Values ל-ctx.params לפני קריאה ל-fn. Policy Functions קוראות ctx.params בלי Null-Guarding כי Defaults תמיד מיושמות ראשון. Pattern Matching בתוך Policies משתמש בParsed Command Tokens (argv), לא Raw String Matching. זה מונע Bypass דרך Shell Operator Injection (למשל Pattern עבור sudo systemctl status * לא יכול להיות bypassed על ידי Appending ; rm -rf / לפקודה).

Custom policies

src/hooks/custom-hooks-registry.ts מיישם globalThis-backed Registry:
src/hooks/custom-hooks-loader.ts טוען את Policy File של ה-User:
  1. קרא customPoliciesPath מ-Config; דלג אם חסר.
  2. Resolve ל-Absolute Path; בדוק אם הקובץ קיים.
  3. כתוב מחדש את כל from "failproofai" Imports ל-Actual Dist Path כדי שה-customPolicies יתמוקד ל-globalThis Registry אותו.
  4. כתוב מחדש באופן Recursive Transitive Local Imports כדי להבטיח ESM Compatibility.
  5. כתוב Temporary .mjs Files ו-import() את Entry File.
  6. קרא getCustomHooks() כדי לאחזר Registered Hooks.
  7. נקה את כל Temp Files בבלוק finally.
בכל Error (File not found, Syntax Error, Import Failure), ה-Error נרשם ל-~/.failproofai/hook.log ו-Loader מחזיר Array ריק. Builtin Policies לא מושפעות. Custom Policies מוערכות לאחר כל Builtin Policies. Custom Policy deny עדיין Short-Circuits Further Custom Policies (אבל כל ה-Builtins כבר רצו בנקודה זו).

Activity logging

לאחר כל Hook Event, ה-Handler Appends JSONL Line ל-~/.failproofai/hook-activity.jsonl:
שורה אחת לכל Policy שעשה Decide שאינו Allow. Allow Decisions לא נרשמות (כדי לשמור את הקובץ קטן).

Dashboard architecture

ה-Dashboard היא אפליקציית Next.js 16 באמצעות App Router עם React Server Components ו-Server Actions.
Data flow:
  • Page Components קוראים ל-lib/projects.ts ו-lib/log-entries.ts כדי לקרוא Project/Session Data ישירות מ-Filesystem (אין API Layer עבור Reads).
  • ה-Policies Page משתמשת ב-Server Actions עבור כל Mutations (Toggle, Params Update, Install/Remove).
  • ה-Session Viewer מנתח Claude’s JSONL Transcript Format ומרנדר Timeline של Messages וTool Calls.
Key Design Decisions:
  • No Database - כל Persistent State נמצא בקבצים רגילים (~/.failproofai/, ~/.claude/projects/).
  • Server Actions לMutations - אין צורך ב-REST API עבור CRUD Operations.
  • React Server Components לRead Pages - Fast Initial Load, לא Client Bundle עבור Data Fetching.
  • Client Components רק כאשר Interactivity נדרשת (Policy Toggles, Activity Search, Log Viewer).

File layout