> ## 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. **Agent Monitor (Dashboard)** — веб-приложение 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` с выводом инструмента.

Обработчик устанавливает лимит stdin в 1 МБ. Полезные нагрузки, превышающие это значение, отбрасываются и все политики неявно разрешают.

### Формат ответа

**Deny (PreToolUse):**

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

**Deny (PostToolUse):**

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

**Instruct (любое событие кроме Stop):**

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

**Событие Stop instruct:**

* Код выхода: `2`
* Причина записана в stderr (не stdout)

**Allow:**

* Код выхода: `0`
* Пустой stdout

**Allow с сообщением:**

`allow(message)` позволяет политике отправить информационный контекст обратно Claude, даже когда операция разрешена. Обработчик хука записывает следующий JSON в **stdout** (не в файл конфигурации — это ответ обработчика Claude Code, как и ответы deny и instruct выше):

```json theme={null}
// Записано в stdout процессом обработчика хука
{
  "hookSpecificOutput": {
    "additionalContext": "All CI checks passed on branch 'feat/my-feature'."
  }
}
```

* Код выхода: `0` (операция разрешена)
* Когда несколько политик возвращают `allow` с сообщением, их сообщения объединяются с переводами строк в одну строку `additionalContext`
* Если ни одна политика не предоставляет сообщение, stdout пустой (как раньше)

### Конвейер обработки

`src/hooks/handler.ts` реализует полный конвейер:

```text theme={null}
stdin JSON
  → парсинг полезной нагрузки (макс 1 МБ)
  → извлечение метаданных сеанса (session_id, cwd, tool_name, tool_input, и т. д.)
  → readMergedHooksConfig(cwd)    ← объединяет конфигурацию проекта + локальную + глобальную
  → регистрация включенных встроенных политик с разрешенными параметрами
  → загрузка пользовательских политик из customPoliciesPath (если установлено)
  → регистрация пользовательских политик в реестре политик
  → оценка всех политик (встроенные первыми, затем пользовательские)
      → первый deny вызывает короткое замыкание
      → решения instruct накапливаются
      → сообщения allow накапливаются
  → запись решения JSON в stdout
  → сохранение события в ~/.failproofai/hook-activity.jsonl
  → выход
```

Весь процесс выполняется менее чем за 100 мс для типичных полезных нагрузок без вызовов LLM.

***

## Загрузка конфигурации

`src/hooks/hooks-config.ts` реализует загрузку конфигурации с тремя областями.

```text theme={null}
[1] {cwd}/.failproofai/policies-config.json        ← проект  (наивысший приоритет)
[2] {cwd}/.failproofai/policies-config.local.json  ← локальная
[3] ~/.failproofai/policies-config.json             ← глобальная   (наименьший приоритет)
```

Логика объединения:

* `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` определяет все 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), а не сопоставление по сырой строке. Это предотвращает обход с помощью инъекции оператора оболочки (например, паттерн для `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 { ... }  // используется в тестах
```

`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
}
```

По одной строке на политику, которая приняла решение, отличное от allow. Решения allow не регистрируются (чтобы сохранить размер файла маленьким).

***

## Архитектура панели

Панель является приложением **Next.js 16** с использованием App Router с React Server Components и Server Actions.

```text theme={null}
app/
  layout.tsx                  ← Корневой макет (тема, телеметрия, навигация)
  projects/page.tsx           ← Server component: список всех проектов Claude
  project/[name]/page.tsx     ← Server component: список сеансов в проекте
  project/[name]/session/
    [sessionId]/page.tsx      ← Server component: отображение просмотра сеанса
  policies/page.tsx           ← Client component: управление политиками + журнал активности
  actions/
    get-hooks-config.ts       ← Чтение конфигурации + список политик
    update-hooks-config.ts    ← Включение/отключение политики
    update-policy-params.ts   ← Обновление параметров политики
    get-hook-activity.ts      ← Постраничный поиск журнала активности
    install-hooks-web.ts      ← Установка/удаление хуков из браузера
  api/
    download/[project]/[session]/route.ts   ← Экспорт сеанса по CLI (JSONL или JSON)
```

**Поток данных:**

* Компоненты страниц вызывают `lib/projects.ts` и `lib/log-entries.ts` для чтения данных проекта/сеанса непосредственно из файловой системы (нет уровня API для чтения).
* Страница Policies использует Server Actions для всех изменений (переключение, обновление параметров, установка/удаление).
* Просмотрщик сеанса парсит формат стенограммы JSONL Claude и отображает хронологию сообщений и вызовов инструментов.

**Ключевые дизайн-решения:**

* Нет базы данных — все постоянное состояние находится в обычных файлах (`~/.failproofai/`, `~/.claude/projects/`).
* Server Actions для изменений — REST API не требуется для операций CRUD.
* React Server Components для страниц чтения — более быстрая начальная загрузка, нет клиентского пакета для выборки данных.
* Клиентские компоненты только там, где требуется интерактивность (переключатели политик, поиск активности, просмотр журнала).

***

## Структура файлов

```text theme={null}
failproofai/
├── bin/
│   └── failproofai.mjs           # Маршрутизатор CLI (hook / dashboard / install / и т. д.)
├── src/hooks/
│   ├── handler.ts                # Конвейер события хука
│   ├── builtin-policies.ts       # 39 определений политик
│   ├── policy-evaluator.ts       # Механизм выполнения политик
│   ├── policy-registry.ts        # Регистрация и поиск политик
│   ├── policy-types.ts           # Интерфейсы TypeScript
│   ├── hooks-config.ts           # Загрузка конфигурации с несколькими областями
│   ├── custom-hooks-registry.ts  # Реестр хуков, основанный на globalThis
│   ├── custom-hooks-loader.ts    # Загрузчик ESM для пользовательских JS хуков
│   ├── manager.ts                # Операции установки / удаления / списка
│   ├── install-prompt.ts         # Интерактивное приглашение выбора политики
│   ├── hook-logger.ts            # Логирование в hook.log
│   ├── hook-activity-store.ts    # Сохранение активности в hook-activity.jsonl
│   └── llm-client.ts             # Клиент LLM API (для политик с поддержкой AI)
├── app/                          # Next.js панель (страницы + server actions)
├── lib/                          # Общие утилиты
│   ├── projects.ts               # Перечисление проектов Claude из файловой системы
│   ├── log-entries.ts            # Парсинг формата стенограммы Claude JSONL
│   ├── paths.ts                  # Разрешение путей системы
│   └── ...
├── components/                   # Общие компоненты React UI
├── contexts/                     # Поставщики контекста React (тема, авто-обновление, телеметрия)
├── examples/                     # Примеры файлов пользовательского хука
└── __tests__/                    # Модульные и E2E тесты
```
