Хуки Claude Code — это команды, которые Claude Code сам запускает в фиксированные моменты сессии: перед вызовом инструмента, после правки файла, при отправке промпта, когда Claude останавливается или ему нужно ваше внимание. Они описываются под ключом hooks в settings.json. Хук может добавить контекст, отформатировать файл или заблокировать действие, завершившись с кодом 2 или вернув JSON-решение. В отличие от инструкций в CLAUDE.md, хук срабатывает всегда, потому что его запускает среда выполнения, а не модель.
В этом руководстве: важные события, формат конфигурации, matcher, коды выхода и JSON-ответ, три хука, которые можно скопировать сегодня, и замечания по безопасности, которые стоит прочитать до добавления любого хука. Факты взяты из официального справочника по хукам и руководства по хукам. Если нужно только короткое определение, см. статью глоссария о хуках Claude Code.
Зачем нужны хуки, если есть инструкции
В CLAUDE.md можно написать «всегда запускай Prettier после правок», и Claude обычно так и сделает. «Обычно» — вот в чём проблема. Инструкции — это совет, который модель взвешивает вместе со всем остальным в своём контексте. Хуки — это код, который выполняется каждый раз, когда срабатывает событие.
Поэтому хуки подходят для трёх видов правил:
- То, что должно происходить всегда: форматирование, линтинг, логирование.
- То, чего не должно происходить никогда: правка
.envилиrm -rfне в той папке. - То, о чём вы хотите знать: например, Claude ждёт ответа на запрос разрешения, пока вы в другом окне.
Советы по стилю и знания о проекте держите в CLAUDE.md, а жёсткие правила — в хуках.
События хуков, которые вам реально понадобятся
В справочнике больше тридцати событий, и список растёт с новыми релизами. В большинстве реальных настроек используется несколько:
| Событие | Когда срабатывает | Может ли блокировать? |
|---|---|---|
PreToolUse | Перед запуском вызова инструмента | Да, блокирует вызов |
PostToolUse | После успешного вызова инструмента | Нет, инструмент уже отработал; stderr уходит Claude |
UserPromptSubmit | Когда вы отправляете промпт | Да, промпт не доходит до Claude |
Notification | Когда Claude Code отправляет уведомление, например запрос разрешения или ожидание | Нет |
Stop | Когда Claude заканчивает ответ | Да, Claude продолжает работать |
SubagentStart / SubagentStop | Когда субагент запускается или завершается | Только SubagentStop |
SessionStart | При запуске, возобновлении, /clear или сжатии | Нет, но stdout становится контекстом |
PreCompact | Перед сжатием контекста | Да, блокирует сжатие |
PermissionRequest | Когда вот-вот появится диалог разрешения | Только через JSON, не через exit 2 |
SessionEnd | Когда сессия заканчивается | Нет |
Большинство задач закрывают PreToolUse и PostToolUse. Для «сообщи мне, когда готово или завис» подходят Notification и Stop.
Как хуки настраиваются в settings.json
Хуки живут в тех же файлах настроек, что и разрешения:
| Файл | Область | Передаётся через git? |
|---|---|---|
~/.claude/settings.json | Все ваши проекты | Нет |
.claude/settings.json | Один проект | Да |
.claude/settings.local.json | Один проект, только вы | Нет (в gitignore) |
| Managed policy settings | Вся организация | Задают администраторы |
Плагины могут поставлять хуки в hooks/hooks.json, а skills и субагенты — описывать хуки в своём frontmatter.
Структура состоит из трёх уровней: событие, группа matcher и список обработчиков.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write",
"timeout": 30
}
]
}
]
}
}
type обработчика может быть command (shell-команда), http (POST на URL), mcp_tool (инструмент подключённого MCP-сервера), prompt (быстрая проверка «да/нет» моделью) или agent (экспериментальная проверка субагентом). Таймаут по умолчанию — 600 секунд для обработчиков command, HTTP и MCP tool, 30 секунд для хуков prompt и 60 для хуков agent.
Каждый хук получает JSON на stdin. Общие поля: session_id, transcript_path, cwd, permission_mode и hook_event_name. События инструментов добавляют tool_name, tool_input и tool_use_id. Ваш скрипт читает этот JSON, обычно через jq, и решает, что делать. Переменная окружения CLAUDE_PROJECT_DIR указывает на корень проекта, что удобно для ссылок на скрипты из репозитория.
Введите /hooks в Claude Code, чтобы посмотреть, что загружено и из какого файла пришёл каждый хук. Браузер хуков работает только на чтение, поэтому менять хуки нужно, редактируя JSON.
Matcher: какие вызовы инструментов видит хук
matcher определяет, какие вызовы запускают хук. Для событий инструментов он сопоставляется с именем инструмента:
| Matcher | Значение |
|---|---|
"*", "" или без matcher | Каждый вызов |
"Bash" | Именно инструмент Bash |
"Edit|Write" | Edit или Write (список) |
"mcp__memory__.*" | Каждый инструмент MCP-сервера memory |
"mcp__.*__write.*" | Любой инструмент MCP, имя которого начинается с write |
Правило простое. Если matcher содержит только буквы, цифры, _, -, пробелы, запятые или |, это точное имя или список имён. Любой другой символ превращает его в регулярное выражение JavaScript. Инструменты MCP называются mcp__<server>__<tool>.
Некоторые события игнорируют matcher, в том числе UserPromptSubmit и Stop, потому что сопоставлять нечего. Другие сопоставляют не имя инструмента. SessionStart сопоставляет способ запуска сессии (startup, resume, clear, compact), а Notification — тип уведомления, например permission_prompt или idle_prompt.
События инструментов также принимают поле if с синтаксисом правил разрешений, так что хук Bash может запускаться только для, скажем, "Bash(git *)". В документации это описано как фильтр по принципу «лучшее из возможного», поэтому настоящую проверку держите в скрипте.
Коды выхода и JSON-ответ
Командный хук отвечает Claude Code двумя способами: кодом выхода и необязательным JSON в stdout.
| Код выхода | Что происходит |
|---|---|
0 | Успех. stdout разбирается как JSON, если это один JSON-объект. Для UserPromptSubmit и SessionStart простой текст в stdout добавляется в контекст Claude. |
2 | Блокирующая ошибка. stderr — это причина. В PreToolUse вызов отменяется, в UserPromptSubmit промпт отклоняется, в Stop Claude продолжает работу. |
Любой другой, включая 1 | Неблокирующая ошибка. Claude Code отмечает её и идёт дальше. |
Ловушка здесь — код выхода 1. Многие скрипты по умолчанию падают с 1, и это не блокирует ничего. Если вы имеете в виду «остановить», выходите с 2.
Для более тонкого управления завершайтесь с 0 и выводите JSON. Хук PreToolUse может разрешить, запретить или спросить:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Use rg instead of grep for better performance"
}
}
permissionDecision принимает allow, deny, ask или defer. Хук также может переписать вызов через updatedInput или передать Claude дополнительный текст через additionalContext. Поля, работающие для любого события, включают continue: false (полностью остановить Claude, с stopReason) и systemMessage (предупреждение, которое видите вы).
Если подходит несколько хуков, они выполняются параллельно, и побеждает самый строгий ответ: deny сильнее defer, defer сильнее ask, ask сильнее allow. allow от хука не отменяет правило deny в ваших разрешениях.
Пример 1: форматировать файлы после каждой правки
С этого хука начинает большинство. Он запускает Prettier для любого файла, который пишет или правит Claude:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}
Для других языков подставьте ruff format, gofmt -w или rustfmt. Поскольку форматтер запускается после правки, Claude увидит отформатированный файл при следующем чтении, а вы перестанете встречать в ревью diff, где меняется только стиль.
Пример 2: блокировать опасные команды и защищённые файлы
Хук PreToolUse — место для жёстких ограничений. Этот скрипт, адаптированный из официального руководства, блокирует правки чувствительных файлов. Сохраните его как .claude/hooks/protect-files.sh:
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")
for pattern in "${PROTECTED_PATTERNS[@]}"; do
if [[ "$FILE_PATH" == *"$pattern"* ]]; then
echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
exit 2
fi
done
exit 0
Сделайте его исполняемым командой chmod +x .claude/hooks/protect-files.sh, затем зарегистрируйте:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
}
]
}
]
}
}
Тот же приём работает для shell-команд. Сопоставьте Bash, прочитайте .tool_input.command и выходите с 2, если там есть то, что вам не нужно никогда, например rm -rf /, git push --force или DROP TABLE. Помните, что проверку по строке легко обойти, поэтому считайте её ремнём безопасности, а не замком.
Пример 3: получить уведомление на рабочем столе
Долгие задачи останавливаются и ждут вас чаще, чем хотелось бы. Хук Notification сообщит об этом сразу. В macOS:
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
}
]
}
]
}
}
В Linux используйте вместо этого notify-send 'Claude Code' 'Claude Code needs your attention'. Задайте matcher permission_prompt, если вас интересуют только запросы разрешений, или добавьте хук Stop с той же командой, чтобы узнавать, когда Claude закончил.
Ещё полезные приёмы
- Вернуть контекст после сжатия. Хук
SessionStartс matchercompactможет сделатьechoкороткого напоминания о ваших правилах. Его stdout добавляется в новый контекст. - Аудит изменений конфигурации. Хук
ConfigChangeможет дописывать каждое изменение настроек в лог-файл. - Контроль качества на Stop. Хук
Stopможет запускать ваши тесты и завершаться с 2, передав сбои, чтобы Claude продолжал исправлять. Проверяйте полеstop_hook_activeво входных данных, чтобы не попасть в бесконечный цикл. Кроме того, Claude Code отключает хук Stop после нескольких блокировок подряд. - Автоодобрение одного безопасного запроса. Хук
PermissionRequestможет ответить на конкретный диалог с помощью{"behavior": "allow"}внутри объекта решения. Делайте matcher узким.
Замечания по безопасности перед добавлением хуков
Хуки выполняются как shell-команды с правами вашего пользователя, без вопросов. В этом и смысл, и риск.
- Читайте хуки, прежде чем доверять репозиторию.
.claude/settings.jsonпроекта может содержать хуки. Просматривайте их так же, как скриптpostinstall. - Заключайте переменные в кавычки. Входные данные хука приходят от модели, а модель читает файлы и веб-страницы, где может быть prompt injection. Используйте
"$VAR", никогда не применяйте eval ко входным данным и предпочитайтеjqсамодельному разбору. - Используйте абсолютные или относительные к проекту пути через
$CLAUDE_PROJECT_DIR, чтобы хук не зависел от текущей папки. - Держите хуки быстрыми. Медленный хук
PreToolUseзамедляет каждый вызов инструмента. Задайтеtimeout. - Хуки — не песочница. Хук deny блокирует вызовы даже при
--dangerously-skip-permissions, и это полезно, но настойчивый или запутавшийся агент может прийти к тому же результату другим путём. Сочетайте хуки с правилами deny и изоляцией, как описано в статьях безопасность ИИ-агентов для кода и безопасный пропуск разрешений. - Знайте выключатели.
"disableAllHooks": trueотключает хуки, а администраторы могут задатьallowManagedHooksOnlyв managed settings, чтобы заблокировать пользовательские и проектные хуки.
Если хук ведёт себя странно, запустите Claude Code с claude --debug или пишите лог в файл через --debug-file /tmp/claude.log, чтобы увидеть matcher, код выхода и вывод каждого хука.
Как AgentVera использует хуки
AgentVera — десктопное приложение, которое запускает Claude Code, Codex, Gemini CLI и другие кодовые CLI рядом друг с другом. Хуки — важная часть того, как оно работает с Claude Code.
- Ваши хуки остаются вашими. AgentVera передаёт собственные хуки каждому процессу Claude Code через флаг
--settings. Claude Code объединяет их с хуками из ваших файлов настроек, а вашsettings.jsonне редактируется. - Статус агента берётся из хуков. Статус, который каждый агент показывает в приложении, читается из собственных событий хуков CLI, а не угадывается по тексту терминала.
- Smart tools — это хуки. Функция smart tools добавляет четыре хука локальным агентам Claude Code: блокирует повторное чтение одного и того же файла, запускает только те тесты, которых касается правка, проверяет ошибки сразу после правки и делит результаты между агентами. Они включены по умолчанию, и их можно отключить в Settings → “Token saving”.
- Скрипт уведомлений не нужен. Уведомления и одобрения собирают всех агентов, ждущих одобрения, в одну очередь, отправляют уведомления на рабочий стол, пока приложение в фоне, и могут отправить сообщение на телефон через Telegram.
Qwen Code тоже получает хуки AgentVera, потому что его система хуков следует событиям и формату JSON Claude Code.
Итоги
Начните с одного форматтера PostToolUse и одной защиты PreToolUse, проверьте их через /hooks и --debug и добавляйте новые, только когда правило продолжают нарушать. Выходите с 2, чтобы заблокировать, выводите JSON, когда нужно больше контроля, и относитесь к каждому хуку как к коду, который работает с вашими правами.
Читайте также:
Чтобы попробовать AgentVera, начните с главной страницы.