Skip to main content

title: Архитектура description: “Как работают обработчик крючков, загрузка конфигурации и оценка политик” icon: sitemap

Этот документ объясняет внутреннее устройство failproofai: как система крючков перехватывает вызовы инструментов агента, как загружается и объединяется конфигурация, как оцениваются политики и как панель мониторинга отслеживает активность агента.

Обзор

failproofai состоит из двух независимых подсистем:
  1. Обработчик крючков — быстрый CLI подпроцесс, который Claude Code вызывает при каждом вызове инструмента агента. Оценивает политики и возвращает решение.
  2. Монитор агента (Панель) — веб-приложение Next.js для мониторинга сеансов агента и управления политиками.
Обе подсистемы используют файлы конфигурации в ~/.failproofai/ и в директории проекта .failproofai/, но работают как отдельные процессы и взаимодействуют только через файловую систему.

Обработчик крючков

Интеграция с Claude Code

Когда вы выполняете failproofai policies --install, он записывает записи вроде этой в ~/.claude/settings.json:
Claude Code затем вызывает failproofai --hook PreToolUse как подпроцесс перед каждым вызовом инструмента, передавая JSON-полезную нагрузку на stdin.

Формат полезной нагрузки

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

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

Запретить (PreToolUse):
Запретить (PostToolUse):
Инструктировать (любое событие кроме Stop):
Событие Stop с инструкцией:
  • Код выхода: 2
  • Причина записывается в stderr (не в stdout)
Разрешить:
  • Код выхода: 0
  • Пустой stdout
Разрешить с сообщением: allow(message) позволяет политике отправить информационный контекст обратно Claude даже когда операция разрешена. Обработчик крючков записывает следующий JSON в stdout (не в файл конфигурации — это ответ обработчика на Claude Code, так же как запрет и инструкции выше):
  • Код выхода: 0 (операция разрешена)
  • Когда несколько политик возвращают allow с сообщением, их сообщения объединяются новыми строками в одну строку additionalContext
  • Если ни одна политика не предоставляет сообщение, stdout пустой (как и раньше)

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

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

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

src/hooks/hooks-config.ts реализует загрузку конфигурации с тремя уровнями видимости.
Логика объединения:
  • 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:
Политики, которые принимают params, объявляют PolicyParamsSchema с типами и значениями по умолчанию для каждого параметра. Оценщик политик внедряет разрешенные значения в ctx.params перед вызовом fn. Функции политик читают ctx.params без проверок на null, потому что значения по умолчанию всегда применяются первыми. Сопоставление шаблонов внутри политик использует разобранные токены команд (argv), а не прямое сопоставление строк. Это предотвращает обход через инъекции операторов оболочки (например, шаблон для sudo systemctl status * не может быть обойден путем добавления ; rm -rf / к команде).

Пользовательские политики

src/hooks/custom-hooks-registry.ts реализует реестр на основе globalThis:
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:
Одна строка на политику, которая приняла решение не-разрешение. Решения о разрешении не регистрируются (чтобы файл был меньше).

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

Панель — это приложение Next.js 16, использующее App Router с React Server Components и Server Actions.
Поток данных:
  • Компоненты страниц вызывают lib/projects.ts и lib/log-entries.ts для прямого чтения данных проекта/сеанса из файловой системы (нет API слоя для чтения).
  • Страница Политик использует Server Actions для всех мутаций (переключение, обновление параметров, установка/удаление).
  • Средство просмотра сеансов анализирует формат JSONL-транскрипта Claude и отображает временную шкалу сообщений и вызовов инструментов.
Ключевые решения по проектированию:
  • Нет базы данных — все постоянное состояние находится в простых файлах (~/.failproofai/, ~/.claude/projects/).
  • Server Actions для мутаций — не требуется REST API для операций CRUD.
  • React Server Components для страниц чтения — быстрая первоначальная загрузка, нет клиентского пакета для выборки данных.
  • Клиентские компоненты только где нужна интерактивность (переключатели политик, поиск активности, средство просмотра логов).

Расположение файлов