> ## Documentation Index
> Fetch the complete documentation index at: https://docs.befailproof.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Architecture

title: البنية المعمارية
description: "كيفية عمل معالج الخطاف وتحميل الإعدادات وتقييم السياسات بشكل داخلي"
icon: sitemap
-------------

تشرح هذه الوثيقة كيفية عمل failproofai داخليًا: كيف يعترض نظام الخطاف استدعاءات أدوات الوكيل، وكيف يتم تحميل الإعدادات ودمجها، وكيف يتم تقييم السياسات، وكيف تراقب لوحة المعلومات نشاط الوكيل.

***

## نظرة عامة

يحتوي failproofai على نظامين فرعيين مستقلين:

1. **معالج الخطاف** - عملية CLI سريعة يستدعيها Claude Code على كل استدعاء لأداة وكيل. يقيّم السياسات ويعيد قرارًا.
2. **مراقب الوكيل (لوحة المعلومات)** - تطبيق ويب Next.js لمراقبة جلسات الوكيل وإدارة السياسات.

يشارك كلا النظامين الفرعيين ملفات الإعدادات في `~/.failproofai/` ودليل المشروع `.failproofai/`، لكنهما يعملان كعمليات منفصلة ولا يتواصلان إلا عبر نظام الملفات.

***

## معالج الخطاف

### التكامل مع Claude Code

عند تشغيل `failproofai policies --install`، يكتب إدخالات مثل هذه في `~/.claude/settings.json`:

```json theme={null}
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "failproofai --hook PreToolUse"
          }
        ]
      }
    ],
    "PostToolUse": [ ... ]
  }
}
```

ثم يستدعي Claude Code `failproofai --hook PreToolUse` كعملية فرعية قبل كل استدعاء أداة، ويمرر حمولة JSON على stdin.

### تنسيق الحمولة

```json theme={null}
{
  "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` بمخرجات الأداة.

يفرض المعالج حد أقصى بحجم 1 ميجابايت على stdin. يتم تجاهل الحمولات التي تتجاوز هذا الحد وتسمح جميع السياسات ضمنيًا.

### تنسيق الاستجابة

**رفض (PreToolUse):**

```json theme={null}
{
  "hookSpecificOutput": {
    "permissionDecision": "deny",
    "permissionDecisionReason": "Blocked by failproofai: sudo command blocked"
  }
}
```

**رفض (PostToolUse):**

```json theme={null}
{
  "hookSpecificOutput": {
    "additionalContext": "Blocked by failproofai because: API key detected in output"
  }
}
```

**تعليمات (أي حدث ما عدا Stop):**

```json theme={null}
{
  "hookSpecificOutput": {
    "additionalContext": "Instruction from failproofai: Verify tests pass before committing."
  }
}
```

**حدث التعليمات الخاص:**

* رمز الخروج: `2`
* السبب المكتوب على stderr (وليس stdout)

**السماح:**

* رمز الخروج: `0`
* stdout فارغ

**السماح مع رسالة:**

يسمح `allow(message)` لسياسة بإرسال سياق معلومات مرة أخرى إلى Claude حتى عند السماح بالعملية. يكتب معالج الخطاف JSON التالي إلى **stdout** (وليس ملف إعدادات — هذه هي استجابة المعالج لـ Claude Code، تمامًا مثل استجابات الرفض والتعليمات أعلاه):

```json theme={null}
// 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` خط الأنابيب الكامل:

```text theme={null}
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
```

تعمل العملية بأكملها في أقل من 100 ميلي ثانية للحمولات النموذجية بدون استدعاءات LLM.

***

## تحميل الإعدادات

تنفذ `src/hooks/hooks-config.ts` تحميل الإعدادات ثلاثي النطاق.

```text theme={null}
[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`، صدر استجابة الرفض.
* إذا تم جمع أي استجابات `instruct`، أصدر استجابة تعليمات واحدة مع دمج جميع الرسائل.
* بخلاف ذلك، أصدر استجابة سماح (stdout فارغ، الخروج 0).

***

## السياسات المدمجة

تحدد `src/hooks/builtin-policies.ts` جميع 39 سياسة مدمجة كائنات `BuiltinPolicyDefinition`:

```typescript theme={null}
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` دون حماية فارغة لأن الافتراضيات يتم تطبيقها دائمًا أولاً.

يستخدم تطابق النمط داخل السياسات رموز الأوامر المحللة (argv)، وليس مطابقة السلسلة الخام. هذا يمنع الالتفاف عبر حقن مشغلات shell (على سبيل المثال، نمط لـ `sudo systemctl status *` لا يمكن التفافه عن طريق إضافة `; rm -rf /` إلى الأمر).

***

## السياسات المخصصة

تنفذ `src/hooks/custom-hooks-registry.ts` سجل مدعوم بـ `globalThis`:

```typescript theme={null}
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()` لاسترجاع الخطافات المسجلة.
7. نظف جميع الملفات المؤقتة في كتلة `finally`.

عند أي خطأ (ملف غير موجود، خطأ بناء جملة، فشل استيراد)، يتم تسجيل الخطأ إلى `~/.failproofai/hook.log` ويعيد المحمل مصفوفة فارغة. السياسات المدمجة لم تتأثر.

يتم تقييم السياسات المخصصة بعد جميع السياسات المدمجة. لا يزال `deny` السياسة المخصصة يختصر السياسات المخصصة الإضافية (لكن جميع المدمجة قد عملت بالفعل في هذه المرحلة).

***

## تسجيل النشاط

بعد كل حدث خطاف، يضيف المعالج سطر JSONL إلى `~/.failproofai/hook-activity.jsonl`:

```json theme={null}
{
  "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
}
```

سطر واحد لكل سياسة اتخذت قرارًا بعدم السماح. لا يتم تسجيل قرارات السماح (للحفاظ على حجم الملف صغيرًا).

***

## بنية لوحة المعلومات

لوحة المعلومات عبارة عن تطبيق **Next.js 16** يستخدم App Router مع React Server Components و Server Actions.

```text theme={null}
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` لقراءة بيانات المشروع/الجلسة مباشرة من نظام الملفات (لا توجد طبقة API للقراءات).
* تستخدم صفحة السياسات Server Actions لجميع التغييرات (تبديل، تحديث المعاملات، التثبيت/الإزالة).
* يحلل عارض الجلسة تنسيق نصوص JSONL الخاص بـ Claude ويرسم خط زمني للرسائل واستدعاءات الأدوات.

**قرارات التصميم الرئيسية:**

* لا قاعدة بيانات - جميع الحالات الدائمة موجودة في ملفات عادية (`~/.failproofai/`, `~/.claude/projects/`).
* Server Actions للتغييرات - لا توجد حاجة إلى REST API لعمليات CRUD.
* React Server Components لصفحات القراءة - تحميل أسرع للبداية، لا توجد حزمة عميل لجلب البيانات.
* مكونات العميل فقط حيث تكون التفاعلية مطلوبة (تبديلات السياسة، البحث عن النشاط، عارض السجل).

***

## تخطيط الملفات

```text theme={null}
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
```
