Claude Code Hooks: settings.json, 5 событий и блокировка через exit code
Hooks — детерминированный слой Claude Code: они выполняются всегда, без напоминаний. Этот иллюстрированный разбор использует видео Anthropic о hooks для визуальной части — пять событий, блокирующий скрипт PreToolUse, структурированный deny JSON и полный конфиг форматирования PostToolUse.
TL;DR — что такое Claude Code hooks
- Hooks детерминированы: они выполняются в фиксированных точках жизненного цикла Claude Code каждый раз. Инструкция в CLAUDE.md вроде «запускай Prettier после каждой правки» срабатывает в большинстве случаев — hook срабатывает всегда.
- Событий пять: UserPromptSubmit (до обработки вашего промпта), PreToolUse (перед вызовом инструмента), PostToolUse (после завершения инструмента), Notification и Stop (когда Claude закончил отвечать).
- PreToolUse hook, завершившийся с exit code 2, блокирует вызов инструмента, а сообщение из stderr возвращается Claude, чтобы тот понял причину. Exit code 0 разрешает вызов.
- Hooks живут в settings.json — событие, опциональный matcher инструментов и команда. Держите их в .claude/settings.json проекта и коммитьте — вся команда наследует те же гарантии.
Hooks in Claude Code
Канал:Claude (official Anthropic channel)3:22
Claude Code Hooks, Explained Simply
Канал:Agentic Lab8:32
Claude Code - Getting Started with Hooks
Канал:Greg Baugues11:53
Hooks reference — Claude Code documentation
Документация:code.claude.com
Кадры этого гайда взяты из официального объясняющего видео Anthropic о hooks; текст написан независимо и сверен с официальной справкой по hooks.
Права на скриншоты остаются у их авторов; они используются с указанием авторства как визуальная документация. Каждый шаг глубокой ссылкой ведёт к точному моменту исходного видео.
Настройка Claude Code hooks шаг за шагом
1 · Как hooks выглядят в бою
- 1
Посмотрите, как hook срабатывает в конце ответа
В статусной строке написано «Running stop hook · 39s · 484 tokens» — Claude Code выполняет Stop hook, прежде чем вернуть ход вам. Вся идея в одном скриншоте: команда, которую вы зарегистрировали, выполняется в фиксированной точке жизненного цикла, при каждом совпадении, без надежды на то, что модель «не забудет».

Stop hook выполняется после ответа Claude — 39 секунд, 484 токенов израсходовано.Смотреть на 0:10 - 2
Выучите пять hook-событий
UserPromptSubmit срабатывает в момент отправки промпта, до обработки Claude. PreToolUse — перед каждым вызовом инструмента. PostToolUse — после завершения вызова. Notification срабатывает, когда Claude отправляет уведомление, а Stop — когда Claude закончил отвечать. Каждый ваш hook прикрепляется ровно к одной из этих пяти точек.

Пять событий из официального видео Anthropic о hooks — всё остальное держится на этом списке.Смотреть на 1:04
2 · Пишем первые hooks
- 3
Добавьте блок hooks в settings.json
Hook в settings.json — это три вещи: имя события, опциональный matcher, сужающий применение к конкретным инструментам, и команда. На скриншоте для matcher'а PreToolUse автодополняется Edit — такой hook будет срабатывать только на вызовах инструментов редактирования файлов. Не хотите править JSON вручную — меню /hooks редактирует тот же конфиг интерактивно.

Автодополнение подставляет Edit в matcher, ограничивая PreToolUse hook правками файлов.Смотреть на 0:14 - 4
Блокируйте опасные команды через exit code 2
PreToolUse hook получает имя инструмента и его ввод в JSON на stdin. Этот скрипт прогоняет его через jq, вытаскивая .tool_input.command, ищет grep'ом деструктивные шаблоны — rm -rf, git push --force — и при совпадении выводит причину в stderr и завершается с кодом 2. Exit code 2 блокирует вызов; текст из stderr возвращается Claude как обратная связь, и модель понимает, почему её остановили, и подстраивается.

jq читает команду из stdin; совпадение с rm -rf или --force печатает в stderr и завершается кодом 2.Смотреть на 2:02 - 5
Отправьте структурированный отказ вместо exit code
Для более тонкого контроля hook может напечатать JSON-решение вместо exit code. Здесь PreToolUse hook ловит DROP TABLE, а hookSpecificOutput передаёт permissionDecision «deny» с причиной — «используй migration» — прямо в контекст модели. Та же жёсткая гарантия, но с исполнимой инструкцией.

permissionDecision со значением deny блокирует SQL-команду и говорит модели, что делать вместо.Смотреть на 2:16 - 6
Держите hooks в репозитории, чтобы команда их получила
Hooks, настроенные в .claude/settings.json проекта, живут на уровне проекта и могут быть закоммичены. Каждый, кто клонирует репозиторий, автоматически запускает те же hooks — включая блокирующие. Служебные скрипты храните в .claude/hooks/ и ссылайтесь на них через переменную окружения CLAUDE_PROJECT_DIR, чтобы пути разрешались, где бы ни находилась рабочая директория Claude.

В папке .claude проекта лежат settings.json и каталог hooks/ со скриптами.Смотреть на 0:17 - 7
Скопируйте полный боевой конфиг hooks
Этот конфиг делает две работы сразу. Блок PostToolUse совпадает с Edit|Write|MultiEdit и запускает .claude/hooks/auto-format.sh с таймаутом 30 секунд — каждый файл, которого коснулся Claude, форматируется. Ниже второй hook совпадает с Bash и логирует каждую выполненную команду — классика комплаенса. Поля timeout и async не дают медленным форматтерам стопорить сессию.

Автоформатирование PostToolUse с таймаутом 30 с плюс Bash hook, логирующий каждую команду.Смотреть на 2:46
3 · Используем как команда
- 8
Знайте контракт exit code наизусть
Exit code 0 — продолжаем. Exit code 2 — блокировка, и stderr передаётся Claude как обратная связь, с которой можно работать. Любой другой exit code показывает stderr вам, пользователю, но вызов инструмента продолжается — используйте для предупреждений, которые хочется видеть, не останавливая агента намертво.
- 9
Зарегистрируйте hooks из меню /hooks и выберите рецепты
Команда /hooks открывает тот же конфиг интерактивно — удобно проверять, какие hooks зарегистрированы и в каком скоупе. Дальше — четыре рабочих рецепта: автоформатирование после правок (PostToolUse), лог всех выполненных команд (PostToolUse на Bash), блокировка опасных операций (PreToolUse с exit 2) и уведомление о завершении (Stop). Если что-то должно происходить всегда и без сбоев, не пишите это в промпт — пишите в hook.
Контракт exit code в одной таблице
Каждая hook-команда общается через свой exit code. Три случая покрывают всё:
- exit 0Продолжаем. Вызов инструмента выполняется как обычно. stdout hook'а виден в режиме транскрипта (Ctrl-R).
- exit 2Блокировка. Вызов отклоняется, а stderr hook'а возвращается Claude как обратная связь, и модель может скорректировать курс — именно поэтому exit-2 hooks учат, а не просто убивают.
- exit 1Любой другой код: предупреждай, не блокируй. stderr показывается вам, но вызов продолжается. Для совещательных hooks — «этот файл обычно генерируется, вы уверены?»
Есть путь прокачки: вместо exit code hook может напечатать JSON-решение (hookSpecificOutput с permissionDecision) и отказать со структурированной причиной, как в шаге 5. Exit code — простой контракт; JSON-решения — типизированный.
Четыре рецепта, которые стоит закоммитить сегодня
Официальное видео называет четыре сценария; вот они в виде готовых намерений:
- 1Автоформатирование после правок — PostToolUse hook на Edit|MultiEdit проверяет расширение файла и запускает нужный форматтер: Prettier для TypeScript, gofmt для Go, Ruff для Python.
- 2Лог каждой выполненной команды — PostToolUse hook на Bash дописывает каждую команду в файл. Комплаенс-команды в восторге; и вы в будущем, разбирая «что же тогда запускалось», тоже.
- 3Блокировка опасных операций — PreToolUse hook с exit 2 охраняет каталоги прод-конфигов, шаблоны rm -rf, коммиты в main. Это гарантии, а не пожелания.
- 4Уведомление о завершении — Stop или Notification hook запускает десктопное уведомление или звук, чтобы длинные агентные прогоны не требовали сидеть рядом.
Все четыре умещаются в одном .claude/settings.json. Начните с форматтера — это hook, который вы почувствуете при каждом сохранении.
