Хуки Claude Code — это пользовательские shell-команды (а также HTTP-эндпоинты и промпты), которые агент запускает автоматически в конкретных точках своего жизненного цикла: перед вызовом инструмента, после записи файла, при старте сессии, когда останавливается. Главное отличие от промпта или навыка: хук срабатывает гарантированно, а не «если модель решит». Это самый мощный рычаг настройки Claude Code — и одновременно самый опасный, потому что командный хук исполняется с полными правами вашего пользователя в системе.
- Что такое хуки и зачем они нужны
- Как объявить хук в settings.json
- События жизненного цикла: 30 точек, из которых ходовых — десяток
- Exit-коды и как хук блокирует действие
- Три рабочих рецепта: формат, гейт на секреты, уведомление
- Где ломается: слои защиты и их слабые места
- Безопасность и риски: хук — это произвольный код с полными правами
- FAQ
Хуки — быстро меняющаяся часть Claude Code: официальный список событий уже вырос до 30, поэтому у любого гайда по теме есть срок годности, и дату сверки стоит держать в голове.
Ниже — рабочая ментальная модель механизма, разбор settings.json с примерами JSON, полная логика exit-кодов, три проверенных по документации рецепта и честный разбор рисков с датированными инцидентами, а не общими словами «будьте осторожны с shell».
Что такое хуки и зачем они нужны
Хук — это связка «событие → условие → действие». Когда в Claude Code наступает событие (например, агент собирается выполнить bash-команду), система проверяет ваши настройки, и если условие совпало, запускает заданную команду. Официальная документация формулирует смысл через одно слово — детерминизм: хуки дают предсказуемый контроль над поведением агента, гарантируя, что нужное действие произойдёт всегда, а не будет зависеть от того, «вспомнит» ли модель про инструкцию.
Это ключевая граница между хуком и соседними механизмами расширения. Навык (skill) — инструкция, которой модель может последовать, а может и нет. MCP-инструмент — функция, которую модель вызовет, если сочтёт нужным. Хук же не спрашивает модель: условие выполнено — команда запущена. Такую же логику детерминированного контроля независимо описывают и русскоязычные разборы темы, и официальный гайд Anthropic.
Практический вывод: хуки нужны там, где «попросить модель» недостаточно надёжно. Автоформатирование кода, запрет на правку секретов, запуск тестов, аудит-лог каждой команды, уведомление на телефон — всё это должно происходить каждый раз, а не через раз.Механизм Кто решает, запускать Когда выбирать Хук Условие в settings.json (детерминированно) Действие обязано случаться всегда: формат, гейт, лог Навык (skill) Модель — по контексту Нужна гибкая процедура, где уместно суждение модели MCP-инструмент Модель — вызывает при необходимости Доступ к внешним данным и API как к инструменту Субагент Модель — делегирует задачу Тяжёлая изолированная работа в отдельном контексте Sandboxing / permission-правила Движок Claude Code Ограничить файлы и сеть, разрешить/запретить инструмент
Ещё один недооценённый плюс: командные и HTTP-хуки почти не тратят токены модели. Форматтер, линтер или проверка запускаются как обычный процесс ОС, а не как рассуждение LLM — сообщество прямо ценит это как «автоматизацию за ноль токенов». Навык или субагент на ту же задачу съели бы часть контекстного окна; хук — нет.
Хуки появились в Claude Code не сразу: по официальному CHANGELOG репозитория anthropics/claude-code их выпустили в версии v1.0.38. Это тот случай, когда точную версию релиза полезно знать — почти ни один сторонний гайд её не называет, а она объясняет, почему список событий с тех пор так разросся.
Как объявить хук в settings.json
Хуки описываются декларативно в файле settings.json. Конфигурация имеет три уровня вложенности, и понимание этой структуры снимает большую часть вопросов:
- Событие — на что реагируем (
PreToolUse,PostToolUse,Stopи т. д.). - Matcher-группа — фильтр, когда именно срабатывать (например, «только для инструмента Bash»).
- Обработчики (handlers) — одна или несколько команд, которые запускаются при совпадении.
Минимальный пример: перед каждым вызовом Bash прогонять свой скрипт-проверку.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/Users/me/.claude/hooks/check-bash.sh"
}
]
}
]
}
}
Поле matcher трактуется по простым правилам. Пусто, "*" или отсутствует — совпадает всегда. Строка только из букв, цифр, _, -, пробелов, запятых и | — точное совпадение или список точных значений через | (например, "Edit|Write"). Любой другой символ превращает значение в JavaScript-регулярное выражение без якорей — удобно, но легко выстрелить себе в ногу, если не помнить про это.
Обработчик бывает пяти типов: command (shell-команда), http (POST на эндпоинт), mcp_tool, prompt и agent. В подавляющем большинстве практических случаев вы пишете именно command.
Где лежит файл — определяет область действия хука. Это важно с точки зрения безопасности: хук из чужого репозитория действует так же, как ваш собственный.Расположение Область Коммитится в репозиторий ~/.claude/settings.jsonВсе ваши проекты Нет, локально на машине .claude/settings.jsonОдин проект Да, попадает в git .claude/settings.local.jsonОдин проект Нет, в .gitignoreManaged policy settings Вся организация Задаёт администратор hooks/hooks.json плагинаПроекты с плагином Через маркетплейс плагинов Frontmatter навыка/субагента При активации навыка Вместе с навыком
Проверить, какие хуки вообще зарегистрированы, помогает встроенная команда /hooks — она открывает read-only список всех событий с числом хуков, matcher’ами, типом и файлом-источником. Менять хуки прямо из меню нельзя: только правкой JSON или через просьбу к агенту.
События жизненного цикла: 30 точек, из которых ходовых — десяток
Вот тот самый разрыв, который важно зафиксировать явно. Большинство туториалов 2026 года перечисляют 9–13 «событий жизненного цикла»: один из топовых англоязычных гайдов прямо озаглавлен «All 12 Lifecycle Events». Актуальный официальный reference на июль 2026 года содержит их около 30 — от SessionStart и Setup до Elicitation и SessionEnd. Это не ошибка авторов гайдов, а протухание контента: список расширяется быстрее, чем материалы успевают обновляться. Полную таблицу держит первоисточник; здесь — ходовые события, которые закрывают почти все реальные сценарии.Событие Когда срабатывает Может заблокировать действие SessionStartСтарт сессии Claude Code — UserPromptSubmitПользователь отправил запрос Да (может отклонить/дополнить промпт) PreToolUseПеред вызовом любого инструмента Да — единственное с полным контролем решения PostToolUseСразу после выполнения инструмента Нет — инструмент уже отработал NotificationАгент ждёт ответа/разрешения — StopАгент завершает ход Да (может вернуть его в работу) SubagentStopЗавершился субагент Да PreCompactПеред сжатием контекста — SessionEndКонец сессии —
События удобно делить по кадансу — как часто они срабатывают. Официальный reference выделяет три группы: раз за сессию (SessionStart, SessionEnd), раз за ход (UserPromptSubmit, Stop, StopFailure) и на каждый вызов инструмента внутри агентного цикла (PreToolUse, PostToolUse). Это сразу подсказывает, где хук будет дёргаться десятки раз за задачу (и должен быть быстрым), а где — единожды.
Практический костяк: PreToolUse — для запретов и проверок до действия; PostToolUse — для реакции после (формат, тесты); Notification — чтобы не пропустить, что агент вас ждёт; Stop — чтобы не дать закончить, пока не выполнено условие; SessionStart — чтобы подгрузить контекст. Остальные события существуют под тонкие сценарии, и лезть в них стоит, только когда ходовых не хватает.
Exit-коды и как хук блокирует действие
Хук общается с Claude Code двумя каналами: кодом возврата процесса и JSON на stdout. Начнём с кодов — здесь у конкурентов встречается прямая ошибка.
- Exit 0 — успех. Claude Code читает stdout; если там валидный JSON, он его разбирает и учитывает.
- Exit 2 — блокирующая ошибка. Для
PreToolUseэто отменяет вызов инструмента; stdout игнорируется, а текст из stderr передаётся модели как причина отказа. - Любой другой код — неблокирующая ошибка для большинства событий (исключение —
WorktreeCreate, где любой ненулевой код отменяет операцию).
Здесь важная поправка к распространённому источнику: популярный туториал DataCamp приписывает коду exit 3 значение «Deferred execution». В официальном reference такого кода нет — есть только 0, 2 и «прочее». Слово «defer» в документации относится к полю permissionDecision, а не к коду возврата. Если вы читали про «exit 3» — это неточный пересказ, не закладывайте его в свои скрипты.
Точный контроль над разрешениями даёт не код, а JSON. У события PreToolUse есть уникальная возможность: вернуть в hookSpecificOutput.permissionDecision одно из четырёх решений — allow (пропустить без запроса), deny (запретить вызов), ask (спросить пользователя) или defer (аккуратно выйти, не вмешиваясь). Если несколько PreToolUse-хуков вернули разные решения, приоритет такой: deny > defer > ask > allow. Пример ответа, который жёстко блокирует команду:
{
"hookSpecificOutput": {
"permissionDecision": "deny",
"permissionDecisionReason": "Правка .env запрещена политикой проекта"
}
}
На вход каждый командный хук получает JSON через stdin. Общие для всех событий поля: session_id, prompt_id, transcript_path (путь к JSON-транскрипту разговора), cwd, permission_mode и hook_event_name; для событий-инструментов добавляются tool_name и tool_input. HTTP-хуки получают тот же JSON телом POST-запроса. Отсюда простое правило: скрипт-хук читает stdin, парсит нужные поля и решает, что делать.
Отдельно про PostToolUse: он не может откатить уже выполненное действие. Exit 2 покажет модели ваш stderr как обратную связь, но инструмент к этому моменту уже отработал. Поэтому запреты вешают на PreToolUse (до действия), а PostToolUse используют для того, что уместно делать после — форматирования, запуска проверок, логирования.
Три рабочих рецепта: формат, гейт на секреты, уведомление
Ниже — три готовых сценария, собранных по официальному guide. Каждый — это command-хук; путь к скрипту подставьте свой.
1. Автоформатирование после Edit/Write. Классический PostToolUse: как только агент записал файл, прогоняем форматтер. Экономит ревью и держит стиль ровным — и всё это за ноль токенов модели.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }
]
}
]
}
}
2. Блокировка правки .env и других защищённых файлов. Это PreToolUse с решением deny. Скрипт читает tool_input из stdin, смотрит путь и, если он ведёт к секрету или в .git, возвращает exit 2 с причиной в stderr (или JSON с permissionDecision: deny). Агент не сможет тронуть файл, даже если «очень захочет» — в отличие от текстовой инструкции в промпте, которую модель может проигнорировать.
3. Десктоп-уведомление, когда агент ждёт вас. Событие Notification срабатывает, когда Claude Code остановился в ожидании ответа или разрешения. Хук на macOS может дёрнуть системный баннер:
{
"hooks": {
"Notification": [
{
"matcher": "*",
"hooks": [
{ "type": "command", "command": "osascript -e 'display notification \"Claude ждёт ответа\" with title \"Claude Code\"'" }
]
}
]
}
}
Для долгих задач есть важная деталь. По умолчанию хук блокирует работу агента, пока не завершится. Если проверка тяжёлая (полный прогон тестов, деплой), задайте у command-хука поле "async": true — он уйдёт в фон, а агент продолжит работу; таймаут по умолчанию — 10 минут. Дополнительное поле "asyncRewake": true «разбудит» агента, если фоновый хук завершится с exit 2. Эту связку почти не описывают в гайдах, хотя именно она позволяет встроить долгие проверки без просадки скорости работы.
Сколько это стоит? Не в токенах (их хуки почти не тратят), а в труде на настройку и в риске сломать поток. Полезно оценивать хуки по этой рамке до внедрения:Хук Что даёт Что сломает при ошибке в скрипте Автоформат ( PostToolUse)Единый стиль без ручного ревью Испорченный файл, если форматтер падает Гейт на секреты ( PreToolUse deny)Запрет правки .env/.gitЛожные блокировки, агент «застревает» Уведомление ( Notification)Не пропустить ожидание агента Спам баннеров при частых паузах Async-проверка (тесты/деплой) Долгие гейты без блокировки Незамеченный провал, если забыть asyncRewake
Где ломается: слои защиты и их слабые места
Здесь самый частый пробел конкурентов: хуки подают как единый абсолютный барьер. На деле защита многослойная, и у каждого слоя своя граница.
Хук-deny сильнее режима обхода прав. PreToolUse-хуки срабатывают до проверки режима разрешений. Хук, вернувший permissionDecision: deny, блокирует инструмент даже в режиме bypassPermissions и с флагом --dangerously-skip-permissions. Обратное неверно: allow из хука не отменяет deny-правила из настроек. То есть для жёсткого запрета PreToolUse-хук надёжнее, чем правила разрешений сами по себе.
Почему это не абстракция — показал смежный баг. Adversa AI 2 апреля 2026 года описала, что легаси regex-парсер Claude Code переставал применять deny-правила разрешений, если bash-команда содержала более 50 подкоманд (через &&, || или ;), и падал в общий разрешающий запрос. Исправленный парсер существовал в кодовой базе, но на дату отчёта не был в публичной сборке. Практический вывод ровно тот же: для критичных запретов опирайтесь на PreToolUse-хук, а не только на allow/deny в settings.json.
Но и хук — не бетон. Внутри обработчика есть best-effort фильтр if, которым удобно ограничивать срабатывание по содержимому bash-команды. Официальная документация честно предупреждает: этот фильтр fail-open — если команду не удалось распарсить, хук запустится в любом случае. Многие практики интуитивно считают if жёсткой стеной; для настоящего hard-deny документация прямо рекомендует permission-систему, а не фильтр в хуке.
Stop-хук может залипнуть. Хук на событии Stop умеет возвращать агента в работу, пока не выполнено условие — но это же создаёт риск бесконечного цикла. Защита встроена: Claude Code принудительно завершает ход после 8 подряд блокировок Stop-хуком без прогресса. Если вашей проверке легитимно нужно больше итераций, лимит поднимается переменной окружения CLAUDE_CODE_STOP_HOOK_BLOCK_CAP.
Это тот класс задач, где детерминированный хук честнее агентной автоматизации: одно дело — навык, который ведёт базу знаний и сам решает, что и когда записать, и совсем другое — жёсткий гейт, который обязан сработать при каждом коммите. Если вам нужен не гарантированный триггер, а гибкий автономный помощник — это уже другой класс инструмента, и хук тут не замена.
Безопасность и риски: хук — это произвольный код с полными правами
Главный тезис раздела прямой: командный хук исполняется с полными правами вашего системного пользователя. Официальный диклеймер не оставляет двусмысленности — хук может прочитать, изменить или удалить любой файл, к которому у вас есть доступ, выполнить произвольный bash, сходить в сеть, добраться до переменных окружения с ключами. Независимые security-разборы формулируют то же самое. Отсюда правило: любой хук нужно прочитать и протестировать до того, как он попадёт в конфиг.
Опасность усиливает то, что settings.json психологически воспринимается как «метаданные», а не как исполняемый код. Это делает хуки тихим вектором supply-chain атак — и это уже не гипотеза.
CVE-2025-59536 и CVE-2026-21852. Исследователи Check Point (Авив Доненфельд, Одед Вануну) показали, что хук SessionStart из .claude/settings.json чужого репозитория выполнялся без явного подтверждения пользователя — в отличие от обычных bash-команд. Через это удавалось дойти до удалённого выполнения кода и эксфильтрации API-ключа (подмена ANTHROPIC_BASE_URL). Первый баг получил CVSS 8.7 (High), второй — 5.3. CVE-2026-21852 опубликован Anthropic 21 января 2026 года, публичное раскрытие Check Point — 25 февраля 2026 года; на дату отчёта обе уязвимости уже были полностью пропатчены.
Кампания Shai-Hulud. Тот же SessionStart-хук использовали как механизм персистентности supply-chain малвари в npm-пакетах. Техника «внедрить SessionStart-хук через .claude/settings.json из пакета» впервые появилась в Wave 3 кампании (пакеты SAP CAP-JS/MBT, апрель 2026 года, около 4 пакетов) и вернулась в Wave 5: 19 мая 2026 года через скомпрометированный аккаунт мейнтейнера за примерно час опубликовали, по данным Socket через Snyk, 637 версий в 323 пакетах (@antv/* и ещё свыше 310); в отчёте BleepingComputer и в GitHub-issue фигурирует цифра 639 версий — расхождение на пару версий объясняется разным моментом снимка. Хук переживает перезапуск и запускает код атакующего при следующем открытии Claude Code — ещё до любого ввода пользователя. Хронология Wave 3 → Wave 5 наглядно показывает, что это эволюция одной техники, а не разрозненные инциденты.
Претензия сообщества. GitHub-issue #49778 (создан 17 апреля, закрыт как not_planned 26 июня 2026 года) формулирует архитектурную проблему: у активных хуков нет постоянного индикатора в интерфейсе, и нет подтверждения, когда хук регистрирует сторонний процесс — npm postinstall, плагин, навык. Показательно, что Shai-Hulud Wave 5 (19 мая) на практике реализовала ровно тот риск, который issue описал теоретически.
Что с этим делать:
- Не доверяйте
.claude/settings.jsonиз чужих и клонированных репозиториев. После клонирования запустите/hooksи посмотрите, что зарегистрировано. - Для команд и организаций есть жёсткие рычаги:
allowManagedHooksOnlyблокирует пользовательские, проектные и плагинные хуки, аdisableAllHooks: trueотключает хуки вовсе. Отключить managed-хуки может толькоdisableAllHooks, заданный на уровне managed-политики — рядовой пользователь их не снимет. - Смежная линия защиты — sandboxed Bash tool: он отдельно ограничивает файловую систему и сеть и дополняет, а не заменяет
PreToolUse-deny хуки.
Экосистема при этом живая: крупнейшая открытая коллекция примеров disler/claude-code-hooks-mastery набрала 3822 звезды и 627 форков (снимок на 11 июля 2026 года). Готовые хуки — это удобно, но каждый из них — чужой код с вашими правами, так что правило «прочитал и проверил» распространяется и на них.
Стоит отделять этот материал от похожего по названию Agent SDK hooks: если вы строите приложение на Claude Agent SDK, там хуки — это программные callback-функции в коде (TypeScript/Python), а не JSON-конфиг в settings.json. Механика близка, способ подключения разный. Похожая экосистема расширений — навыки, MCP, хуки — стала стандартом и у продуктов на базе Claude Code: например, постоянного ИИ-коллегу в Slack собирают на той же связке.
FAQ
Чем PreToolUse отличается от PostToolUse простыми словами?
PreToolUse срабатывает до вызова инструмента и может его заблокировать, разрешить или отправить на подтверждение — это единственное событие с полным контролем решения. PostToolUse срабатывает после: он видит результат и может дать модели обратную связь, но отменить уже выполненное действие не в состоянии. Запреты вешают на первый, реакции (формат, тесты, логи) — на второй.
Хук с exit-кодом 3 существует?
Нет. Официальный reference описывает только exit 0 (успех), exit 2 (блокирующая ошибка) и «любой другой код» как неблокирующую ошибку. Значение «Deferred execution» для exit 3 встречается в стороннем туториале DataCamp, но это неточность: «defer» — это одно из значений поля permissionDecision, а не код возврата процесса.
Сколько событий жизненного цикла у Claude Code на самом деле?
На июль 2026 года официальный справочник перечисляет около 30 событий. Многие гайды называют 9–13 — они писались раньше и просто устарели, потому что список активно расширяется. Ходовых при этом около десятка: PreToolUse, PostToolUse, UserPromptSubmit, Notification, Stop, SubagentStop, SessionStart, PreCompact, SessionEnd.
Могут ли хуки навредить компьютеру?
Да, если хук вредоносный. Командный хук выполняется с полными правами вашего пользователя и может делать всё, что можете вы. Уже задокументированы реальные случаи: CVE-2025-59536 (RCE через SessionStart-хук чужого репозитория, пропатчено) и кампания Shai-Hulud, где SessionStart-хук в npm-пакетах служил механизмом закрепления малвари. Поэтому чужие settings.json не запускают вслепую.
Тратят ли хуки токены модели?
Практически нет. Командные и HTTP-хуки — это обычные процессы ОС и сетевые запросы, они не идут через контекст модели. Именно поэтому форматтеры, линтеры и проверки на хуках считаются «бесплатной» в токенах автоматизацией, в отличие от навыков и субагентов, которые расходуют часть контекстного окна.
Как запретить агенту трогать определённые файлы?
Повесьте PreToolUse-хук на инструменты Edit|Write (и Bash, если правки идут командами), который читает путь из tool_input и возвращает permissionDecision: deny для защищённых путей вроде .env или .git. Такой хук держится даже в режиме обхода прав. Для организаций жёстче — allowManagedHooksOnly и disableAllHooks на уровне managed-политики.
Курс «Claude Code с нуля до продакшена» · модуль «Конфиг, память, навыки». Полная программа и два маршрута обучения — на странице курса.
Предыдущий урок: MCP в Claude Code: настройка, Tool Search


