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

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 event instruct:
  • קוד יציאה: 2
  • סיבה כתובה ל-stderr (לא stdout)
Allow:
  • קוד יציאה: 0
  • stdout ריק
Allow עם הודעה: allow(message) מאפשר למדיניות לשלוח הקשר מידע חזרה ל-Claude גם כאשר הפעולה מותרת. מטפל ה-hook כותב את ה-JSON הבא ל-stdout (לא קובץ תצורה — זהו התגובה של מטפל ה-hook ל-Claude Code, בדיוק כמו תגובות deny ו-instruct לעיל):
// Written to stdout by the hook handler process
{
  "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 - union מפושט בכל שלוש הקבצים
  • policyParams - לכל-מדיניות מפתח, הקובץ הראשון המגדיר אותו מנצח לחלוטין
  • customPoliciesPath - הקובץ הראשון המגדיר אותו מנצח
  • llm - הקובץ הראשון המגדיר אותו מנצח
לוח הבקרה של האינטרנט משתמש ב-readHooksConfig() (global בלבד) לקריאה וכתיבה, מכיוון שהוא לא משודר עם 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 ריק, exit 0).

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

src/hooks/builtin-policies.ts מגדיר את כל 39 המדיניות המובנית כאובייקטי 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 * לא יכול להיות bypassed על ידי הוספת ; rm -rf / לפקודה).

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

src/hooks/custom-hooks-registry.ts מיישם רישום מבוסס globalThis:
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   ← Per-CLI session export (JSONL or JSON)
זרימת נתונים:
  • רכיבי עמוד קוראים lib/projects.ts ו-lib/log-entries.ts כדי לקרוא נתוני פרויקט/session ישירות מהמערכת קבצים (אין שכבת API לקריאה).
  • עמוד המדיניות משתמש ב-Server Actions לכל התמורות (toggle, עדכון params, התקנה/הסרה).
  • מסמך ה-session מנתח את פורמט התמלול JSONL של Claude ומעבד ציר זמן של הודעות וקריאות כלי.
החלטות עיצוב מפתח:
  • אין מסד נתונים - כל מצב קבוע נמצא בקבצים רגילים (~/.failproofai/, ~/.claude/projects/).
  • Server Actions למוטציות - אין צורך בAPI REST עבור פעולות 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       # 39 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