> ## Documentation Index
> Fetch the complete documentation index at: https://exosphere-auto-translate-docs-20260626-1023.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

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

> Напишите свои собственные политики на JavaScript — соблюдайте соглашения, предотвращайте отклонения, обнаруживайте сбои, интегрируйте с внешними системами

Пользовательские политики позволяют вам написать правила для любого поведения агента: соблюдать соглашения проекта, предотвращать отклонения, ограничивать деструктивные операции, обнаруживать зависших агентов или интегрироваться с Slack, рабочими процессами утверждения и многим другим. Они используют ту же систему событий хука и решения `allow`, `deny`, `instruct`, что и встроенные политики.

***

## Быстрый пример

```js theme={null}
// my-policies.js
import { customPolicies, allow, deny, instruct } from "failproofai";

customPolicies.add({
  name: "no-production-writes",
  description: "Block writes to paths containing 'production'",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (ctx.toolName !== "Write" && ctx.toolName !== "Edit") return allow();
    const path = ctx.toolInput?.file_path ?? "";
    if (path.includes("production")) {
      return deny("Writes to production paths are blocked");
    }
    return allow();
  },
});
```

Установите её:

```bash theme={null}
failproofai policies --install --custom ./my-policies.js
```

***

## Два способа загрузки пользовательских политик

### Вариант 1: На основе соглашения (рекомендуется)

Поместите файлы `*policies.{js,mjs,ts}` в `.failproofai/policies/` и они будут загружены автоматически — не требуются флаги или изменения конфигурации. Это работает как git hooks: положите файл, и всё работает.

```
# Уровень проекта — заложено в git, поделено с командой
.failproofai/policies/security-policies.mjs
.failproofai/policies/workflow-policies.mjs

# Уровень пользователя — личное, применяется ко всем проектам
~/.failproofai/policies/my-policies.mjs
```

**Как это работает:**

* Сканируются оба каталога проекта и пользователя (объединение — не первый приоритет)
* Файлы загружаются в алфавитном порядке в каждом каталоге. Префиксируйте `01-`, `02-` для управления порядком
* Загружаются только файлы, соответствующие `*policies.{js,mjs,ts}`; другие файлы игнорируются
* Каждый файл загружается независимо (открытое поведение при ошибке для каждого файла)
* Работает вместе с явным `--custom` и встроенными политиками

<Tip>
  Политики на основе соглашения — это самый простой способ создать стандарт качества для вашей организации. Зафиксируйте `.failproofai/policies/` в git и каждый член команды автоматически получит одинаковые правила — никакой предварительной настройки для каждого разработчика не требуется. По мере того, как ваша команда обнаруживает новые сбои, добавляйте политику и выполняйте push. Со временем они станут живым стандартом качества, который постоянно улучшается с каждым вкладом.
</Tip>

### Вариант 2: Явный путь к файлу

```bash theme={null}
# Установка с пользовательским файлом политик
failproofai policies --install --custom ./my-policies.js

# Замена пути к файлу политик
failproofai policies --install --custom ./new-policies.js

# Удаление пути пользовательской политики из конфигурации
failproofai policies --uninstall --custom
```

Разрешённый абсолютный путь сохраняется в `policies-config.json` как `customPoliciesPath`. Файл загружается заново при каждом событии хука — кэширования между событиями нет.

### Использование обоих способов вместе

Политики на основе соглашения и явный файл `--custom` могут сосуществовать. Порядок загрузки:

1. Явный файл `customPoliciesPath` (если настроен)
2. Файлы соглашения проекта (`{cwd}/.failproofai/policies/`, по алфавиту)
3. Файлы соглашения пользователя (`~/.failproofai/policies/`, по алфавиту)

***

## API

### Импорт

```js theme={null}
import { customPolicies, allow, deny, instruct } from "failproofai";
```

### `customPolicies.add(hook)`

Регистрирует политику. Вызывайте это столько раз, сколько необходимо для нескольких политик в одном файле.

```ts theme={null}
customPolicies.add({
  name: string;                         // обязательно - уникальный идентификатор
  description?: string;                 // показывается в выводе `failproofai policies`
  match?: { events?: HookEventType[] }; // фильтр по типу события; опустите, чтобы совпадать со всеми
  fn: (ctx: PolicyContext) => PolicyResult | Promise<PolicyResult>;
});
```

### Вспомогательные функции решения

| Функция             | Эффект                           | Используйте когда                                             |
| ------------------- | -------------------------------- | ------------------------------------------------------------- |
| `allow()`           | Разрешить операцию беззвучно     | Действие безопасно, сообщение не требуется                    |
| `deny(message)`     | Заблокировать операцию           | Агент не должен выполнять это действие                        |
| `instruct(message)` | Добавить контекст без блокировки | Дать агенту дополнительный контекст, чтобы оставаться в курсе |

`deny(message)` — сообщение отображается для Claude с префиксом `"Blocked by failproofai:"`. Один `deny` прерывает всю дальнейшую оценку.

`instruct(message)` — сообщение добавляется в контекст Claude для текущего вызова инструмента. Все сообщения `instruct` накапливаются и доставляются вместе.

<Tip>
  Вы можете добавить дополнительное руководство к любому сообщению `deny` или `instruct`, добавив поле `hint` в `policyParams` — изменение кода не требуется. Это работает для пользовательских (`custom/`), соглашений проекта (`.failproofai-project/`) и соглашений пользователя (`.failproofai-user/`) политик тоже. See [Configuration → hint](/ru/configuration#hint-cross-cutting) для подробностей.
</Tip>

### Информационные сообщения allow

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

| Функция          | Эффект                                | Используйте когда                                                             |
| ---------------- | ------------------------------------- | ----------------------------------------------------------------------------- |
| `allow(message)` | Разрешить и отправить контекст Claude | Подтвердить успешность проверки или объяснить, почему проверка была пропущена |

Примеры использования:

* **Подтверждения статуса:** `allow("All CI checks passed.")` — сообщает Claude, что всё в порядке
* **Объяснения открытого поведения:** `allow("GitHub CLI not installed, skipping CI check.")` — сообщает Claude, почему проверка была пропущена, чтобы он имел полный контекст
* **Несколько сообщений накапливаются:** если несколько политик каждая возвращают `allow(message)`, все сообщения объединяются новыми строками и доставляются вместе

```js theme={null}
customPolicies.add({
  name: "confirm-branch-status",
  match: { events: ["Stop"] },
  fn: async (ctx) => {
    const cwd = ctx.session?.cwd;
    if (!cwd) return allow("No working directory, skipping branch check.");

    // ... проверка статуса ветки ...
    if (allPushed) {
      return allow("Branch is up to date with remote.");
    }
    return deny("Unpushed changes detected.");
  },
});
```

### Поля `PolicyContext`

| Поле        | Тип                                    | Описание                                                        |
| ----------- | -------------------------------------- | --------------------------------------------------------------- |
| `eventType` | `string`                               | `"PreToolUse"`, `"PostToolUse"`, `"Notification"`, `"Stop"`     |
| `toolName`  | `string \| undefined`                  | Вызываемый инструмент (например, `"Bash"`, `"Write"`, `"Read"`) |
| `toolInput` | `Record<string, unknown> \| undefined` | Входные параметры инструмента                                   |
| `payload`   | `Record<string, unknown>`              | Полная необработанная полезная нагрузка события из Claude Code  |
| `session`   | `SessionMetadata \| undefined`         | Контекст сеанса (см. ниже)                                      |

### Поля `SessionMetadata`

| Поле             | Тип      | Описание                              |
| ---------------- | -------- | ------------------------------------- |
| `sessionId`      | `string` | Идентификатор сеанса Claude Code      |
| `cwd`            | `string` | Рабочий каталог сеанса Claude Code    |
| `transcriptPath` | `string` | Путь к файлу стенограммы JSONL сеанса |

### Типы событий

| Событие        | Когда оно срабатывает               | Содержимое `toolInput`                                                                                                                                        |
| -------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PreToolUse`   | Перед запуском инструмента Claude   | Входные данные инструмента (например, `{ command: "..." }` для Bash)                                                                                          |
| `PostToolUse`  | После завершения инструмента        | Входные данные инструмента + `tool_result` (выходные данные)                                                                                                  |
| `Notification` | Когда Claude отправляет уведомление | `{ message: "...", notification_type: "idle" \| "permission_prompt" \| ... }` - хуки должны всегда возвращать `allow()`, они не могут блокировать уведомления |
| `Stop`         | Когда сеанс Claude заканчивается    | Пусто                                                                                                                                                         |

***

## Порядок оценки

Политики оцениваются в этом порядке:

1. Встроенные политики (в порядке определения)
2. Явные пользовательские политики из `customPoliciesPath` (в порядке `.add()`)
3. Политики соглашения из проекта `.failproofai/policies/` (файлы по алфавиту, `.add()` порядок внутри)
4. Политики соглашения из пользователя `~/.failproofai/policies/` (файлы по алфавиту, `.add()` порядок внутри)

<Note>
  Первый `deny` прерывает все последующие политики. Все сообщения `instruct` накапливаются и доставляются вместе.
</Note>

***

## Транзитивные импорты

Файлы пользовательских политик могут импортировать локальные модули, используя относительные пути:

```js theme={null}
// my-policies.js
import { isBlockedPath } from "./utils.js";
import { checkApproval } from "./approval-client.js";

customPolicies.add({
  name: "approval-gate",
  fn: async (ctx) => {
    if (ctx.toolName !== "Bash") return allow();
    const approved = await checkApproval(ctx.toolInput?.command, ctx.session?.sessionId);
    return approved ? allow() : deny("Approval required for this command");
  },
});
```

Все относительные импорты, достижимые из файла входа, разрешаются. Это реализуется путём переписывания импортов `from "failproofai"` на фактический путь dist и создания временных файлов `.mjs` для обеспечения совместимости ESM.

***

## Фильтрация типов событий

Используйте `match.events` для ограничения срабатывания политики:

```js theme={null}
customPolicies.add({
  name: "require-summary-on-stop",
  match: { events: ["Stop"] },
  fn: async (ctx) => {
    // Срабатывает только при завершении сеанса
    // ctx.session.transcriptPath содержит полный журнал сеанса
    return allow();
  },
});
```

Опустите `match` полностью, чтобы срабатывало на каждый тип события.

***

## Обработка ошибок и режимы отказа

Пользовательские политики **открыты при ошибке**: ошибки никогда не блокируют встроенные политики и не приводят к сбою обработчика хука.

| Отказ                                           | Поведение                                                                                                               |
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `customPoliciesPath` не установлен              | Явные пользовательские политики не выполняются; политики соглашения и встроенные политики продолжают работать нормально |
| Файл не найден                                  | Предупреждение записано в `~/.failproofai/hook.log`; встроенные политики продолжают работать                            |
| Синтаксическая/ошибка импорта (явная)           | Ошибка записана в `~/.failproofai/hook.log`; явные пользовательские политики пропущены                                  |
| Синтаксическая/ошибка импорта (соглашение)      | Ошибка записана; этот файл пропущен, другие файлы соглашения всё ещё загружаются                                        |
| `fn` выбрасывает исключение во время выполнения | Ошибка записана; этот хук рассматривается как `allow`; другие хуки продолжают работать                                  |
| `fn` занимает дольше 10s                        | Timeout записан; рассматривается как `allow`                                                                            |
| Каталог соглашения отсутствует                  | Политики соглашения не выполняются; нет ошибки                                                                          |

<Tip>
  Для отладки ошибок пользовательской политики смотрите файл журнала:

  ```bash theme={null}
  tail -f ~/.failproofai/hook.log
  ```
</Tip>

***

## Полный пример: несколько политик

```js theme={null}
// my-policies.js
import { customPolicies, allow, deny, instruct } from "failproofai";

// Запретить агенту писать в каталог secrets/
customPolicies.add({
  name: "block-secrets-dir",
  description: "Prevent agent from writing to secrets/ directory",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (!["Write", "Edit"].includes(ctx.toolName ?? "")) return allow();
    const path = ctx.toolInput?.file_path ?? "";
    if (path.includes("secrets/")) return deny("Writing to secrets/ is not permitted");
    return allow();
  },
});

// Держать агента в курсе: проверить тесты перед коммитом
customPolicies.add({
  name: "remind-test-before-commit",
  description: "Keep the agent on track: verify tests pass before committing",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (ctx.toolName !== "Bash") return allow();
    const cmd = ctx.toolInput?.command ?? "";
    if (/git\s+commit/.test(cmd)) {
      return instruct("Verify all tests pass before committing. Run `bun test` if you haven't already.");
    }
    return allow();
  },
});

// Запретить незапланированные изменения зависимостей во время заморозки
customPolicies.add({
  name: "dependency-freeze",
  description: "Prevent unplanned dependency changes during freeze period",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (ctx.toolName !== "Bash") return allow();
    const cmd = ctx.toolInput?.command ?? "";
    const isInstall = /^(npm install|yarn add|bun add|pnpm add)\s+\S/.test(cmd);
    if (isInstall && process.env.DEPENDENCY_FREEZE === "1") {
      return deny("Package installs are frozen. Unset DEPENDENCY_FREEZE to allow.");
    }
    return allow();
  },
});

export { customPolicies };
```

***

## Примеры

Каталог `examples/` содержит готовые к использованию файлы политик:

| Файл                                                 | Содержимое                                                                                                     |
| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `examples/policies-basic.js`                         | Пять начальных политик, охватывающих распространённые режимы отказа агента                                     |
| `examples/policies-advanced/index.js`                | Продвинутые шаблоны: транзитивные импорты, асинхронные вызовы, очистка выходных данных и хуки конца сеанса     |
| `examples/convention-policies/security-policies.mjs` | Политики безопасности на основе соглашения (блокировка записей .env, предотвращение переписывания истории git) |
| `examples/convention-policies/workflow-policies.mjs` | Политики рабочего процесса на основе соглашения (напоминания о тестах, запись файлов аудита)                   |

### Использование примеров явных файлов

```bash theme={null}
failproofai policies --install --custom ./examples/policies-basic.js
```

### Использование примеров на основе соглашения

```bash theme={null}
# Копирование на уровень проекта
mkdir -p .failproofai/policies
cp examples/convention-policies/*.mjs .failproofai/policies/

# Или копирование на уровень пользователя
mkdir -p ~/.failproofai/policies
cp examples/convention-policies/*.mjs ~/.failproofai/policies/
```

Команда установки не требуется — файлы подбираются автоматически при следующем событии хука.
