Хуки
Команда или проверка моделью на вашем сообщении, перед шагом агента и после его хода — например, не давать агенту закончить, пока тесты не проходят.
Хук — команда или проверка, которую «Сведум» запускает в определённый момент работы агента:
когда вы отправили сообщение, перед шагом, после шага или когда агент закончил ход. Хук может
не передать сообщение агенту, запретить шаг, спросить вас или вернуть агента к работе с
причиной: «тесты падают», «не обновлён README». Формат тот же,
что у хуков Claude Code, — файл .svedum/hooks.json в проекте.
{
"hooks": {
"Stop": [
{
"hooks": [{ "type": "command", "command": "sh 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— шаг идёт как обычно: режим разрешений и «Проверять» решают так же, как без хука. Хук может только запретить или спросить, но не разрешить сверх режима. → Проверка разрешений
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
Что из файла не работает
Файл можно взять из Claude Code целиком. То, чего в «Сведуме» нет, — другие события, хуки
типа http и mcp_tool, хуки с async, незнакомые поля — пропускается, а остальное
работает. Что пропущено, видно там же, где вы доверяете файлу: в «Персонализации» на
вкладке «Подключения».
Доверие
Хуки запускают программы на вашем компьютере, поэтому .svedum/hooks.json работает только
после того, как вы ему доверились: в «Персонализации» на вкладке «Подключения» появится
карточка «Папка хочет запускать команды» — проверьте файл и нажмите «Доверять». После любого
изменения файла «Сведум» спросит снова — и после импорта тоже. Запись в этот файл агент
делает только с вашего разрешения: проверка разрешений такой шаг за вас не решает.
У облачного агента, который работает с подключённым репозиторием, хуки из
.svedum/hooks.json этого репозитория работают без «Доверять»: репозиторий вы выбрали сами,
когда его подключали. Сети у таких хуков нет — как и у команд самого агента на облачном
компьютере.
Хуки в плагине
Плагин приносит хуки в файле hooks/hooks.json или в поле hooks своего plugin.json.
Они работают, пока плагин включён. В каталог плагины с хуками не принимают — такой плагин
ставят из папки. → Формат плагина
