# Хуки

Источник: https://svedum.ru/docs/customize/hooks

> Команда или проверка моделью на вашем сообщении, перед шагом агента и после его хода — например, не давать агенту закончить, пока тесты не проходят.

Хук — команда или проверка, которую «Сведум» запускает в определённый момент работы агента:
когда вы отправили сообщение, перед шагом, после шага или когда агент закончил ход. Хук может
не передать сообщение агенту, запретить шаг, спросить вас или вернуть агента к работе с
причиной: «тесты падают», «не обновлён README». Формат тот же,
что у хуков Claude Code, — файл `.svedum/hooks.json` в проекте.

```json title=".svedum/hooks.json"
{
  "hooks": {
    "Stop": [
      {
        "hooks": [{ "type": "command", "command": "sh scripts/check-before-stop.sh" }]
      }
    ]
  }
}
```

```sh title="scripts/check-before-stop.sh"
#!/bin/sh
if ! bun test > /tmp/tests.log 2>&1; then
  echo "Тесты падают — исправь и проверь снова:" >&2
  tail -20 /tmp/tests.log >&2
  exit 2
fi
```

Агент дописал ответ, хук запустил тесты, они упали — агент получает причину из скрипта и
продолжает работу в том же ходе. Пока хук работает, в чате видно «Хук проверяет ход»: ход
можно остановить, и хук остановится вместе с ним, а сообщение, которое вы напишете в это
время, агент прочитает после хука.

## События

| Событие            | Когда срабатывает                                                                   |
| ------------------ | ----------------------------------------------------------------------------------- |
| `SessionStart`     | Первый ход нового чата и первый запрос после сжатия контекста                       |
| `UserPromptSubmit` | Вы отправили сообщение, агент его ещё не прочитал                                   |
| `PreToolUse`       | Агент собирается сделать шаг: запустить команду, записать файл, вызвать подключение |
| `PostToolUse`      | Шаг сделан                                                                          |
| `Stop`             | Агент закончил ход, и новых сообщений в очереди нет                                 |
| `StopFailure`      | Ход закончился ошибкой                                                              |

Остальные события Claude Code, например `Notification` и `PreCompact`, «Сведум» не вызывает.

## Виды хуков

* **`command`** — команда в папке проекта. На вход, в stdin, она получает JSON о событии:
  чат, путь к журналу хода, последний ответ агента, а у хуков шага — сам шаг. Код выхода
  `2` у `Stop` возвращает агента к работе, а текст из stderr становится причиной; код `0` —
  агент заканчивает. Другой код — ошибка хука: всё идёт так, как если бы хука не было.
* **`prompt`** — проверка моделью: в поле `prompt` — условие, а `$ARGUMENTS` подставит в
  него данные события. Условие не выполнено — у `Stop` агент продолжает с причиной, которую
  назвала модель, у `PreToolUse` шаг не выполняется, у `UserPromptSubmit` сообщение не
  передаётся агенту. Проверяет недорогая модель; свою задаёт поле `model`.

`timeout` задаётся в секундах, как в Claude Code: по умолчанию 600 для `command`, 30 для
`command` у `UserPromptSubmit` и 30 для `prompt`. Значение от 1000 читается как миллисекунды:
`"timeout": 30000` — это 30 секунд. Подряд хук возвращает агента к работе не больше восьми раз, потом агент
заканчивает ход.

## Хуки сообщения и начала чата

`UserPromptSubmit` получает в поле `prompt` текст, который вы отправили, — и первое сообщение
хода, и те, что вы дописали, пока агент работал. Хук может не передать сообщение агенту: код
выхода `2`, `"decision": "block"` или `"continue": false`. Тогда сообщение остаётся в чате с
отметкой «Не передано агенту» и причиной из stderr или `reason`; причину видите только вы,
агент не видит ни её, ни само сообщение. Если в ходе больше ничего нет, агент не отвечает.

`SessionStart` срабатывает на первом ходе нового чата (`"source": "startup"`) и после каждого
сжатия контекста (`"source": "compact"`); `matcher` сравнивается с `source`. Остановить
агента он не может.

У обоих событий текст, который команда печатает в stdout при коде `0`, и
`additionalContext` из JSON агент читает сразу после вашего сообщения или после сводки
сжатого контекста — например, текущую ветку или правила на сегодня. В чатах агентов, которых
запустил другой агент, эти события не срабатывают.

Если ход пришлось повторить, например после перезапуска «Сведума», хук может сработать на
том же сообщении ещё раз: пишите его так, чтобы повтор ничего не ломал.

## Хуки шагов

`PreToolUse` и `PostToolUse` видят шаг так же, как в Claude Code: команда — это `Bash`, правка
файла — `Edit`, вызов подключения — `mcp__<сервер>__<инструмент>`, запуск агента — `Agent`.
В `tool_input` те же поля, что у Claude Code, например `command` или `file_path` с полным
путём. Поэтому `"matcher": "Edit|Write"` из Claude Code работает и здесь; в `matcher` можно
написать и имя инструмента «Сведума», например `Shell`.

Хук `PreToolUse` отвечает в `hookSpecificOutput.permissionDecision`:

* **`deny`** или код выхода `2` — шаг не выполняется, агент получает причину из
  `permissionDecisionReason` или stderr.
* **`ask`** — в чате появляется карточка разрешения с причиной хука. Решаете вы, в любом
  режиме разрешений, даже в «Разрешать всё»; кнопки «Всегда» на такой карточке нет. После
  «Разрешить» агент повторяет шаг, и он выполняется. Если отвечать некому — например, шаг
  делает агент, которого запустил другой агент, — шаг не выполняется.
* **`allow`** — шаг идёт как обычно: режим разрешений и «Проверять» решают так же, как без
  хука. Хук может только запретить или спросить, но не разрешить сверх режима.
  → [Проверка разрешений](https://svedum.ru/docs/agents/permission-review)

`updatedInput` хук вернуть может, но «Сведум» его не применяет: шаг выполняется таким, каким
его задумал агент.

Хук `PostToolUse` срабатывает, когда шаг уже сделан. Его `additionalContext`, `reason` при
`"decision": "block"` или stderr при коде `2` агент прочитает сразу после результата шага —
например, «запусти линтер».

## Ответ хука в JSON

Вместо кода выхода команда может напечатать в stdout JSON — те же поля, что у Claude Code:

| Поле                                       | Что делает                                                         |
| ------------------------------------------ | ------------------------------------------------------------------ |
| `"decision": "block"` и `"reason"`         | У `Stop`: агент продолжает работу, `reason` — его следующая задача |
| `"decision": "block"` у `UserPromptSubmit` | Сообщение не передаётся агенту, `reason` видите только вы          |
| `hookSpecificOutput.additionalContext`     | Подсказка агенту; у `Stop` агент с ней продолжает работу           |
| `"continue": false`                        | Агент заканчивает ход, даже если другой хук просит продолжить      |
| `stopReason`                               | Сообщение вам в чате, когда хук остановил агента                   |
| `systemMessage`                            | Сообщение вам в чате; агент его не видит                           |

Если сработало несколько хуков, причины и подсказки всех складываются в одну, а из ответов
`PreToolUse` побеждает самый строгий: `deny`, затем `ask`.

Подсказку, которую хук передал агенту, видите и вы: раскройте шаг хода — в нём строка «Хук
добавил контекст», а её текст открывается по клику.

## Перенос из Claude Code

Импорт из Claude переносит хуки проекта из `.claude/settings.json` и
`.claude/settings.local.json` в `.svedum/hooks.json`. Хуки, которые уже есть в
`.svedum/hooks.json`, остаются, импорт только добавляет недостающие. `$CLAUDE_PROJECT_DIR` в
команде становится `.`: хук и так запускается в папке проекта. Если скрипт хука сам читает
эту переменную, поправьте его. Ваши хуки из `~/.claude/settings.json` не переносятся: в
«Сведуме» хуки живут в проекте и в плагинах. → [Переход с Cursor и Claude Code](https://svedum.ru/docs/customize/import)

## Что из файла не работает

Файл можно взять из Claude Code целиком. То, чего в «Сведуме» нет, — другие события, хуки
типа `http` и `mcp_tool`, хуки с `async`, незнакомые поля — пропускается, а остальное
работает. Что пропущено, видно там же, где вы доверяете файлу: в «Персонализации» на
вкладке «Подключения».

## Доверие

Хуки запускают программы на вашем компьютере, поэтому `.svedum/hooks.json` работает только
после того, как вы ему доверились: в «Персонализации» на вкладке «Подключения» появится
карточка «Папка хочет запускать команды» — проверьте файл и нажмите «Доверять». После любого
изменения файла «Сведум» спросит снова — и после импорта тоже. Запись в этот файл агент
делает только с вашего разрешения: проверка разрешений такой шаг за вас не решает.

У облачного агента, который работает с подключённым репозиторием, хуки из
`.svedum/hooks.json` этого репозитория работают без «Доверять»: репозиторий вы выбрали сами,
когда его подключали. Сети у таких хуков нет — как и у команд самого агента на облачном
компьютере.

## Хуки в плагине

Плагин приносит хуки в файле `hooks/hooks.json` или в поле `hooks` своего `plugin.json`.
Они работают, пока плагин включён. В каталог плагины с хуками не принимают — такой плагин
ставят из папки. → [Формат плагина](https://svedum.ru/docs/customize/plugin-format#что-можно-опубликовать)
