раздел 06 · подстраница 1
События hooks
Hook - это shell-команда, которую Claude Code исполняет при определённом событии: до или после вызова инструмента, при остановке, при отправке промпта. Девять событий, под каждое можно повесить любое количество команд.
Зачем
Hooks - способ навязать Claude процессы, которые он сам не будет соблюдать стабильно: автоформат, авто-тесты, защита от чтения секретов, уведомления, авто-коммиты. В отличие от инструкций в CLAUDE.md, hook исполняется детерминированно - не "по настроению".
Полная таблица событий
| Событие | Когда срабатывает |
| ------------------- | -------------------------------------------------------------------------- |
| PreToolUse | До вызова любого инструмента. Можно блокировать вызов (exit 1). |
| PostToolUse | После вызова инструмента. Видит результат. |
| UserPromptSubmit | Когда пользователь отправляет промпт. До отправки в модель. |
| Stop | Когда Claude закончил отвечать и собирается отдать управление пользователю.|
| SubagentStop | Когда суб-агент (через Task tool) закончил работу. |
| Notification | Когда Claude хочет показать пользователю notification (например, ждёт ввод)|
| PreCompact | Перед автоматическим сжатием контекста. |
| SessionStart | При старте сессии (claude, claude --resume). |
| SessionEnd | При завершении сессии (Ctrl+C, exit). |
Переменные окружения внутри hook
Claude передаёт контекст события через env-переменные. Доступны не во всех событиях.
| Переменная | Где доступна | Что содержит |
| ---------------------- | --------------------------- | ------------------------------------------- |
| $CLAUDE_TOOL_NAME | PreToolUse, PostToolUse | Имя инструмента: Bash, Edit, Write |
| $CLAUDE_FILE_PATHS | PostToolUse (Edit/Write) | Пути изменённых файлов, через пробел |
| $CLAUDE_TOOL_INPUT | PreToolUse, PostToolUse | JSON входа инструмента |
| $CLAUDE_TOOL_RESULT | PostToolUse | JSON результата |
| $CLAUDE_USER_PROMPT | UserPromptSubmit | Текст промпта пользователя |
| $CLAUDE_SESSION_ID | везде | ID сессии |
| $CLAUDE_PROJECT_DIR | везде | Корень проекта (или ~) |
Что когда срабатывает - примеры
PreToolUse
До любого инструмента. Самое мощное: можно блокировать опасные действия.
# заблокировать чтение .env
[[ "$CLAUDE_TOOL_NAME" == "Read" && "$CLAUDE_FILE_PATHS" == *".env"* ]] && exit 1
exit 0
Если hook вернул exit 1 - инструмент не вызывается, Claude получает ошибку.
PostToolUse
После инструмента. Удобно для автоформата, авто-тестов, уведомлений.
# автоформат .py после Edit
[[ "$CLAUDE_TOOL_NAME" == "Edit" ]] || exit 0
for f in $CLAUDE_FILE_PATHS; do
[[ "$f" == *.py ]] && black "$f"
done
UserPromptSubmit
Перед отправкой промпта в модель. Можно дополнить промпт системным контекстом или заблокировать.
# логировать все промпты
echo "[$(date +%H:%M)] $CLAUDE_USER_PROMPT" >> ~/.claude/prompts.log
Stop
Когда Claude закончил отвечать. Типично - уведомление, авто-коммит.
# macOS уведомление
osascript -e 'display notification "Claude finished" with title "Claude Code"'
SubagentStop
Когда суб-агент завершился. Удобно собирать результат, обновлять статус, считать траты.
echo "[$(date)] subagent done" >> ~/.claude/agents.log
Notification
Когда Claude хочет вашего внимания (ждёт ответ на вопрос, требует апрув инструмента).
# звук + bounce иконки Dock на macOS
afplay /System/Library/Sounds/Ping.aiff
PreCompact
До автокомпакта. Можно сохранить полную историю в файл прежде, чем её сожмут.
cp ~/.claude/sessions/$CLAUDE_SESSION_ID.json ~/Documents/claude-archive/
SessionStart / SessionEnd
Старт - можно подгрузить контекст (например, дёрнуть git status и положить в системный промпт). End - сохранить summary.
# SessionStart: показать TODO из проекта
[[ -f TODO.md ]] && cat TODO.md
Контроль через exit-код
| Exit | Поведение | | ---- | ---------------------------------------------------------- | | 0 | Hook отработал, Claude продолжает. | | 1 | Ошибка / блок. Для PreToolUse - инструмент не вызывается. | | 2 | "Soft block" - Claude получит сообщение и попробует иначе. |
Антипаттерны
- Тяжёлые операции в PreToolUse - блокирует каждый вызов инструмента, тормозит работу.
- Hooks, которые могут зависнуть без таймаута - заблокируют весь Claude. Всегда
timeout 10s .... - exit 1 без сообщения - Claude не поймёт, что пошло не так. Пишите в stderr.
- Не использовать кавычки вокруг
$CLAUDE_FILE_PATHS- если в имени пробел, всё сломается.
Полезные ссылки
- Hooks reference - официальная справка
- Hooks examples - примеры Anthropic