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

# Plugin-хуки

Хуки Plugin — це внутрішньопроцесні точки розширення для Plugin OpenClaw. Використовуйте їх,
коли Plugin має перевіряти або змінювати запуски агентів, виклики інструментів, потік повідомлень,
життєвий цикл сеансу, маршрутизацію субагентів, встановлення або запуск Gateway.

Натомість використовуйте [внутрішні хуки](/uk/automation/hooks), коли вам потрібен невеликий
встановлений оператором скрипт `HOOK.md` для подій команд і Gateway, як-от
`/new`, `/reset`, `/stop`, `agent:bootstrap` або `gateway:startup`.

## Швидкий старт

Зареєструйте типізовані хуки Plugin за допомогою `api.on(...)` з точки входу вашого Plugin:

```typescript theme={"theme":{"light":"min-light","dark":"min-dark"}}
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";

export default definePluginEntry({
  id: "tool-preflight",
  name: "Tool Preflight",
  register(api) {
    api.on(
      "before_tool_call",
      async (event) => {
        if (event.toolName !== "web_search") {
          return;
        }

        return {
          requireApproval: {
            title: "Run web search",
            description: `Allow search query: ${String(event.params.query ?? "")}`,
            severity: "info",
            timeoutMs: 60_000,
            timeoutBehavior: "deny",
          },
        };
      },
      { priority: 50 },
    );
  },
});
```

Обробники хуків виконуються послідовно в порядку спадання `priority`. Хуки з однаковим пріоритетом
зберігають порядок реєстрації.

`api.on(name, handler, opts?)` приймає:

* `priority` - порядок обробників (вище значення виконується першим).
* `timeoutMs` - необов’язковий бюджет для окремого хука. Коли його задано, засіб виконання хуків перериває цей
  обробник після вичерпання бюджету й переходить до наступного, замість того щоб
  дозволити повільному налаштуванню або відновленню даних використати налаштований для викликача тайм-аут моделі.
  Пропустіть його, щоб використати стандартний тайм-аут спостереження/рішення, який
  засіб виконання хуків застосовує загально.

Оператори також можуть задавати бюджети хуків без виправлення коду Plugin:

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "plugins": {
    "entries": {
      "my-plugin": {
        "hooks": {
          "timeoutMs": 30000,
          "timeouts": {
            "before_prompt_build": 90000,
            "agent_end": 60000
          }
        }
      }
    }
  }
}
```

`hooks.timeouts.<hookName>` перевизначає `hooks.timeoutMs`, який перевизначає
значення `api.on(..., { timeoutMs })`, задане автором Plugin. Кожне налаштоване значення має
бути додатним цілим числом не більше ніж 600000 мілісекунд. Надавайте перевагу перевизначенням для окремих хуків
для відомо повільних хуків, щоб один Plugin не отримував довший бюджет
усюди.

Кожен хук отримує `event.context.pluginConfig`, розв’язану конфігурацію для
Plugin, який зареєстрував цей обробник. Використовуйте її для рішень хуків, яким потрібні
поточні параметри Plugin; OpenClaw ін’єктує її для кожного обробника без зміни
спільного об’єкта події, який бачать інші Plugin.

## Каталог хуків

Хуки згруповано за поверхнею, яку вони розширюють. Назви, виділені **жирним**, приймають
результат рішення (блокування, скасування, перевизначення або вимогу схвалення); усі інші
призначені лише для спостереження.

**Хід агента**

* `before_model_resolve` - перевизначити провайдера або модель до завантаження повідомлень сеансу
* `agent_turn_prepare` - спожити поставлені в чергу ін’єкції ходу Plugin і додати контекст того самого ходу перед хуками промпта
* `before_prompt_build` - додати динамічний контекст або текст системного промпта перед викликом моделі
* `before_agent_start` - комбінована фаза лише для сумісності; надавайте перевагу двом хукам вище
* **`before_agent_run`** - перевірити фінальний промпт і повідомлення сеансу перед надсиланням до моделі та за потреби заблокувати запуск
* **`before_agent_reply`** - коротко замкнути хід моделі синтетичною відповіддю або мовчанням
* **`before_agent_finalize`** - перевірити природну фінальну відповідь і запросити ще один прохід моделі
* `agent_end` - спостерігати фінальні повідомлення, стан успіху та тривалість запуску
* `heartbeat_prompt_contribution` - додати контекст лише для Heartbeat для фонових моніторів і Plugin життєвого циклу

**Спостереження за розмовою**

* `model_call_started` / `model_call_ended` - спостерігати санітизовані метадані виклику провайдера/моделі, час, результат і обмежені хеші ідентифікаторів запиту без вмісту промпта або відповіді
* `llm_input` - спостерігати вхідні дані провайдера (системний промпт, промпт, історію)
* `llm_output` - спостерігати вихідні дані провайдера, використання та розв’язаний `contextTokenBudget`, коли він доступний

**Інструменти**

* **`before_tool_call`** - переписати параметри інструмента, заблокувати виконання або вимагати схвалення
* `after_tool_call` - спостерігати результати інструмента, помилки та тривалість
* `resolve_exec_env` - надати змінні середовища, якими володіє Plugin, для `exec`
* **`tool_result_persist`** - переписати повідомлення асистента, створене з результату інструмента
* **`before_message_write`** - перевірити або заблокувати запис повідомлення в процесі (рідко)

**Повідомлення й доставка**

* **`inbound_claim`** - заявити право на вхідне повідомлення до маршрутизації агента (синтетичні відповіді)
* `message_received` — спостерігати вхідний вміст, відправника, тред і метадані
* **`message_sending`** — переписати вихідний вміст або скасувати доставку
* **`reply_payload_sending`** — змінити або скасувати нормалізовані корисні навантаження відповідей перед доставкою
* `message_sent` — спостерігати успіх або невдачу вихідної доставки
* **`before_dispatch`** - перевірити або переписати вихідне надсилання перед переданням каналу
* **`reply_dispatch`** - брати участь у фінальному конвеєрі надсилання відповіді

**Сеанси та Compaction**

* `session_start` / `session_end` - відстежувати межі життєвого циклу сеансу. `reason` події є одним із `new`, `reset`, `idle`, `daily`, `compaction`, `deleted`, `shutdown`, `restart` або `unknown`. Значення `shutdown` і `restart` спрацьовують із фіналізатора вимкнення Gateway, коли процес зупиняється або перезапускається, поки сеанси ще активні, щоб нижчі за потоком Plugin (наприклад, сховища пам’яті або транскриптів) могли фіналізувати фантомні рядки, які інакше залишилися б у відкритому стані між перезапусками. Фіналізатор обмежений, тож повільний Plugin не може заблокувати SIGTERM/SIGINT.
* `before_compaction` / `after_compaction` - спостерігати або анотувати цикли Compaction
* `before_reset` - спостерігати події скидання сеансу (`/reset`, програмні скидання)

**Субагенти**

* `subagent_spawned` / `subagent_ended` - спостерігати запуск і завершення субагента.
* `subagent_delivery_target` - хук сумісності для доставки завершення, коли прив’язка основного сеансу не може спроєктувати маршрут.
* `subagent_spawning` - застарілий хук сумісності. Тепер ядро готує прив’язки субагентів `thread: true` через адаптери прив’язки сеансів каналів до спрацьовування `subagent_spawned`.
* `subagent_spawned` містить `resolvedModel` і `resolvedProvider`, коли OpenClaw розв’язав нативну модель дочірнього сеансу перед запуском.
* `subagent_ended` несе `targetSessionKey` (ідентичність — це відповідає `subagent_spawned.childSessionKey`), `targetKind` (`"subagent"` або `"acp"`), `reason`, необов’язковий `outcome` (`"ok"`, `"error"`, `"timeout"`, `"killed"`, `"reset"` або `"deleted"`), необов’язковий `error`, `runId`, `endedAt`, `accountId` і `sendFarewell`. Він **не** містить `agentId` або `childSessionKey`; використовуйте `targetSessionKey`, щоб співвіднести його з відповідною подією `subagent_spawned`.

**Життєвий цикл**

* `gateway_start` / `gateway_stop` - запускати або зупиняти сервіси, якими володіє Plugin, разом із Gateway
* `deactivate` - застарілий псевдонім сумісності для `gateway_stop`; використовуйте `gateway_stop` у нових Plugin
* `cron_changed` - спостерігати зміни життєвого циклу Cron, яким володіє Gateway (додано, оновлено, видалено, запущено, завершено, заплановано)
* **`before_install`** - перевірити підготовлені матеріали встановлення Skills або Plugin із завантаженого
  середовища виконання Plugin

## Налагодження хуків середовища виконання

Використовуйте `before_model_resolve`, коли Plugin має перемкнути провайдера або модель
для ходу агента. Він виконується до розв’язання моделі; `llm_output` виконується лише після того, як
спроба моделі створить вихідні дані асистента.

Для підтвердження ефективної моделі сеансу перевірте реєстрації середовища виконання, а потім
використайте `openclaw sessions` або поверхні сеансу/стану Gateway. Під час налагодження
корисних навантажень провайдера запустіть Gateway з `--raw-stream` і
`--raw-stream-path <path>`; ці прапорці записують сирі події потоку моделі у файл jsonl.

## Політика викликів інструментів

`before_tool_call` отримує:

* `event.toolName`
* `event.params`
* необов’язкові `event.toolKind` і `event.toolInputKind`, авторитетні для хоста
  дискримінатори для інструментів, які навмисно мають спільні назви; наприклад, зовнішні
  виклики `exec` у режимі коду використовують `toolKind: "code_mode_exec"` і
  містять `toolInputKind: "javascript" | "typescript"`, коли мова вводу
  відома
* необов’язковий `event.derivedPaths`, що містить отримані хостом на основі найкращих зусиль підказки цільових шляхів
  для добре відомих оболонок інструментів, таких як `apply_patch`; коли вони присутні,
  ці шляхи можуть бути неповними або можуть завищувати обсяг того, чого інструмент
  фактично торкнеться (наприклад, із пошкодженими або частковими вхідними даними)
* необов’язковий `event.runId`
* необов’язковий `event.toolCallId`
* поля контексту, як-от `ctx.agentId`, `ctx.sessionKey`, `ctx.sessionId`,
  `ctx.runId`, `ctx.jobId` (задано для запусків, керованих Cron), `ctx.toolKind`,
  `ctx.toolInputKind` і діагностичний `ctx.trace`

Він може повернути:

```typescript theme={"theme":{"light":"min-light","dark":"min-dark"}}
type BeforeToolCallResult = {
  params?: Record<string, unknown>;
  block?: boolean;
  blockReason?: string;
  requireApproval?: {
    title: string;
    description: string;
    severity?: "info" | "warning" | "critical";
    timeoutMs?: number;
    timeoutBehavior?: "allow" | "deny";
    allowedDecisions?: Array<"allow-once" | "allow-always" | "deny">;
    pluginId?: string;
    onResolution?: (
      decision: "allow-once" | "allow-always" | "deny" | "timeout" | "cancelled",
    ) => Promise<void> | void;
  };
};
```

Поведінка захисту хуків для типізованих хуків життєвого циклу:

* `block: true` є термінальним і пропускає обробники з нижчим пріоритетом.
* `block: false` розглядається як відсутність рішення.
* `params` переписує параметри інструмента для виконання.
* `requireApproval` призупиняє запуск агента й запитує користувача через схвалення Plugin.
  Команда `/approve` може схвалювати як exec, так і схвалення Plugin.
  У нативних ретрансляціях `PreToolUse` режиму звіту сервера застосунку Codex це відкладається
  до відповідного запиту схвалення сервера застосунку; див. [середовище виконання обв’язки Codex](/uk/plugins/codex-harness-runtime#hook-boundaries).
* `block: true` з нижчим пріоритетом усе ще може заблокувати після того, як хук із вищим пріоритетом
  запросив схвалення.
* `onResolution` отримує розв’язане рішення схвалення - `allow-once`,
  `allow-always`, `deny`, `timeout` або `cancelled`.

Див. [запити дозволів Plugin](/uk/plugins/plugin-permission-requests) щодо
маршрутизації схвалень, поведінки рішень і того, коли використовувати `requireApproval` замість
необов’язкових інструментів або схвалень exec.

Plugin, яким потрібна політика рівня хоста, можуть реєструвати довірені політики інструментів за допомогою
`api.registerTrustedToolPolicy(...)`. Вони виконуються перед звичайними
хуками `before_tool_call` і перед нормальними рішеннями хуків. Вбудовані довірені
політики виконуються першими; довірені політики встановлених Plugin виконуються далі в порядку завантаження Plugin;
звичайні хуки `before_tool_call` виконуються після них. Вбудовані Plugin зберігають
наявний шлях довіреної політики. Встановлені Plugin мають бути явно ввімкнені
і оголошувати кожен ідентифікатор політики в `contracts.trustedToolPolicies`; неоголошені ідентифікатори
відхиляються до реєстрації. Ідентифікатори політик обмежені Plugin, який їх реєструє,
тому різні Plugin можуть повторно використовувати той самий локальний ідентифікатор. Використовуйте цей рівень лише
для довірених хостом шлюзів, як-от політика робочої області, примусове дотримання бюджету або
безпека зарезервованих робочих процесів.

### Хук середовища exec

`resolve_exec_env` дозволяє Plugin надавати змінні середовища для викликів інструмента `exec`
після побудови базового середовища exec і перед виконанням
команди. Він отримує:

* `event.sessionKey`
* `event.toolName`, наразі завжди `"exec"`
* `event.host`, одне з `"gateway"`, `"sandbox"` або `"node"`
* поля контексту, як-от `ctx.agentId`, `ctx.sessionKey`,
  `ctx.messageProvider` і `ctx.channelId`

Поверніть `Record<string, string>`, щоб об’єднати його із середовищем exec. Обробники
виконуються в порядку пріоритету, і пізніші результати хуків перевизначають раніші результати хуків для
того самого ключа.

Вивід hook фільтрується через політику ключів середовища виконання хоста перед
об’єднанням. Недійсні ключі, `PATH` і небезпечні ключі перевизначення хоста,
як-от `LD_*`, `DYLD_*`, `NODE_OPTIONS`, змінні проксі та змінні перевизначення
TLS, відкидаються. Відфільтроване середовище Plugin включається до метаданих
схвалення/аудиту Gateway і пересилається до запитів виконання node-host.

### Збереження результатів інструментів

Результати інструментів можуть містити структуровані `details` для рендерингу UI, діагностики,
маршрутизації медіа або метаданих, що належать Plugin. Розглядайте `details` як метадані часу виконання,
а не як вміст промпта:

* OpenClaw вилучає `toolResult.details` перед повторним відтворенням провайдером і вхідними даними Compaction,
  щоб метадані не ставали контекстом моделі.
* Збережені записи сесій тримають лише обмежені `details`. Завеликі details
  замінюються компактним підсумком і `persistedDetailsTruncated: true`.
* `tool_result_persist` і `before_message_write` виконуються перед фінальним
  обмеженням збереження. Hooks все одно мають тримати повернені `details` малими й уникати
  розміщення тексту, релевантного для промпта, лише в `details`; видимий для моделі вивід інструмента
  розміщуйте в `content`.

## Hooks промптів і моделей

Використовуйте hooks, специфічні для фази, для нових plugins:

* `before_model_resolve`: отримує лише поточний промпт і метадані вкладень.
  Поверніть `providerOverride` або `modelOverride`.
* `agent_turn_prepare`: отримує поточний промпт, підготовлені повідомлення сесії
  та всі рівно-один-раз поставлені в чергу ін’єкції, вичерпані для цієї сесії. Поверніть
  `prependContext` або `appendContext`.
* `before_prompt_build`: отримує поточний промпт і повідомлення сесії.
  Поверніть `prependContext`, `appendContext`, `systemPrompt`,
  `prependSystemContext` або `appendSystemContext`.
* `heartbeat_prompt_contribution`: виконується лише для ходів Heartbeat і повертає
  `prependContext` або `appendContext`. Він призначений для фонових моніторів,
  яким потрібно підсумувати поточний стан без зміни ходів, ініційованих користувачем.

`before_agent_start` залишається для сумісності. Віддавайте перевагу явним hooks вище,
щоб ваш plugin не залежав від застарілої об’єднаної фази.

`before_agent_run` виконується після побудови промпта і до будь-яких вхідних даних моделі,
включно із завантаженням зображень, локальним для промпта, та спостереженням `llm_input`. Він отримує
поточний користувацький ввід як `prompt`, а також завантажену історію сесії в `messages`
і активний системний промпт. Поверніть `{ outcome: "block", reason, message? }`,
щоб зупинити запуск до того, як модель зможе прочитати промпт. `reason` є внутрішнім;
`message` є заміною, видимою користувачу. Єдині підтримувані результати:
`pass` і `block`; непідтримувані форми рішення закриваються з відмовою.

Коли запуск заблоковано, OpenClaw зберігає лише текст заміни в
`message.content` плюс нечутливі метадані блокування, як-от id plugin, що заблокував,
і мітку часу. Оригінальний користувацький текст не зберігається в транскрипті або майбутньому
контексті. Внутрішні причини блокування вважаються чутливими та виключаються з
транскрипта, історії, широкомовлення, журналів і діагностичних payload. Спостережуваність
має використовувати санітизовані поля, як-от id блокувальника, результат, мітку часу або безпечну
категорію.

`before_agent_start` і `agent_end` включають `event.runId`, коли OpenClaw може
ідентифікувати активний запуск. Те саме значення також доступне в `ctx.runId`.
Запуски, керовані Cron, також відкривають `ctx.jobId` (id вихідного cron-завдання), щоб
plugin hooks могли прив’язувати метрики, побічні ефекти або стан до конкретного запланованого
завдання.

Для запусків, що походять із каналу, `ctx.channel` і `ctx.messageProvider` ідентифікують
поверхню провайдера, як-от `discord` або `telegram`, тоді як `ctx.channelId` є
ідентифікатором цільової розмови, коли OpenClaw може вивести його з ключа сесії
або метаданих доставки.

Коли доступна ідентичність відправника, контексти agent hooks також містять:

* `ctx.senderId` — ID відправника в межах каналу (наприклад, Feishu `open_id`, ID користувача Discord).
  Заповнюється, коли запуск походить із користувацького повідомлення з відомими
  метаданими відправника.
* `ctx.chatId` — транспортно-нативний ідентифікатор розмови (наприклад, Feishu
  `chat_id`, Telegram `chat_id`). Заповнюється, коли вихідний канал
  надає нативний ID розмови.
* `ctx.channelContext.sender.id` — той самий ID відправника, що й `ctx.senderId`, під
  об’єктом, який належить каналу і який plugins можуть розширювати специфічними для каналу полями.
* `ctx.channelContext.chat.id` — той самий ID розмови, що й `ctx.chatId`, під
  об’єктом, який належить каналу і який plugins можуть розширювати специфічними для каналу полями.

Core визначає лише вкладені поля `id`. Channel plugins, які передають багатші
метадані відправника або чату через inbound helper, можуть розширювати
`PluginHookChannelSenderContext` або `PluginHookChannelChatContext` з
`openclaw/plugin-sdk/channel-inbound`:

```ts theme={"theme":{"light":"min-light","dark":"min-dark"}}
declare module "openclaw/plugin-sdk/channel-inbound" {
  interface PluginHookChannelSenderContext {
    unionId?: string;
    userId?: string;
  }
}
```

Channel plugins передають ці поля через inbound SDK helper:

```ts theme={"theme":{"light":"min-light","dark":"min-dark"}}
buildChannelInboundEventContext({
  // ...
  channelContext: {
    sender: { id: senderOpenId, unionId, userId },
    chat: { id: chatId },
  },
});
```

Ці поля є необов’язковими й відсутні для запусків, що походять із системи (heartbeat,
cron, exec-event).

`ctx.senderExternalId` залишається застарілим полем сумісності з вихідним кодом для
старіших plugins. Core не заповнює його; нові специфічні для каналу ідентичності відправника
мають жити під `ctx.channelContext.sender` через доповнення модуля.

`agent_end` є hook спостереження. Шляхи Gateway і persistent harness виконують його
за принципом fire-and-forget після ходу, тоді як короткоживучі одноразові CLI-шляхи очікують
promise hook перед очищенням процесу, щоб довірені plugins могли скинути термінальну
спостережуваність або захопити стан. Runner hook застосовує таймаут 30 секунд, щоб
завислий plugin або endpoint вбудовування не міг залишити promise hook у стані очікування
назавжди. Таймаут журналюється, і OpenClaw продовжує роботу; він не скасовує
мережеву роботу, що належить plugin, якщо plugin також не використовує власний сигнал переривання.

Використовуйте `model_call_started` і `model_call_ended` для телеметрії викликів провайдера,
яка не має отримувати сирі промпти, історію, відповіді, заголовки, тіла запитів
або ID запитів провайдера. Ці hooks включають стабільні метадані, як-от
`runId`, `callId`, `provider`, `model`, необов’язкові `api`/`transport`, термінальні
`durationMs`/`outcome` і `upstreamRequestIdHash`, коли OpenClaw може вивести
обмежений хеш request-id провайдера. Коли runtime визначив метадані context-window,
подія hook і контекст також містять `contextTokenBudget`,
ефективний бюджет токенів після обмежень моделі/конфігурації/agent, а також
`contextWindowSource` і `contextWindowReferenceTokens`, коли було застосовано нижчу межу.

`before_agent_finalize` виконується лише тоді, коли harness збирається прийняти природну
фінальну відповідь assistant. Це не шлях скасування `/stop`, і він не
виконується, коли користувач перериває хід. Поверніть `{ action: "revise", reason }`, щоб попросити
harness виконати ще один прохід моделі перед фіналізацією, `{ action:
"finalize", reason? }`, щоб примусити фіналізацію, або не повертайте результат, щоб продовжити.
Нативні hooks Codex `Stop` ретранслюються в цей hook як рішення OpenClaw
`before_agent_finalize`.

Повертаючи `action: "revise"`, plugins можуть включити метадані `retry`, щоб зробити
додатковий прохід моделі обмеженим і безпечним для повторного відтворення:

```typescript theme={"theme":{"light":"min-light","dark":"min-dark"}}
type BeforeAgentFinalizeRetry = {
  instruction: string;
  idempotencyKey?: string;
  maxAttempts?: number;
};
```

`instruction` додається до причини ревізії, надісланої до harness.
`idempotencyKey` дає хосту змогу рахувати повтори для того самого запиту plugin у межах
еквівалентних рішень finalize, а `maxAttempts` обмежує, скільки додаткових проходів
хост дозволить перед продовженням із природною фінальною відповіддю.

Non-bundled plugins, яким потрібні hooks сирої розмови (`before_model_resolve`,
`before_agent_reply`, `llm_input`, `llm_output`, `before_agent_finalize`,
`agent_end` або `before_agent_run`), повинні встановити:

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "plugins": {
    "entries": {
      "my-plugin": {
        "hooks": {
          "allowConversationAccess": true
        }
      }
    }
  }
}
```

Hooks, що змінюють промпт, і довговічні ін’єкції наступного ходу можна вимкнути для окремого plugin
за допомогою `plugins.entries.<id>.hooks.allowPromptInjection=false`.

### Розширення сесій та ін’єкції наступного ходу

Workflow plugins можуть зберігати малий JSON-сумісний стан сесії за допомогою
`api.registerSessionExtension(...)` і оновлювати його через метод Gateway
`sessions.pluginPatch`. Рядки сесій проєктують зареєстрований стан розширення
через `pluginExtensions`, даючи Control UI та іншим клієнтам змогу рендерити
статус, що належить plugin, без знання внутрішньої будови plugin.

Використовуйте `api.enqueueNextTurnInjection(...)`, коли plugin потребує довговічного контексту, щоб
досягти наступного модельного ходу рівно один раз. OpenClaw вичерпує ін’єкції з черги перед
prompt hooks, відкидає протерміновані ін’єкції та дедуплікує за `idempotencyKey`
для кожного plugin. Це правильний seam для відновлення після схвалення, підсумків політик,
дельт фонових моніторів і продовжень команд, які мають бути видимими для
моделі на наступному ході, але не мають ставати постійним текстом системного промпта.

Семантика очищення є частиною контракту. Очищення розширення сесії та
callback очищення життєвого циклу runtime отримують `reset`, `delete`, `disable` або
`restart`. Хост видаляє стійкий стан розширення сесії, що належить plugin,
і очікувані ін’єкції наступного ходу для reset/delete/disable; restart зберігає
довговічний стан сесії, тоді як callback очищення дають plugins змогу звільнити scheduler
jobs, контекст запуску та інші позасмугові ресурси для старого покоління runtime.

## Hooks повідомлень

Використовуйте message hooks для маршрутизації на рівні каналу та політики доставки:

* `message_received`: спостерігає inbound-вміст, відправника, `threadId`, `messageId`,
  `senderId`, необов’язкову кореляцію запуску/сесії та метадані.
* `message_sending`: переписує `content` або повертає `{ cancel: true }`.
* `reply_payload_sending`: переписує нормалізовані об’єкти `ReplyPayload` (включно з
  `presentation`, `delivery`, media refs і текстом) або повертає `{ cancel: true }`.
* `message_sent`: спостерігає фінальний успіх або помилку.

Для audio-only TTS replies `content` може містити прихований усний транскрипт
навіть тоді, коли payload каналу не має видимого тексту/підпису. Переписування цього
`content` оновлює лише транскрипт, видимий hook; він не рендериться як
медіапідпис.

Події `reply_payload_sending` можуть містити `usageState`, best-effort live
знімок моделі/використання/контексту для кожного ходу. Довговічна доставка, відновлене повторне відтворення та
відповіді без точної кореляції запуску пропускають його.

Контексти message hook відкривають стабільні поля кореляції, коли вони доступні:
`ctx.sessionKey`, `ctx.runId`, `ctx.messageId`, `ctx.senderId`, `ctx.trace`,
`ctx.traceId`, `ctx.spanId`, `ctx.parentSpanId` і `ctx.callDepth`. Inbound
і контексти `before_dispatch` також відкривають метадані відповіді, коли канал має
відфільтровані за видимістю дані цитованого повідомлення: `replyToId`, `replyToIdFull`,
`replyToBody`, `replyToSender` і `replyToIsQuote`. Віддавайте перевагу цим first-class
полям перед читанням застарілих метаданих.

Віддавайте перевагу типізованим полям `threadId` і `replyToId` перед використанням специфічних для каналу
метаданих.

Правила ухвалення рішень:

* `message_sending` з `cancel: true` є термінальним.
* `message_sending` з `cancel: false` вважається відсутністю рішення.
* Переписаний `content` продовжує переходити до хуків нижчого пріоритету, якщо пізніший хук
  не скасує доставку.
* `reply_payload_sending` виконується після нормалізації payload і перед доставкою каналу,
  включно з відповідями, скерованими назад до початкового каналу. Обробники
  виконуються послідовно, і кожен обробник бачить найновіший payload, створений
  обробниками вищого пріоритету.
* Payload-и `reply_payload_sending` не відкривають маркери довіри runtime, такі як
  `trustedLocalMedia`; plugins можуть змінювати форму payload, але не можуть надавати довіру
  до локальних медіа.
* `message_sending` може повертати `cancelReason` і обмежені `metadata` разом зі
  скасуванням. Нові API життєвого циклу повідомлень відкривають це як результат пригніченої доставки
  з причиною `cancelled_by_message_sending_hook`; застаріла пряма
  доставка й надалі повертає порожній масив результатів для сумісності.
* `message_sent` призначений лише для спостереження. Збої обробників записуються в журнал і не
  змінюють результат доставки.

## Хуки встановлення

Використовуйте `security.installPolicy` для рішень дозволу/блокування, якими керує оператор. Ця
політика виконується з конфігурації OpenClaw, охоплює шляхи встановлення та оновлення CLI і завершується
закритою відмовою, коли її ввімкнено, але вона недоступна.

`before_install` — це хук життєвого циклу runtime Plugin. Він виконується після
`security.installPolicy` лише в процесі OpenClaw, де хуки Plugin уже
завантажено, наприклад у потоках встановлення, підтриманих Gateway. Він корисний для
спостережень, попереджень і перевірок сумісності, якими керує Plugin, але не є
основною корпоративною або хостовою межею безпеки для встановлень. Поле `builtinScan`
залишається в payload події для сумісності, але OpenClaw більше не
виконує вбудоване блокування небезпечного коду під час встановлення, тому це порожній результат `ok`.
Поверніть додаткові findings або `{ block: true, blockReason }`, щоб зупинити
встановлення в цьому процесі.

`block: true` є термінальним. `block: false` вважається відсутністю рішення.
Збої обробників блокують встановлення за принципом fail-closed.

## Життєвий цикл Gateway

Використовуйте `gateway_start` для сервісів Plugin, яким потрібен стан, керований Gateway. Контекст
відкриває `ctx.config`, `ctx.workspaceDir` і `ctx.getCron?.()` для
перевірки та оновлень cron. Використовуйте `gateway_stop`, щоб очистити довготривалі
ресурси.

Не покладайтеся на внутрішній хук `gateway:startup` для runtime-сервісів,
якими керує Plugin.

`cron_changed` спрацьовує для подій життєвого циклу cron, якими керує gateway, з типізованим
payload події, що охоплює причини `added`, `updated`, `removed`, `started`, `finished`
і `scheduled`. Подія містить snapshot `PluginHookGatewayCronJob`
(включно з `state.nextRunAtMs`, `state.lastRunStatus` і
`state.lastError`, коли вони наявні), а також `PluginHookGatewayCronDeliveryStatus`
зі значеннями `not-requested` | `delivered` | `not-delivered` | `unknown`. Події видалення
все одно містять snapshot видаленого завдання, щоб зовнішні планувальники могли
узгодити стан. Використовуйте `ctx.getCron?.()` і `ctx.config` з runtime-контексту
під час синхронізації зовнішніх планувальників пробудження та залишайте OpenClaw
джерелом істини для перевірок строку виконання й виконання.

## Майбутні припинення підтримки

Кілька поверхонь, суміжних із хуками, застаріли, але все ще підтримуються. Перейдіть
до нових API до наступного major-релізу:

* **Текстові конверти каналів** в обробниках `inbound_claim` і `message_received`.
  Читайте `BodyForAgent` і структуровані блоки контексту користувача
  замість парсингу плоского тексту конверта. Див.
  [Текстові конверти каналів → BodyForAgent](/uk/plugins/sdk-migration#active-deprecations).
* **`before_agent_start`** залишається для сумісності. Нові plugins мають використовувати
  `before_model_resolve` і `before_prompt_build` замість об’єднаної
  фази.
* **`subagent_spawning`** залишається для сумісності зі старішими plugins, але
  нові plugins не мають повертати з нього маршрутизацію thread. Core готує
  прив’язки subagent `thread: true` через адаптери прив’язки сесій каналу
  до спрацювання `subagent_spawned`.
* **`deactivate`** залишається застарілим псевдонімом сумісності для очищення до
  після 2026-08-16. Нові plugins мають використовувати `gateway_stop`.
* **`onResolution` у `before_tool_call`** тепер використовує типізований
  union `PluginApprovalResolution` (`allow-once` / `allow-always` / `deny` /
  `timeout` / `cancelled`) замість довільного `string`.

Повний список — реєстрацію capability пам’яті, профіль thinking провайдера,
зовнішніх провайдерів auth, типи discovery провайдера, accessor-и runtime завдань
і перейменування `command-auth` → `command-status` — див. у
[міграції Plugin SDK → Активні припинення підтримки](/uk/plugins/sdk-migration#active-deprecations).

## Пов’язане

* [Міграція Plugin SDK](/uk/plugins/sdk-migration) - активні припинення підтримки та графік видалення
* [Створення plugins](/uk/plugins/building-plugins)
* [Огляд Plugin SDK](/uk/plugins/sdk-overview)
* [Точки входу Plugin](/uk/plugins/sdk-entrypoints)
* [Внутрішні хуки](/uk/automation/hooks)
* [Внутрішня архітектура Plugin](/uk/plugins/architecture-internals)
