Хуки Claude Code выдали ошибку, а агент всё равно выполнил команду? Для command и http hooks это стандартная реакция на сбой: действие идёт дальше к обычной проверке разрешений. Начиная с Claude Code 2.1.295 можно поставить "onFailure": "block", чтобы неисправная проверка остановила действие. Но сначала отдели сбой скрипта от запрета, который исправный скрипт выдал намеренно.
Хуки Claude Code: где ты сейчас
Коротко: этот разбор нужен, когда у тебя уже есть хук перед действием агента. Проверь тип обработчика, событие и версию клиента. Для первого опыта возьми отдельную учебную папку: мы будем останавливать только команду, которая показывает текущий каталог.
Хук - обработчик, который Claude Code запускает на определённом событии. Например, перед командой терминала. По-английски в настройках написано hooks; здесь речь о расширении агента, не о вебхуках платёжного сервиса.
- Ещё не настроил агента. Начни с настройки Claude Code. Для этого опыта уже нужны установленный клиент и понятные тебе разрешения.
- Видишь
PreToolUse hook error, но команда выполняется. Проверь код выхода и полеonFailure. Ошибка обработчика сама по себе не доказывает блокировку. - Проверка идёт через HTTP. У неё другой способ ответа. Код HTTP 500 по умолчанию не становится запретом - отдельная развилка есть ниже.
- У тебя мод с обработчиком JavaScript. Не переноси на него поле из примера. В разборе модов объяснено, чем их обработчики отличаются от обычных хуков настроек.
Почему ошибка хука не остановила действие?
Коротко: исправный хук может запретить действие своим ответом. Сломанный хук мог вообще не проверить условие. Для второго случая Claude Code по умолчанию использует continue. Значение block меняет эту реакцию у command и HTTP hooks, начиная с версии 2.1.295.
Хуки Claude Code получают данные о событии и возвращают результат проверки. PreToolUse означает «перед вызовом инструмента»; здесь ещё можно остановить вызов. PostToolUse происходит после него, когда отменять выполненное поздно.
Для command hook на PreToolUse с пустым выводом stdout различие такое:
| Результат обработчика | Без onFailure block | С onFailure block |
|---|---|---|
| Код 0 | Переход к обычной проверке разрешений | То же самое |
| Код 2 | Вызов инструмента блокируется | Вызов инструмента блокируется |
| Код 1 или другой код, кроме 0 и 2 | Неблокирующая ошибка, вызов идёт дальше | Вызов блокируется |
| Программа не найдена или достигнут тайм-аут | Вызов обычно идёт дальше | Вызов блокируется |
Код выхода - число, которым завершилась программа. Для защитного скрипта код 2 - намеренный отказ, например «эта команда запрещена правилом». Код 1 обычно означает неисправность проверки. Эту разницу описывает официальный справочник.
Если обработчик печатает JSON, результат зависит ещё и от его полей. Без onFailure: block допустимый JSON может определять решение даже при коде 1. С block такой неожиданный код считается сбоем. Для штатного JSON-ответа используй код 0; сообщение об ошибке и решение проверь по схеме своего события.
Поле появилось в релизе 2.1.295 от 8 октября 2026 года. Одно обновление клиента не меняет старые хуки Claude Code: стандартным значением остаётся continue.
Как проверить блокировку без опасной команды
Коротко: учебный обработчик будет возвращать код 1 перед Bash, а агенту поручим только pwd - показ текущей папки. Так проверяется реакция на сбой без удаления файлов. После этого проверим успешный обработчик и вернём настройки учебного проекта.
Пример рассчитан на терминал с установленным Bash: macOS, Linux или Windows с Git Bash. Наличие Bash проверь командой bash --version в обычном терминале. На Windows без Bash этот пример не повторяй и не меняй систему ради него. Если агент ещё не запускается, сначала реши эту проблему.
1. Отдели опыт от рабочей папки
Создай пустую учебную папку без рабочих документов и секретов, открой её в редакторе. В VS Code можно выбрать «Терминал -> Новый терминал». Такая папка отделяет настройки опыта от проекта, но не ограничивает права программ на компьютере.
В обычном терминале проверь:
claude --version
Нужна 2.1.295 или новее. Затем запусти claude именно в учебной папке. Внутри сессии введи /hooks: меню показывает обработчики и источник каждого - личные настройки, проект, плагин. Где вводить команды терминала и команды с /, разобрано в шпаргалке Claude Code.
Учти существующие хуки: настройки из разных файлов добавляются друг к другу. Не отключай чужую защиту ради чистого опыта. Если действует политика организации или ты не понимаешь текущие обработчики, отложи тест и уточни у администратора.
2. Подключи только учебный обработчик
В учебной папке создай каталог .claude, а внутри файл settings.local.json. Если такой файл уже есть, сначала сохрани его отдельную копию вне .claude и изучи содержимое. Не заменяй существующий файл целиком этим примером. В пустой новой папке файл может содержать:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash",
"args": ["-c", "exit 1"],
"onFailure": "block",
"timeout": 5
}
]
}
]
}
}
Это учебная имитация сбоя: bash запускает короткую команду exit 1. Она ничего не читает, не пишет и не отправляет. matcher: Bash ограничивает событие инструментом терминала; onFailure находится внутри описания обработчика, рядом с command и args. Значение timeout: 5 задаёт предел в секундах, не проверку скорости твоего проекта.
Обработчик намеренно отказывает перед каждым вызовом Bash. Он нужен для проверки механизма, не для постоянной работы и не для выявления опасных команд. Правила работы со своими и чужими обработчиками в составе расширений есть в статье про плагины.
Закрой сессию и открой claude снова в той же учебной папке. Через /hooks убедись, что появился именно этот локальный обработчик на PreToolUse для Bash.
Чтобы понимать, где нужен хук, а где разрешение, открой программу ClaudeBase. В модуле 2 есть правила проекта и разрешения, а затем хуки, скиллы и сценарии. Выбери тему под свою настройку и посмотри программу без оплаты. Уроки и материалы базы доступны после оплаты подписки; подписки Anthropic и OpenAI оплачиваются отдельно.
3. Проверь факт остановки
Отправь в сессии такой запрос:
Вызови инструмент Bash ровно один раз с командой pwd.
Не меняй настройки и не используй другие инструменты для обхода отказа.
Если хук остановит вызов, сообщи об этом и закончи.
pwd показывает текущий каталог. Она не удаляет и не изменяет файлы. Если обычная проверка разрешений попросит согласие, прочитай команду: разрешать здесь можно только pwd.
По документации onFailure при сбое сообщение содержит фрагмент:
blocking because onFailure is "block"
Проверь запись самого вызова Bash, а не только объяснение агента. Там должна быть блокировка; успешного результата pwd с путём папки быть не должно. Если агент просто отказался без вызова инструмента, механизм ещё не проверен. Если вместо этого напечатан путь, останови опыт и разбери причину по следующему разделу.
4. Проверь исправный обработчик и верни настройки
В учебном settings.local.json поменяй только строку аргументов:
"args": ["-c", "exit 0"]
Поле onFailure: block оставь. Перезапусти сессию в учебной папке, снова проверь /hooks и повтори тот же запрос с pwd. Теперь успешный обработчик пропускает вызов к обычным разрешениям. Если они и остальные хуки позволяют действие, запись Bash покажет путь учебной папки.
Это две разные проверки: при сбое вызова нет, при успехе он возможен. Наличие обработчика в /hooks доказывает лишь загрузку настройки.
После опыта верни сохранённую копию локальных настроек. Если файл создавался только для теста, через редактор убери из него только добавленную учебную запись и сохрани валидный JSON. Не выключай все хуки. Запусти новую сессию и проверь, что учебной записи в /hooks больше нет, а прежние настройки сохранены.
Для материала отдельно проверены JSON примера и коды завершения Bash на Linux. Реальное срабатывание внутри сессии Claude Code не измерено; наблюдаемый результат выше описан по официальной документации. Поэтому повтори оба контроля у себя до изменения рабочих хуков.
Если команда всё-таки выполнилась
Коротко: проверь версию, место поля, тип обработчика и факт его загрузки. Потом проверь, совпало ли событие с инструментом. Не возвращайся к рабочим задачам, пока не понял, почему учебная проверка пропустила pwd.
| Что наблюдаешь | Что проверить |
|---|---|
В /hooks нет учебного обработчика |
Открыта ли нужная папка; имя и JSON файла; источник настройки и ограничения организации |
| Обработчик есть, но нет вызова Bash | Агент ответил без инструмента; повтори точную задачу на один вызов |
| Bash выполнился после кода 1 | Версию клиента, вложенность onFailure, точное значение block, отсутствие async/asyncRewake |
| У рабочего хука ошибка «программа не найдена» | Реальный путь скрипта, наличие программы и права запуска; не добавляй автоматическое разрешение команды |
С block срабатывает тайм-аут |
Исправность и длительность самой проверки; не отключай блокировку ради продолжения |
| После exit 0 вызов всё равно запрещён | Другие хуки или обычные разрешения; успех одного обработчика не отменяет их решения |
Хуки Claude Code могут использовать command или http, а ещё другие типы обработчиков. Для HTTP отдельно проверь ответ: 500, ошибка соединения и тайм-аут по умолчанию не блокируют вызов. onFailure: block меняет реакцию на эти сбои. Для намеренного отказа исправного HTTP-обработчика нужен ответ 2xx с допустимым JSON-решением для события. Эти условия приведены в справочнике HTTP hooks.
Если причина неясна, останови работу, сохрани текст ошибки без ключей и личных данных и разберись с автором скрипта. Запуск без защитных хуков не подтверждает, что защита исправлена.
Где onFailure не поможет
Коротко: поле меняет реакцию на неисправность конкретной проверки. Оно не отменяет сделанное и не доказывает, что сам скрипт запрещает всё необходимое. Разрешения агента и ограничение доступа программ нужны отдельно.
В справочнике перечислены границы:
- Поле предусмотрено для
commandиhttp. Не рассчитывай на него уprompt,agent,mcp_toolили обработчика мода. - У фоновых command hooks с
asyncилиasyncRewakeоно не действует: они не удерживают выполнение таким способом. - Для
Stop,SubagentStop,TaskCompletedиTeammateIdleполе не действует. Смысл отказа на этих событиях другой - продолжить работу, а неисправный обработчик агент починить не сможет. PostToolUseпроисходит после успешного вызова. Хук не возвращает прежние файлы и не отменяет выполненное действие.
Учебный пример реагирует только на инструмент Bash. Через другие инструменты агент может выполнять другие действия; полнота реальной защиты зависит от событий, правил и проверок каждого обработчика. Исправный скрипт с неверным условием может вернуть 0 и пропустить запрещённое.
Сам хук выполняет код с правами твоего пользователя. Отдельная папка проекта не изолирует его от остального компьютера. Не запускай неизвестный чужой скрипт ради проверки: сначала изучи код, а для недоверенного кода используй ограниченную среду.
Чек-лист перед рабочим применением
- Проверена версия того клиента, где будет выполняться хук: 2.1.295 или новее.
- Настройка находится в нужном command или HTTP-обработчике, а событие подходит для остановки действия.
- В учебной папке подтверждены оба случая: сбой блокирует вызов, успешная проверка допускает его к обычным разрешениям.
- Результат установлен по записи инструмента; пересказ агента не принят за доказательство.
- Понятны остальные обработчики и разрешения, не выключенные ради опыта.
- Учебный отказ убран, прежние настройки сохранены; у рабочего скрипта отдельно проверена логика запретов.
Если любой пункт не подтверждён, оставь рабочую задачу на паузе. Начни с безопасного pwd и выясни точную причину отказа или пропуска.