דלג לתוכן הראשי

title: ארכיטקטורה description: “כיצד מטפל ה-hook, טעינת ההגדרות והערכת המדיניות עובדים באופן פנימי” icon: sitemap

מסמך זה מסביר כיצד failproofai עובד באופן פנימי: כיצד מערכת ה-hook מיירטת קריאות כלים של סוכנים, כיצד הגדרות נטענות ומתמזגות, כיצד מדיניות מוערכת, וכיצד לוח הבקרה עוקב אחרי פעילות סוכנים.

סקירה כללית

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

מטפל Hook

שילוב עם Claude Code

כאשר אתה מריץ failproofai policies --install, הוא כותב ערכים כמו זה לתוך ~/.claude/settings.json:
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "failproofai --hook PreToolUse"
          }
        ]
      }
    ],
    "PostToolUse": [ ... ]
  }
}
Claude Code לאחר מכן מפעיל את failproofai --hook PreToolUse כתת-תהליך לפני כל קריאת כלי, תוך העברת מטען JSON ל-stdin.

פורמט מטען

{
  "session_id": "abc123",
  "transcript_path": "/home/user/.claude/projects/myproject/sessions/abc123.jsonl",
  "cwd": "/home/user/myproject",
  "permission_mode": "default",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": { "command": "sudo apt install nodejs" }
}
לאירועי PostToolUse, המטען מכיל גם tool_result עם הפלט של הכלי. המטפל אוכף מגבלת stdin של 1 MB. מטענים החוצים זאת מושלכים וכל מדיניות מאפשרת באופן מובנה.

פורמט תجובה

Deny (PreToolUse):
{
  "hookSpecificOutput": {
    "permissionDecision": "deny",
    "permissionDecisionReason": "Blocked by failproofai: sudo command blocked"
  }
}
Deny (PostToolUse):
{
  "hookSpecificOutput": {
    "additionalContext": "Blocked by failproofai because: API key detected in output"
  }
}
Instruct (כל אירוע מלבד Stop):
{
  "hookSpecificOutput": {
    "additionalContext": "Instruction from failproofai: Verify tests pass before committing."
  }
}
אירוע Stop instruct:
  • קוד יציאה: 2
  • סיבה כתובה ל-stderr (לא stdout)
Allow:
  • קוד יציאה: 0
  • stdout ריק
Allow עם הודעה: allow(message) מאפשר למדיניות לשלוח הקשר מידע חזור ל-Claude גם כאשר הפעולה מורשית. מטפל ה-hook כותב את ה-JSON הבא ל-stdout (לא קובץ הגדרות — זו תגובת המטפל ל-Claude Code, בדיוק כמו תגובות deny ו-instruct לעיל):
// כתוב ל-stdout על ידי תהליך מטפל ה-hook
{
  "hookSpecificOutput": {
    "additionalContext": "All CI checks passed on branch 'feat/my-feature'."
  }
}
  • קוד יציאה: 0 (פעולה מורשית)
  • כאשר מדיניות מרובות מחזירות allow עם הודעה, הודעותיהן משולבות עם שורות חדשות לתוך מחרוזת additionalContext יחידה
  • אם אף מדיניות לא מספקת הודעה, stdout ריק (זהה לקודם)

צינור עיבוד

src/hooks/handler.ts מיישם את כל הצינור:
stdin JSON
  → parse payload (max 1 MB)
  → extract session metadata (session_id, cwd, tool_name, tool_input, etc.)
  → readMergedHooksConfig(cwd)    ← merges project + local + global config
  → register enabled builtin policies with resolved params
  → load custom policies from customPoliciesPath (if set)
  → register custom policies into policy registry
  → evaluate all policies (builtins first, then custom)
      → first deny short-circuits
      → instruct decisions accumulate
      → allow messages accumulate
  → write JSON decision to stdout
  → persist event to ~/.failproofai/hook-activity.jsonl
  → exit
כל התהליך פועל בפחות מ-100ms עבור מטענים טיפוסיים ללא קריאות LLM.

טעינת הגדרות

src/hooks/hooks-config.ts מיישם טעינת הגדרות בשלוש טווחים.
[1] {cwd}/.failproofai/policies-config.json        ← project  (highest priority)
[2] {cwd}/.failproofai/policies-config.local.json  ← local
[3] ~/.failproofai/policies-config.json             ← global   (lowest priority)
לוגיקת מיזוג:
  • enabledPolicies - איחוד מבודד בכל שלושה הקבצים
  • policyParams - למפתח לכל מדיניות, הקובץ הראשון שמגדיר אותו מנצח במלואו
  • customPoliciesPath - הקובץ הראשון שמגדיר אותו מנצח
  • llm - הקובץ הראשון שמגדיר אותו מנצח
לוח הבקרה בדיקה משתמש ב-readHooksConfig() (גלובאלי בלבד) לקריאה וכתיבה, מכיוון שהוא אינו מופעל עם cwd של פרויקט.

הערכת מדיניות

src/hooks/policy-evaluator.ts מפעיל מדיניות בסדר. עבור כל מדיניות:
  1. חפש את סכמת params של המדיניות (אם יש לה אחת).
  2. קרא את policyParams[policy.name] מההגדרה המתמזגת.
  3. מזג ערכים המסופקים על ידי משתמש על ברירות ברירת המחדל של הסכמה לייצור ctx.params.
  4. קרא ל-policy.fn(ctx) עם ההקשר שנפתר.
  5. אם התוצאה היא deny, עצור מיד והחזר את ההחלטה הזו.
  6. אם התוצאה היא instruct, צבור את ההודעה והמשך.
  7. אם התוצאה היא allow, המשך למדיניות הבאה.
לאחר שכל המדיניות פועלות:
  • אם הוחזר deny, פלוט את תגובת deny.
  • אם התוצאות instruct נאספו, פלוט תגובת instruct יחידה עם כל ההודעות משולבות.
  • אחרת, פלוט תגובת allow (stdout ריק, יציאה 0).

מדיניות מובנית

src/hooks/builtin-policies.ts מגדיר את כל 26 מדיניות מובנית כאובייקטי BuiltinPolicyDefinition:
interface BuiltinPolicyDefinition {
  name: string;
  description: string;
  fn: (ctx: PolicyContext) => PolicyResult;
  match: {
    events: HookEventType[];
    tools?: string[];
  };
  defaultEnabled: boolean;
  category: string;
  beta?: boolean;
  params?: PolicyParamsSchema;
}
מדיניות המקבלת params מצהירה ספכמת PolicyParamsSchema עם סוגים וברירות מחדל לכל פרמטר. מעריך המדיניות מזריק ערכים שנפתרו ל-ctx.params לפני קריאה ל-fn. פונקציות מדיניות קוראות ctx.params ללא שמירה null מכיוון שברירות מחדל מוחלות תמיד קודם. התאמת דפוס בתוך מדיניות משתמשת בטוקנים של פקודה מנותחים (argv), לא התאמה של מחרוזת גולמית. זה מונע עקיפה דרך הזרקת מפעילי shell (לדוגמה, דפוס עבור sudo systemctl status * לא יכול להיות מעוקף על ידי הוספת ; rm -rf / לפקודה).

מדיניות מותאמת אישית

src/hooks/custom-hooks-registry.ts מיישם רישום globalThis-backed:
const REGISTRY_KEY = "__failproofai_custom_hooks__";

export const customPolicies = {
  add(hook: CustomHook): void { ... }
};

export function getCustomHooks(): CustomHook[] { ... }
export function clearCustomHooks(): void { ... }  // used in tests
src/hooks/custom-hooks-loader.ts טוען את קובץ המדיניות של המשתמש:
  1. קרא את customPoliciesPath מהגדרות; דלג אם היעדר.
  2. פתור לנתיב מוחלט; בדוק שהקובץ קיים.
  3. כתוב מחדש את כל from "failproofai" כדי להסב לנתיב dist בפועל כך customPolicies מתפתר לרישום globalThis זהה.
  4. כתוב מחדש רקורסיבי יבוא מקומי חולף כדי להבטיח תאימות ESM.
  5. כתוב קבצי .mjs זמניים ו-import() הקובץ הכניסה.
  6. קרא ל-getCustomHooks() כדי לאחזר hooks שנרשמו.
  7. נקה את כל הקבצים הזמניים בבלוק finally.
בכל שגיאה (קובץ לא נמצא, שגיאת תחביר, כשל בייבוא), השגיאה נרשמת ל-~/.failproofai/hook.log והטוען מחזיר מערך ריק. מדיניות מובנית אינה מושפעת. מדיניות מותאמת אישית מוערכת לאחר כל מדיניות מובנית. מדיניות מותאמת אישית deny עדיין קוצרת מדיניות מותאמת אישית נוספת (אך כל הביומיניות כבר רצות בנקודה זו).

רישום פעילות

לאחר כל אירוע hook, המטפל מצרף שורת JSONL ל-~/.failproofai/hook-activity.jsonl:
{
  "timestamp": "2026-04-06T12:34:56.789Z",
  "sessionId": "abc123",
  "eventType": "PreToolUse",
  "toolName": "Bash",
  "policyName": "block-sudo",
  "decision": "deny",
  "reason": "sudo command blocked by failproofai",
  "durationMs": 12
}
שורה אחת לכל מדיניות שקיבלה החלטה שאינה allow. החלטות allow אינן נרשמות (כדי להקטין את גודל הקובץ).

ארכיטקטורת לוח הבקרה

לוח הבקרה הוא יישום Next.js 16 המשתמש ב-App Router עם React Server Components ו-Server Actions.
app/
  layout.tsx                  ← Root layout (theme, telemetry, nav)
  projects/page.tsx           ← Server component: list all Claude projects
  project/[name]/page.tsx     ← Server component: list sessions in a project
  project/[name]/session/
    [sessionId]/page.tsx      ← Server component: render session viewer
  policies/page.tsx           ← Client component: policy management + activity log
  actions/
    get-hooks-config.ts       ← Read config + policy list
    update-hooks-config.ts    ← Toggle policy on/off
    update-policy-params.ts   ← Update policy parameters
    get-hook-activity.ts      ← Paginate/search activity log
    install-hooks-web.ts      ← Install/remove hooks from the browser
  api/
    download/[project]/[session]/route.ts   ← Export session as ZIP/JSONL
זרימת נתונים:
  • רכיבי עמוד קוראים ל-lib/projects.ts ו-lib/log-entries.ts כדי לקרוא נתוני פרויקט/סשן ישירות מ-מערכת הקבצים (אין שכבת API לקריאה).
  • עמוד המדיניות משתמש ב-Server Actions לכל מוטציות (toggle, params update, install/remove).
  • מציג הסשן מנתח את פורמט התמלילון JSONL של Claude ומרנדר ציר זמן של הודעות וקריאות כלים.
החלטות עיצוב מרכזיות:
  • אין בסיס נתונים - כל מצב מתמשך הוא בקבצים רגילים (~/.failproofai/, ~/.claude/projects/).
  • Server Actions למוטציות - אין צורך ב-REST API עבור פעולות CRUD.
  • React Server Components עבור עמודי קריאה - טעינה ראשונית מהירה יותר, אין חבילת לקוח עבור הבאת נתונים.
  • רכיבים לקוח רק כאשר יש צורך באינטראקטיביות (toggles מדיניות, חיפוש פעילות, מציג יומן).

פריסת קובץ

failproofai/
├── bin/
│   └── failproofai.mjs           # CLI router (hook / dashboard / install / etc.)
├── src/hooks/
│   ├── handler.ts                # Hook event pipeline
│   ├── builtin-policies.ts       # 26 policy definitions
│   ├── policy-evaluator.ts       # Policy execution engine
│   ├── policy-registry.ts        # Policy registration and lookup
│   ├── policy-types.ts           # TypeScript interfaces
│   ├── hooks-config.ts           # Multi-scope config loading
│   ├── custom-hooks-registry.ts  # globalThis-backed hook registry
│   ├── custom-hooks-loader.ts    # ESM loader for user JS hooks
│   ├── manager.ts                # install / remove / list operations
│   ├── install-prompt.ts         # Interactive policy selection prompt
│   ├── hook-logger.ts            # Logging to hook.log
│   ├── hook-activity-store.ts    # Persist activity to hook-activity.jsonl
│   └── llm-client.ts             # LLM API client (for AI-powered policies)
├── app/                          # Next.js dashboard (pages + server actions)
├── lib/                          # Shared utilities
│   ├── projects.ts               # Enumerate Claude projects from filesystem
│   ├── log-entries.ts            # Parse Claude transcript JSONL format
│   ├── paths.ts                  # Resolve system paths
│   └── ...
├── components/                   # Shared React UI components
├── contexts/                     # React context providers (theme, auto-refresh, telemetry)
├── examples/                     # Example custom hook files
└── __tests__/                    # Unit and E2E tests