Hooks в Claude Code — это команды (а также HTTP-запросы, prompts и ещё несколько типов обработчиков), которые Claude Code автоматически запускает в определённые моменты сессии: например, перед запуском инструмента, когда требуется разрешение, или когда Claude заканчивает ответ. Они задаются в ключе hooks в файле настроек, например ~/.claude/settings.json. Каждый hook получает JSON с данными о событии через stdin и может ответить кодом выхода или JSON-объектом в stdout — так он может вести лог, отправлять уведомления, блокировать действие или отвечать за Вас.
01Как устроен hook
Конфигурация hook состоит из трёх уровней:
- Событие hook, например
PreToolUseилиStop. - Группа matcher, которая определяет, когда он срабатывает, например «только для инструмента Bash».
- Один или несколько обработчиков hook — то, что собственно выполняется.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "/path/to/lint-check.sh"
}
]
}
]
}
}
Этот пример запускает скрипт линтинга после того, как Claude создаёт или редактирует файл. Чтобы добавить второе событие, добавьте соседний ключ в тот же объект hooks.
02Где хранятся hooks
~/.claude/settings.jsonВсе Ваши проектыНет, только на Вашем компьютере.claude/settings.jsonОдин проектДа, можно закоммитить.claude/settings.local.jsonОдин проектНетhooks/hooks.json плагинаПока плагин включёнДаHooks из разных файлов суммируются, а не заменяют друг друга. Введите /hooks в Claude Code, чтобы увидеть все активные hooks и их источники.
В интерактивной сессии Claude Code не запускает hooks, даже Ваши собственные, пока Вы не подтвердите доверие к папке в диалоге workspace trust.
03Типы обработчиков
Большинство hooks имеют тип "type": "command" и запускают shell-команду. Есть ещё четыре типа:
http: отправляет JSON события POST-запросом на URL и читает тело ответа.mcp_tool: вызывает инструмент на настроенном Вами MCP-сервере.prompt: задаёт модели Claude однократный вопрос и читает решение в формате JSON.agent: запускает субагента, который может прочитать файлы, прежде чем принять решение (экспериментально).
Command hooks выполняются с полными правами Вашего пользователя: через sh -c на macOS и Linux и через Git Bash (или PowerShell) на Windows. Добавьте "async": true, чтобы запускать hook в фоне; в этом случае он уже не сможет принимать решения.
04Matchers
matcher определяет, при каких вхождениях события запускается hook. С чем он сравнивается, зависит от события: с именем инструмента для событий инструментов, с типом уведомления для Notification, со способом запуска сессии для SessionStart и так далее.
"*",""или отсутствие matcher соответствуют всему.- Буквы, цифры,
_,-, пробелы,|и,трактуются как точные имена.Edit|Writeсоответствует любому из двух инструментов. - Всё остальное считается регулярным выражением JavaScript, поэтому
mcp__memory__.*соответствует всем инструментам одного MCP-сервера.
Matchers чувствительны к регистру. Некоторые события, в том числе Stop и UserPromptSubmit, игнорируют matchers. Для событий инструментов поле if с правилом разрешений, например "Bash(git *)", дополнительно сужает срабатывание отдельного обработчика.
05Входные данные: что получает hook
Каждый hook получает через stdin JSON с несколькими общими полями, включая session_id, transcript_path, cwd и hook_event_name, а также поля, специфичные для события. Например, hook PreToolUse для вызова Bash также получает tool_name и tool_input.command. Прочитать их можно с помощью jq или любого JSON-парсера:
#!/bin/bash
input=$(cat)
cmd=$(jq -r '.tool_input.command // empty' <<<"$input")
echo "Claude wants to run: $cmd" >> ~/claude-commands.log
exit 0
06Выходные данные: коды выхода и JSON
Hook может ответить одним из двух способов.
Коды выхода. 0 означает успех. 2 — блокирующая ошибка: для событий, которые поддерживают блокировку, действие останавливается, а Ваш stderr становится его причиной. Любой другой код, включая привычный 1, — неблокирующая ошибка: действие выполняется, а Вы видите уведомление об ошибке hook. Если hook должен обеспечивать соблюдение правила, завершайте его с кодом 2, а не 1.
JSON в stdout. Для более тонкого управления завершитесь с кодом 0 и выведите один JSON-объект. Некоторые поля работают везде, например continue: false, чтобы полностью остановить Claude. Другие зависят от события: Stop использует decision: "block" вместе с reason, а PreToolUse и PermissionRequest передают решение внутри hookSpecificOutput. Больше ничего в stdout не выводите: случайная строка из профиля shell помешает Claude Code прочитать JSON.
07Все события hook
SessionStartСессия начинается или возобновляетсяНет (добавляет контекст)SetupЗапуск с --init-only или --init / --maintenance вместе с -pНетInstructionsLoadedЗагружается файл CLAUDE.md или .claude/rules/*.mdНетUserPromptSubmitВы отправляете prompt, до того как его увидит ClaudeДаUserPromptExpansionВведённая команда разворачивается в promptДаPreToolUseПеред любым вызовом инструментаДаPermissionRequestДля вызова инструмента требуется решение о разрешенииРазрешает или запрещает через JSONPermissionDeniedAuto mode отклоняет вызов инструментаНетPostToolUseПосле успешного вызова инструментаНет (инструмент уже выполнен)PostToolUseFailureПосле неудачного вызова инструментаНетPostToolBatchПосле пакета параллельных вызовов инструментов, перед следующим обращением к моделиДаNotificationClaude Code отправляет уведомлениеНетMessageDisplayВо время отображения текста ответа ClaudeНет (может изменить отображаемое)SubagentStart / SubagentStopSubagent запускается или завершаетсяТолько SubagentStopTaskCreated / TaskCompletedЗадача создана или отмечена как выполненнаяДаStopClaude заканчивает ответДа (заставляет Claude продолжить)StopFailureХод завершается ошибкой APIНетTeammateIdleУчастник agent team вот-вот перейдёт в режим ожиданияДаConfigChangeФайл настроек изменяется во время сессииДаCwdChangedМеняется рабочий каталогНетDirectoryAddedКаталог добавлен через /add-dirНетFileChangedОтслеживаемый файл изменился на дискеНетWorktreeCreate / WorktreeRemoveWorktree создаётся или удаляетсяДаPreCompact / PostCompactДо и после сжатия контекстаТолько PreCompactPreModelSwitch / PostModelSwitchДо и после смены моделиТолько PreModelSwitchElicitation / ElicitationResultMCP-сервер запрашивает ввод, а также после Вашего ответаДаSessionEndСессия завершаетсяНетAnthropic периодически добавляет новые события, поэтому актуальный список и поля входных данных каждого события смотрите в справочнике по hooks.
08Какие события важны для уведомлений
Четыре события покрывают почти всё, о чём обычно хотят получать уведомления:
Stop— «Claude закончил». См. руководство по Stop hook.Notification— «Claude ждёт Вас», с типами вродеpermission_promptиidle_prompt. См. руководство по Notification hook.PermissionRequest— чтобы сразу узнать о запросе разрешения или ответить на него. См. руководство по PermissionRequest.PreToolUseдля инструментаAskUserQuestion— чтобы видеть вопросы Claude с вариантами ответа и отвечать на них. См. ответы на вопросы с телефона.
Готовую настройку для десктопа, которую можно просто вставить, ищите в статье как получить уведомление, когда Claude Code закончит работу.
09Место Claude Code Notifier
Claude Code Notifier целиком построен на этих hooks. Его бесплатная утилита командной строки ccn работает на Mac, Windows и Linux. При установке она добавляет в ~/.claude/settings.json семь записей hooks, каждая из которых запускает ccn hook, и один раз делает резервную копию файла. ccn работает несколько миллисекунд на событие и завершается, так что в фоне ничего не остаётся.
Сама по себе утилита показывает уведомления на рабочем столе. Если подключить приложение для iPhone или Android, те же hooks передают обратно Ваши ответы: разрешить или отклонить запрос, ответить на вопрос или отправить следующую инструкцию после остановки Claude. Это независимый продукт, не созданный Anthropic. Если Вам нужен только лог или линтинг, проще написать несколько строк самостоятельно. Подробности — на странице ccn.
10FAQ
Как протестировать hook, не дожидаясь Claude?
Передайте в скрипт пример JSON через pipe и проверьте код выхода: echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh; echo $?. Затем выполните /hooks в Claude Code, чтобы убедиться, что hook зарегистрирован на нужное событие.
Почему мой hook не запускается?
Обычные причины: невалидный JSON в settings.json (висячие запятые, комментарии), matcher, который не совпадает точно (он чувствителен к регистру), скрипт без права на выполнение или папка, которой Вы ещё не доверили. Запустите Claude Code с claude --debug и посмотрите в debug-логе, что запускалось. Полный список — в чек-листе по устранению неполадок.
Как временно отключить все hooks?
Укажите "disableAllHooks": true в файле настроек. Чтобы пропустить их на один запуск, запустите Claude Code с --settings '{"disableAllHooks": true}'. Отдельного переключателя для одного hook нет — вместо этого удалите его запись. Ни один из способов не отключает hooks, заданные Вашей организацией в managed settings.
Какой таймаут у hook по умолчанию?
Десять минут (600 секунд) для command, HTTP и MCP tool hooks, 30 секунд для prompt hooks и 60 — для agent hooks. У некоторых событий значения по умолчанию короче; для любого обработчика можно задать timeout в секундах.