раздел 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 - если в имени пробел, всё сломается.

Полезные ссылки