> ## 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.

# Конфигурация

> Формат конфига, трёхуровневая система и правила слияния

failproofai использует JSON-файлы конфигурации для управления активными политиками, их поведением и источниками загрузки пользовательских политик. Конфигурация разработана так, чтобы легко делиться ею с командой — просто закоммитьте в репо, и каждый разработчик получит одну и ту же защиту агента.

***

## Области конфигурации

Существуют три области конфигурации, оцениваемые в порядке приоритета:

| Область     | Путь файла                                | Назначение                                               |
| ----------- | ----------------------------------------- | -------------------------------------------------------- |
| **project** | `.failproofai/policies-config.json`       | Параметры репо, закоммичены в систему контроля версий    |
| **local**   | `.failproofai/policies-config.local.json` | Личные переопределения для репо, добавлены в .gitignore  |
| **global**  | `~/.failproofai/policies-config.json`     | Пользовательские значения по умолчанию для всех проектов |

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

### Правила слияния

**`enabledPolicies`** — объединение всех трёх областей. Политика, активированная на любом уровне, работает.

```text theme={null}
project:  ["block-sudo"]
local:    ["block-rm-rf"]
global:   ["block-sudo", "sanitize-api-keys"]

resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"]  ← дедублицированное объединение
```

**`policyParams`** — первая область, которая определяет параметры для конкретной политики, побеждает полностью. Глубокого слияния значений внутри параметров политики не происходит.

```text theme={null}
project:  block-sudo → { allowPatterns: ["sudo apt-get update"] }
global:   block-sudo → { allowPatterns: ["sudo systemctl status"] }

resolved: { allowPatterns: ["sudo apt-get update"] }   ← project побеждает, global игнорируется
```

```text theme={null}
project:  (нет записи block-sudo)
local:    (нет записи block-sudo)
global:   block-sudo → { allowPatterns: ["sudo systemctl status"] }

resolved: { allowPatterns: ["sudo systemctl status"] }  ← переходит к global
```

**`customPoliciesPath`** — первая область, которая её определяет, побеждает.

**`llm`** — первая область, которая её определяет, побеждает.

***

## Формат файла конфигурации

```json theme={null}
{
  "enabledPolicies": [
    "block-sudo",
    "block-rm-rf",
    "block-push-master",
    "sanitize-api-keys",
    "sanitize-jwt",
    "block-env-files",
    "block-read-outside-cwd"
  ],
  "policyParams": {
    "block-sudo": {
      "allowPatterns": ["sudo systemctl status", "sudo journalctl"]
    },
    "block-push-master": {
      "protectedBranches": ["main", "release", "prod"]
    },
    "block-rm-rf": {
      "allowPaths": ["/tmp"]
    },
    "block-read-outside-cwd": {
      "allowPaths": ["/shared/data", "/opt/company"]
    },
    "sanitize-api-keys": {
      "additionalPatterns": [
        { "regex": "myco_[A-Za-z0-9]{32}", "label": "MyCo API key" }
      ]
    },
    "warn-large-file-write": {
      "thresholdKb": 512
    }
  },
  "customPoliciesPath": "/home/alice/myproject/my-policies.js"
}
```

***

## Справочник полей

### `enabledPolicies`

Тип: `string[]`

Список имён политик для активации. Имена должны точно совпадать с идентификаторами политик, показываемыми `failproofai policies`. Полный список см. в разделе [Built-in Policies](/ru/built-in-policies).

Политики, не входящие в `enabledPolicies`, неактивны, даже если у них есть записи в `policyParams`.

### `policyParams`

Тип: `Record<string, Record<string, unknown>>`

Переопределения параметров для каждой политики. Внешний ключ — имя политики; внутренние ключи — специфичны для политики. Каждая политика документирует свои доступные параметры в разделе [Built-in Policies](/ru/built-in-policies).

Если у политики есть параметры, но вы их не указали, используются встроенные значения по умолчанию политики. Пользователи, которые вообще не настраивают `policyParams`, получают поведение, идентичное предыдущим версиям.

Неизвестные ключи внутри блока параметров политики молча игнорируются при срабатывании хука, но помечаются как предупреждения при запуске `failproofai policies`.

#### `hint` (кросс-функциональный)

Тип: `string` (опционально)

Сообщение, добавляемое к причине, когда политика возвращает `deny` или `instruct`. Используйте его, чтобы дать Claude практические рекомендации без изменения самой политики.

Работает с любым типом политики — встроенной, пользовательской (`custom/`), конвенции проекта (`.failproofai-project/`) или конвенции пользователя (`.failproofai-user/`).

```json theme={null}
{
  "policyParams": {
    "block-force-push": {
      "hint": "Try creating a fresh branch instead."
    },
    "block-sudo": {
      "allowPatterns": ["sudo apt-get"],
      "hint": "Use apt-get directly without sudo."
    },
    "custom/my-policy": {
      "hint": "Ask the user for approval first."
    }
  }
}
```

Когда `block-force-push` отклоняет, Claude видит: *Force-pushing is blocked. Try creating a fresh branch instead.*

Значения не-строкового типа и пустые строки молча игнорируются. Если `hint` не установлен, поведение не изменяется (обратная совместимость).

### `customPoliciesPath`

Тип: `string` (абсолютный путь)

Путь к JavaScript-файлу, содержащему пользовательские политики хуков. Это автоматически устанавливается `failproofai policies --install --custom <path>` (путь разрешается в абсолютный перед сохранением).

Файл загружается заново при каждом событии хука — кеширования нет. Подробности авторства см. в разделе [Custom Policies](/ru/custom-policies).

### Политики на основе конвенций

Помимо явного `customPoliciesPath`, failproofai автоматически обнаруживает и загружает файлы политик из директорий `.failproofai/policies/`:

| Уровень | Директория                 | Область                                         |
| ------- | -------------------------- | ----------------------------------------------- |
| Project | `.failproofai/policies/`   | Общее для команды через систему контроля версий |
| User    | `~/.failproofai/policies/` | Личное, применяется ко всем проектам            |

**Соответствие файлов:** Загружаются только файлы, соответствующие `*policies.{js,mjs,ts}` (например `security-policies.mjs`, `workflow-policies.js`). Другие файлы в директории игнорируются.

**Не требуется конфиг:** Политики конвенций не требуют записей в `policies-config.json`. Просто поместите файлы в директорию, и они будут загружены при следующем событии хука.

**Объединённая загрузка:** Сканируются обе директории конвенций (проекта и пользователя). Все соответствующие файлы из обоих уровней загружаются (в отличие от `customPoliciesPath`, который использует правило первой побеждающей области).

Подробности и примеры см. в разделе [Custom Policies](/ru/custom-policies).

### `llm`

Тип: `object` (опционально)

Конфигурация LLM-клиента для политик, которые делают AI-вызовы. Не требуется для большинства установок.

```json theme={null}
{
  "llm": {
    "model": "claude-sonnet-4-6",
    "apiKey": "sk-ant-..."
  }
}
```

***

## Управление конфигурацией из CLI

Команды `policies --install` и `policies --uninstall` пишут в файл параметров хука вашего CLI агента (точки входа хуков), а `policies-config.json` — это файл, которым вы управляете напрямую. Это раздельные сущности:

* **Параметры CLI агента** — указывает агенту вызывать `failproofai --hook <event>` при каждом использовании инструмента:
  * **Claude Code**: `~/.claude/settings.json` (пользователь), `<cwd>/.claude/settings.json` (проект), `<cwd>/.claude/settings.local.json` (локально)
  * **OpenAI Codex**: `~/.codex/hooks.json` (пользователь), `<cwd>/.codex/hooks.json` (проект) — Codex не имеет локальной области
  * **GitHub Copilot CLI *(бета)***: `~/.copilot/hooks/failproofai.json` (пользователь), `<cwd>/.github/hooks/failproofai.json` (проект) — Copilot не имеет локальной области. Записи хуков используют поля команд `bash`/`powershell` с ключом ОС и `timeoutSec` Copilot; файл содержит маркер `version: 1` верхнего уровня. Поддержка Copilot CLI находится в **бета-версии**, пока мы проверяем схему записи `events.jsonl` (которую общедоступные документы не указывают) против дополнительных реальных сессий.
  * **Cursor Agent *(бета)***: `~/.cursor/hooks.json` (пользователь), `<cwd>/.cursor/hooks.json` (проект) — Cursor не имеет локальной области. Записи хуков используют форму с Claude-подобной формой `{type, command, timeout}` (без разделения `bash`/`powershell`), но хранятся под camelCase ключами событий (`preToolUse`, `beforeSubmitPrompt`, …) в плоском массиве согласно [схеме хуков](https://cursor.com/docs/hooks) Cursor; файл содержит маркер `version: 1` верхнего уровня. Обработчик канонизирует camelCase → PascalCase через `CURSOR_EVENT_MAP`, поэтому существующие встроенные политики срабатывают без изменений. Поддержка Cursor Agent находится в **бета-версии**, пока мы проверяем транскрипт Cursor на диске (не указан в общедоступных документах) против дополнительных реальных установок.
  * **OpenCode *(бета)***: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (пользователь), `<cwd>/.opencode/opencode.json` + `<cwd>/.opencode/plugins/failproofai.mjs` (проект) — OpenCode не имеет локальной области. В отличие от остальных пяти CLI, OpenCode **не имеет системы внешних команд для хуков**: он загружает в процессе плагины JS/TS, явно зарегистрированные через массив `plugin: []` в `opencode.json` (автообнаружение из `.opencode/plugins/` **не** это как загружаются плагины в opencode v1.14.33). Install помещает маленький сгенерированный шим плагина, который subprocess-вызывает бинарный файл failproofai и переводит JSON-ответ бинарного файла Claude-подобной формы обратно в семантику плагина: `throw new Error()` для отрицания tool-события (отменяет вызов инструмента), `client.session.prompt(...)` для instruct И для отрицания `Stop` / `SubagentStop` (отправляет причину отрицания как следующее пользовательское сообщение — единственный канал force-retry, так как `session.idle` только для уведомления и выброс из неё — это no-op), и no-op для allow. Шим канонизирует названия инструментов (lowercase → PascalCase через `OPENCODE_TOOL_MAP`) и ключи аргументов инструментов (camelCase → snake\_case через `OPENCODE_TOOL_INPUT_MAP` для `Read` / `Write` / `Edit`, например `filePath` → `file_path`, `oldString` → `old_string`) перед отправкой в бинарный файл, поэтому встроенные проверки путей вроде `block-read-outside-cwd`, `block-env-files` и `block-secrets-write` срабатывают без изменений для вызовов инструментов OpenCode. Сессии живут в БД SQLite OpenCode в `~/.local/share/opencode/opencode.db`; средство просмотра сессий на панели инструментов читает их через `opencode db --format json` и `opencode export <id>`. Поддержка OpenCode находится в **бета-версии**, пока мы проверяем поведение в разных версиях и против дополнительных реальных сессий. См. [документацию плагинов OpenCode](https://opencode.ai/docs/plugins/).
  * **Pi *(бета)***: `~/.pi/agent/settings.json` (пользователь), `<cwd>/.pi/settings.json` (проект) — Pi не имеет локальной области. Pi загружает пакеты расширений TypeScript при запуске; файл параметров — это плоский массив строк `{"packages": ["./relative/path", …]}`. failproofai записывает одну запись packages-массива, указывающую на встроенную директорию `pi-extension/`. Расширение внутренне подписывается на события Pi `tool_call` / `user_bash` / `input` / `session_start` и shell-вызывает `failproofai --hook <Event> --cli pi`; обработчик канонизирует underscore\_lower\_snake\_case → PascalCase через `PI_EVENT_MAP`, поэтому существующие встроенные политики срабатывают без изменений. Аргументы инструментов также канонизируются через `PI_TOOL_INPUT_MAP` (Pi's Read / Write / Edit доставляют `path` вместо `file_path`; картирование верхнего уровня позволяет `block-env-files` и `block-secrets-write` срабатывать — `block-read-outside-cwd` уже имел fallback для `path`). Поддержка Pi находится в **бета-версии**, пока API расширений Pi и макет журнала сессий стабилизируются.
  * **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**только область пользователя** — Hermes не имеет конфига проекта/локально). Hermes — это **шлюз** Slack/Telegram, поэтому одна установка перехватывает вызовы инструментов от каждой платформы (Slack/Telegram/cli/cron) **и** внутренние подагенты. Записи хуков — это пара `{command, timeout}` (timeout в **секундах**) под картой `hooks:` с ключами от snake\_case событий Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); обработчик канонизирует события через `HERMES_EVENT_MAP` и названия инструментов через `HERMES_TOOL_MAP`, поэтому встроенные политики срабатывают без изменений. Конфиг редактируется через коммент-сохраняющий YAML round-trip `Document`, поэтому остальные параметры оператора выживают, и install устанавливает `hooks_auto_accept: true`, чтобы headless шлюз (без TTY) запускал хуки без промпта согласия. Оценщик выдаёт контракт `{"decision":"block","reason"}` stdout Hermes (Hermes игнорирует коды выхода). **Ограничения:** Hermes не имеет event end-turn `Stop`, поэтому встроенные `require-*-before-stop` никогда не срабатывают для него (неприменимо, не сломано); `instruct` деградирует до allow-with-logged-note (нет канала дополнительного контекста); и переписывание выходных секретов (`sanitize-*`) не может переписать вывод инструмента через shell-hook контракт. Hermes — **также** оффлайн **audit** источник — панель инструментов читает сессии шлюза напрямую из `~/.hermes/state.db`.
* **`policies-config.json`** — указывает failproofai, какие политики оценивать и с какими параметрами (общее для всех CLI агентов)

Передайте `--cli claude|codex|copilot|cursor|opencode|pi|hermes` для выбора конкретного агента (разделённые пробелом или повторённые для подмножества):

```bash theme={null}
failproofai policies --install --cli codex --scope project
failproofai policies --install --cli copilot --scope project
failproofai policies --install --cli cursor --scope project
failproofai policies --install --cli opencode --scope project
failproofai policies --install --cli pi --scope project
failproofai policies --install --cli hermes --scope user
failproofai policies --install --cli claude codex copilot cursor opencode pi
```

Когда `--cli` опущен, `failproofai` обнаруживает, какие CLI агентов установлены (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes`):

* **Один CLI обнаружен** — автоматически выбирает тот CLI без запроса.
* **Несколько CLI обнаружено** в интерактивном терминале — показывает однострочный prompt выбора со стрелками, сгруппированный в раздел `Detected (N)` (с агрегированной строкой `Install for all N detected` + каждый обнаруженный CLI отдельно) и раздел `Not installed (M) · install hooks ahead of time`, перечисляющий каждый неподдерживаемый CLI как опцию forward-install (↑↓ для перемещения, Enter для выбора, ^C для выхода). Flow разустановки показывает только раздел Detected.
* **Несколько CLI обнаружено** в неинтерактивном запуске (CI, без TTY) — устанавливает для всех обнаруженных CLI без запроса.
* **Ничего не обнаружено** — возвращается к `claude` с предупреждением, что бинарный файл агента не найден в PATH; команда хука всё ещё записывается, поэтому она активируется, как только вы установите один.

Вы можете редактировать `policies-config.json` напрямую в любой момент; изменения вступают в силу немедленно при следующем событии хука без необходимости перезагрузки.

***

## Пример: конфиг уровня проекта с командными значениями по умолчанию

Закоммитьте `.failproofai/policies-config.json` в ваш репо:

```json theme={null}
{
  "enabledPolicies": [
    "block-sudo",
    "block-rm-rf",
    "block-push-master",
    "sanitize-api-keys",
    "block-env-files"
  ],
  "policyParams": {
    "block-push-master": {
      "protectedBranches": ["main", "release", "hotfix"]
    }
  }
}
```

Каждый разработчик может затем создать `.failproofai/policies-config.local.json` (добавлен в .gitignore) для личных переопределений без влияния на товарищей по команде.
