Хуки Claude Code блокируют только на коде выхода 2

Допустим, ваш защитный хук в Claude Code завершается с кодом 1, как принято в Unix. Claude Code отметит ошибку и всё равно выполнит команду. Блокирует только код 2, и автор разбора в блоге Blakecrosley называет эту ловушку самой крупной во всей системе хуков.
Коротко
- Хуками в Claude Code называют shell-команды, HTTP-эндпоинты, инструменты MCP и промпты для модели. Они запускаются в фиксированных точках: перед вызовом инструмента, после правки, на старте сессии и когда Claude заканчивает ответ.
- Справочник Anthropic описывает 33 события. Хук получает JSON на stdin и отвечает кодом выхода или JSON в stdout, а почти любой рабочей настройке хватает пяти событий.
- Хук не откатит уже выполненную команду и не увидит файлы, подключённые через @. Его снимают по тайм-ауту, а работает он с полными правами вашей учётной записи, так что скрипты стоит проверять заранее.
Если вы не следили: большинство разработчиков управляют Claude Code двумя слоями. Разрешения определяют, что агенту можно делать, а CLAUDE.md описывает, что ему следует делать. Хуки добавляют третий слой, и автор подчёркивает, что гарантии даёт только он. Инструкцию из CLAUDE.md модель, скорее всего, выполнит: попросите запускать Prettier после каждой правки, и агент будет это делать, но иногда пропустит шаг. Хук сработает всегда.
Из 33 событий почти любой настройке хватает пяти
По состоянию на 6 сентября 2026 года справочник описывает 33 события хуков. Они различаются по ритму. SessionStart и SessionEnd срабатывают раз за сессию, UserPromptSubmit, Stop и StopFailure раз за ход, а PreToolUse и PostToolUse на каждом вызове инструмента внутри агентного цикла. Остальные события привязаны к особым условиям: смене конфигурации, сжатию контекста, работе субагентов и запросам от MCP-серверов.
В рабочих настройках почти всегда обходятся пятью: PreToolUse, PostToolUse, UserPromptSubmit, SessionStart и Stop. Среди редких событий есть любопытные. PreModelSwitch может запретить переход на модель, которую вы не одобряли. MessageDisplay правит текст только на экране и не трогает транскрипт, а в PermissionDenied единственный рычаг: ответ retry: true, с которым модель может повторить попытку.
В Claude Agent SDK система хуков та же. Хуки регистрируются как функции обратного вызова в поле hooks, с тем же синтаксисом матчеров, и возвращают такой же JSON. Правда, SessionStart, SessionEnd, Setup, PostToolBatch и ряд других событий пока доступны только в TypeScript. Хуки из settings.json продолжают работать внутри SDK-приложения, если включён нужный пункт settingSources.
Код 2 блокирует вызов, код 1 только оставляет пометку об ошибке
Хук получает на stdin JSON с общими полями session_id, transcript_path, cwd и hook_event_name, к которым добавляются поля конкретного события. Для PreToolUse это имя инструмента и его аргументы, например команда npm test. Отвечает хук кодом выхода, stdout и stderr.
Код 0 означает успех, и Claude Code ищет в stdout JSON. Код 2 означает блокировку: stdout игнорируется, а stderr уходит Claude как сообщение об ошибке. Любой другой код, включая 1, считается неблокирующей ошибкой: в транскрипте появляется пометка, и работа идёт дальше. Документация прямо предупреждает, что хуки-запреты должны завершаться с кодом 2.
Что именно блокирует код 2, зависит от события. В PreToolUse он отменяет вызов инструмента, в UserPromptSubmit стирает промпт, в Stop не даёт агенту закончить, а PostToolUse заблокировать нельзя совсем, потому что инструмент уже отработал. И ещё одно правило: JSON читается только при коде 0, при коде 2 его выбрасывают.
Запрет из PreToolUse действует даже в режиме bypassPermissions
Хуки PreToolUse срабатывают раньше проверки режима разрешений. Поэтому ответ permissionDecision со значением deny блокирует инструмент даже в bypassPermissions и при запуске с --dangerously-skip-permissions. В обратную сторону так не работает: allow из хука не отменяет запрещающие правила из настроек. Хук может только ужесточить политику.
Если несколько хуков PreToolUse ответили по-разному, побеждает самый строгий ответ в порядке deny, defer, ask, allow. Настройки лежат в трёх местах: ~/.claude/settings.json для всех проектов, .claude/settings.json для проекта с коммитом в репозиторий и .claude/settings.local.json, который попадает в gitignore. Администраторы могут навязать управляемые хуки, которые пользователь не переопределит.
С матчерами легко ошибиться. Строка из букв, цифр и вертикальной черты вроде Edit|Write сравнивается точно, всё остальное становится незаякоренным регулярным выражением JavaScript, так что Edit.* поймает и NotebookEdit. Регистр важен: bash никогда не совпадёт с Bash.
Хук на Stop держит агента до зелёных тестов, но не дольше восьми блокировок
Самый наглядный из пяти шаблонов в разборе построен на событии Stop, которое срабатывает, когда Claude заканчивает ответ. Скрипт запускает npm test и при падении тестов печатает JSON с decision: block и причиной. Claude получает причину и продолжает работу.
Представьте контролёра на выезде со склада: пока накладная не сходится, машину не выпускают. Но контролёру нужна память. Поле stop_hook_active сообщает, что агент уже продолжает работу из-за этого хука, и без такой проверки гейт быстро исчерпает лимит. По умолчанию Claude Code разрешает хуку Stop не больше 8 блокировок подряд, а поднять лимит можно переменной CLAUDE_CODE_STOP_HOOK_BLOCK_CAP.
Мягкий вариант возвращает additionalContext вместо блокировки: продолжение то же, но без пометки об ошибке хука. Для разовых условий есть встроенная команда /goal, по сути хук Stop на промпте, который не требует настройки. Учтите, что Stop срабатывает на каждом завершении ответа, а не только когда задача готова.
Ограничения в документации перечислены честно. Тайм-аут командных хуков по умолчанию 600 секунд, и гейт, снятый по тайм-ауту, просто не сработал. Поле if в матчере пропускает вызов, если не может разобрать команду, поэтому для жёстких гарантий нужны правила разрешений. На наш взгляд, самое неудобное решение здесь в кодах выхода: привычный в Unix код сбоя 1 ничего не блокирует, и хук-запрет, написанный по привычке, тихо превращается в журнал.
Что сверять после релизов v2.1.x
Автор сверял детали с официальной документацией 8 августа 2026 года и предупреждает, что API хуков заметно менялся от релиза к релизу, а при расхождении прав справочник. Пример уже есть: с v2.1.214 SessionStart получил пятое значение source, fork, и хуки со старым списком из четырёх значений форки пропускают. Когда Python SDK получит события, которые сейчас есть только в TypeScript, не сообщается.
Читайте также
- Function Hooks стали Claude Mods, релиз обещают за недели
- Function Hooks для Claude Code показали до релиза
- Claude Code 2.1.283 научился держать новые модели за дверью
- Claude Code игнорирует AGENTS.md, если рядом лежит CLAUDE.md
- В проекте без CLAUDE.md Claude Code 2.1.277 читает AGENTS.md
- 57% субагентов Claude Code наследуют Bash вызвавшего
Комментарии
Пока никто не написал. Будьте первым.
Присоединяйтесь к разговору
Войдите через Google, чтобы оставить комментарий. Имя и аватар подставятся из вашего профиля Google, а комментарий появится после модерации.
