Перейти к содержанию

claude-code

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

Claude News

Допустим, ваш защитный хук в 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, не сообщается.

Читайте также

  1. Function Hooks стали Claude Mods, релиз обещают за недели
  2. Function Hooks для Claude Code показали до релиза
  3. Claude Code 2.1.283 научился держать новые модели за дверью
  4. Claude Code игнорирует AGENTS.md, если рядом лежит CLAUDE.md
  5. В проекте без CLAUDE.md Claude Code 2.1.277 читает AGENTS.md
  6. 57% субагентов Claude Code наследуют Bash вызвавшего

Комментарии

Пока никто не написал. Будьте первым.

Присоединяйтесь к разговору

Войдите через Google, чтобы оставить комментарий. Имя и аватар подставятся из вашего профиля Google, а комментарий появится после модерации.

Из Google мы используем только имя и аватар. Почту не сохраняем.