Хуки — Автоматизация рабочего процесса — Практика
Прямая речь: “Всё на этой странице практики построено так, чтобы вы могли повторять за мной строка за строкой. Когда видите блок с командой или промптом, можете копировать его прямо в терминал или сессию Claude, если я явно не укажу, что это справочный материал. По ходу работы сравнивайте свой результат с моим на экране, чтобы ловить ошибки сразу, а не копить их.”
Продолжительность: ~25 минут Результат: Пять хуков – автоформатирование при редактировании, защита файлов, статус сессии, десктопное уведомление и запрос подтверждения. Предварительные требования: Пройдены Блоки 0-7, проект ai-coderrank открыт в Claude Code
Шаг 1: Автоформатирование Prettier после каждого редактирования (~5 мин)
Это самый полезный хук с немедленным эффектом. Каждый раз, когда Claude пишет или редактирует файл, Prettier запускается автоматически. Больше никаких “ой, забыл отформатировать”.
Сначала убедитесь, что Prettier установлен в проекте ai-coderrank:
cd ~/ai-coderrank
npx prettier --version
Если не установлен, попросите Claude:
Add prettier as a dev dependency and create a basic .prettierrc config for a Next.js TypeScript project.
Теперь создадим хук. Откройте .claude/settings.json в проекте ai-coderrank. Если там уже есть содержимое (из Блока 5 с разрешениями), вы будете добавлять к нему. Попросите Claude:
Add a PostToolUse hook to .claude/settings.json that runs Prettier on any file
after Claude writes or edits it. The hook should:
- Only fire on Write and Edit tool uses
- Read the file path from stdin JSON using jq
- Run prettier --write on the affected file
Результат должен выглядеть так:
{
"permissions": {
"allow": ["Read", "Glob", "Grep", "Write", "Edit", "Bash"]
},
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "FILE=$(cat | jq -r '.tool_input.file_path // empty'); [ -n \"$FILE\" ] && npx prettier --write \"$FILE\" 2>/dev/null || true"
}
]
}
]
}
}
Обратите внимание на несколько моментов:
"matcher": "Write|Edit"– хук срабатывает только при использовании Claude инструмента Write или Edit. Не на Read, не на Bash, не на Grep.cat | jq -r '.tool_input.file_path'– хуки получают контекст в виде JSON на stdin. Мы извлекаем путь к файлу с помощьюjq. Так все хуки Claude Code получают доступ к контексту инструмента.2>/dev/null || true– подавляет ошибки Prettier для файлов, которые он не может отформатировать (например,.mdили.yaml, если Prettier для них не настроен).|| trueгарантирует, что хук всегда завершается с кодом 0, чтобы случайно не заблокировать Claude.
Проверка
Запустите новую сессию Claude Code (чтобы подхватить новые настройки) и попросите:
Add a comment to the top of src/app/page.tsx that says "// Auto-formatted by Prettier hook"
Наблюдайте за происходящим. Claude редактирует файл, и затем Prettier немедленно его форматирует. Если включён подробный режим (Ctrl+O), вы увидите срабатывание хука в выводе.
Шаг 2: Блокировка редактирования защищённых файлов (~5 мин)
Некоторые файлы не должны редактироваться Claude (или кем-либо без тщательного обдумывания). package-lock.json, .env, lock-файлы – они генерируются автоматически или содержат секреты.
Попросите Claude:
Add a PreToolUse hook to .claude/settings.json that blocks Claude from editing
or writing to these files:
- .env (and any .env.* variants)
- package-lock.json
- yarn.lock
- pnpm-lock.yaml
The hook should exit with code 2 to block the operation and print a message
explaining why.
Claude добавит секцию PreToolUse в ваши настройки:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "FILE=$(cat | jq -r '.tool_input.file_path // empty'); case \"$FILE\" in *.env|*.env.*|*package-lock.json|*yarn.lock|*pnpm-lock.yaml) echo \"BLOCKED: $FILE is a protected file. Edit it manually.\"; exit 2;; esac; exit 0"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "FILE=$(cat | jq -r '.tool_input.file_path // empty'); [ -n \"$FILE\" ] && npx prettier --write \"$FILE\" 2>/dev/null || true"
}
]
}
]
}
}
Ключевой момент – exit 2. Он говорит Claude Code: “Эта операция запрещена. Не продолжай.” Claude увидит блокировку, прочитает сообщение и скажет вам, что не смог отредактировать файл.
Проверка
В сессии Claude:
Add a new variable MY_TEST=hello to the .env file
Claude попытается отредактировать .env, хук сработает, и вы увидите блокировку. Claude должен ответить что-то вроде “Мне не удалось отредактировать .env – это защищённый файл.”
Примечание: Это не запрещает Claude читать
.env(матчер –Write|Edit, а неRead). Если хотите заблокировать и чтение, добавьте отдельную запись PreToolUse с"matcher": "Read"и теми же проверками файлов.
Шаг 3: Хук статуса при начале сессии (~3 мин)
Было бы здорово, если бы каждая сессия Claude начиналась с быстрой проверки статуса проекта? Текущая ветка, незакоммиченные изменения, последний коммит – как панель мониторинга, которая появляется автоматически.
Попросите Claude:
Add a SessionStart hook to .claude/settings.json that runs a shell script
printing:
- Current git branch
- Number of uncommitted changes
- Last commit message and date
- Whether the K8s cluster is reachable (kubectl cluster-info, with a timeout)
Keep it concise — 5-6 lines of output max.
Хук:
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "echo '--- Project Status ---' && echo \"Branch: $(git branch --show-current)\" && echo \"Changes: $(git status --porcelain | wc -l | tr -d ' ') files modified\" && echo \"Last commit: $(git log -1 --format='%s (%cr)')\" && echo \"K8s: $(kubectl cluster-info --request-timeout=2s 2>/dev/null | head -1 || echo 'not reachable')\" && echo '---------------------'"
}
]
}
]
}
}
Обратите внимание: у SessionStart нет matcher. Он и не нужен – здесь нет инструмента, хук просто срабатывает при начале сессии.
Проверка
Выйдите из Claude Code и начните новую сессию:
claude
Вы должны увидеть вывод статуса перед тем, как промпт станет готов. Что-то вроде:
--- Project Status ---
Branch: main
Changes: 2 files modified
Last commit: Add dark theme toggle (3 hours ago)
K8s: Kubernetes control plane is running at https://<IP>:6443
---------------------
Шаг 4: Хук десктопных уведомлений (~5 мин)
Когда Claude работает над длительной задачей (реализует фичу, запускает тесты, деплоит), вы можете переключиться на другое окно. Было бы здорово получить уведомление, когда он закончит.
Попросите Claude:
Add a Stop event hook to .claude/settings.json that sends a macOS desktop
notification when Claude finishes a response. Use osascript to display a
notification with the title "Claude Code" and the message "Task completed".
Also provide a Linux alternative using notify-send.
Версия для macOS:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Task completed\" with title \"Claude Code\" sound name \"Glass\"'"
}
]
}
]
}
}
Версия для Linux (альтернатива):
{
"type": "command",
"command": "notify-send 'Claude Code' 'Task completed' --icon=terminal 2>/dev/null || true"
}
Проверка
Начните новую сессию и попросите Claude сделать что-то, что займёт несколько секунд:
Read every file in the k8s/ directory and give me a one-sentence summary of each.
Когда он закончит, вы должны получить уведомление macOS. Переключитесь на другое приложение, пока Claude работает, чтобы убедиться, что уведомление всплывает.
Идея для улучшения: Возможно, вы не хотите уведомление на каждый маленький ответ. Можно сделать хук умнее – например, уведомлять только если ответ занял более 10 секунд. Это требует более сложного скрипта, но Claude может его сгенерировать:
Modify the Stop notification hook to only fire if the Claude response took longer than 10 seconds. Use a SessionStart hook to save the start timestamp and a Stop hook to check the elapsed time.
Шаг 5: Включение подробного режима и наблюдение за хуками (~2 мин)
Теперь у вас настроены четыре хука. Давайте увидим их в действии в подробном режиме.
В сессии Claude Code нажмите Ctrl+O для включения подробного вывода. Появится [verbose mode enabled].
Теперь сделайте что-то, что вызовет срабатывание хуков:
Add a TODO comment to the top of src/app/layout.tsx
В подробном режиме вы увидите вывод вроде:
[hook] PreToolUse:Edit checking matcher "Write|Edit" → matched
[hook] Running: FILE=$(cat | jq -r ...) ...
[hook] Exit code: 0 (proceed)
[tool] Edit src/app/layout.tsx
[hook] PostToolUse:Edit checking matcher "Write|Edit" → matched
[hook] Running: npx prettier --write "src/app/layout.tsx"
[hook] Exit code: 0
Здесь видно:
- Хук PreToolUse сработал и проверил, защищён ли файл (нет, поэтому exit 0)
- Claude отредактировал файл
- Хук PostToolUse сработал и запустил Prettier
Нажмите Ctrl+O ещё раз, чтобы отключить подробный режим, когда закончите отладку.
Шаг 6: Создание хука подтверждения (~5 мин)
Для нашего последнего хука построим нечто, что спрашивает “вы уверены?” перед выполнением Claude потенциально разрушительных shell-команд. А именно команд с rm, git reset, git push --force или kubectl delete.
Попросите Claude:
Add a PreToolUse hook for the Bash tool that checks if the command contains
any of these patterns: "rm -rf", "git reset --hard", "git push --force",
"kubectl delete namespace", "DROP TABLE", "docker system prune".
If any pattern is found, the hook should:
1. Print the command that's about to run
2. Print "This looks like a destructive command."
3. Ask the user for confirmation (read from /dev/tty)
4. Exit 2 (block) if the user says no, exit 0 if they say yes
Add it as a separate PreToolUse entry with matcher "Bash".
Скрипт хука:
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "CMD=$(cat | jq -r '.tool_input.command // empty'); DANGEROUS_PATTERNS='rm -rf|git reset --hard|git push --force|git push -f|kubectl delete namespace|DROP TABLE|docker system prune'; if echo \"$CMD\" | grep -qE \"$DANGEROUS_PATTERNS\"; then echo \"\" && echo \"WARNING: Destructive command detected:\" && echo \" $CMD\" && echo \"\" && read -p 'Allow this command? (y/N): ' CONFIRM < /dev/tty; if [ \"$CONFIRM\" = 'y' ] || [ \"$CONFIRM\" = 'Y' ]; then exit 0; else echo 'Blocked by user.'; exit 2; fi; else exit 0; fi"
}
]
}
Проверка
Попросите Claude сделать что-то разрушительное:
Delete the k8s namespace for ai-coderrank using kubectl
Claude попытается выполнить kubectl delete namespace ai-coderrank. Хук перехватит это, покажет команду и запросит подтверждение. Введите n для блокировки или y для разрешения.
Полная конфигурация
После всех хуков ваш .claude/settings.json должен выглядеть примерно так:
{
"permissions": {
"allow": ["Read", "Glob", "Grep", "Write", "Edit", "Bash"]
},
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "echo '--- Project Status ---' && echo \"Branch: $(git branch --show-current)\" && echo \"Changes: $(git status --porcelain | wc -l | tr -d ' ') files modified\" && echo \"Last commit: $(git log -1 --format='%s (%cr)')\" && echo \"K8s: $(kubectl cluster-info --request-timeout=2s 2>/dev/null | head -1 || echo 'not reachable')\" && echo '---------------------'"
}
]
}
],
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "FILE=$(cat | jq -r '.tool_input.file_path // empty'); case \"$FILE\" in *.env|*.env.*|*package-lock.json|*yarn.lock|*pnpm-lock.yaml) echo \"BLOCKED: $FILE is a protected file. Edit it manually.\"; exit 2;; esac; exit 0"
}
]
},
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "CMD=$(cat | jq -r '.tool_input.command // empty'); DANGEROUS_PATTERNS='rm -rf|git reset --hard|git push --force|git push -f|kubectl delete namespace|DROP TABLE|docker system prune'; if echo \"$CMD\" | grep -qE \"$DANGEROUS_PATTERNS\"; then echo \"\" && echo \"WARNING: Destructive command detected:\" && echo \" $CMD\" && echo \"\" && read -p 'Allow this command? (y/N): ' CONFIRM < /dev/tty; if [ \"$CONFIRM\" = 'y' ] || [ \"$CONFIRM\" = 'Y' ]; then exit 0; else echo 'Blocked by user.'; exit 2; fi; else exit 0; fi"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "FILE=$(cat | jq -r '.tool_input.file_path // empty'); [ -n \"$FILE\" ] && npx prettier --write \"$FILE\" 2>/dev/null || true"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Task completed\" with title \"Claude Code\" sound name \"Glass\"'"
}
]
}
]
}
}
Это пять хуков в одном конфигурационном файле, покрывающие:
- Автоформатирование (PostToolUse)
-
Защита файлов (PreToolUse на Write Edit) - Подтверждение разрушительных команд (PreToolUse на Bash)
- Панель статуса сессии (SessionStart)
- Десктопные уведомления (Stop)
Контрольная точка
Ваши хуки теперь активны. Вот что и когда срабатывает:
| Когда | Что срабатывает | Что делает |
|---|---|---|
| Начало сессии | Хук SessionStart | Выводит ветку, изменения, последний коммит, статус кластера |
| Перед редактированием файла | PreToolUse (Write|Edit) | Проверяет, защищён ли файл; блокирует при необходимости |
| Перед выполнением команды | PreToolUse (Bash) | Проверяет разрушительные паттерны; запрашивает подтверждение |
| После редактирования файла | PostToolUse (Write|Edit) | Запускает Prettier на изменённом файле |
| После завершения ответа Claude | Хук Stop | Отправляет уведомление macOS |
Эти хуки всегда активны. Не нужно помнить о форматировании. Не нужно беспокоиться, что .env будет затёрт. Не нужно постоянно проверять, закончил ли Claude. Всё автоматизировано.
Бонусные задания
Задание 1: Хук логирования
Создайте хук PostToolUse, который добавляет запись в .claude/hook-log.txt каждый раз, когда Claude использует инструмент. Включите временную метку, имя инструмента и путь к файлу (если применимо). Это создаёт журнал аудита всего, что Claude делал в сессии.
Задание 2: Хук автолинтинга
Добавьте хук PostToolUse, который запускает ESLint (с --fix) после редактирования файлов, в дополнение к Prettier. Настройте цепочку: сначала Prettier, затем ESLint.
Задание 3: Хук защиты веток
Создайте хук PreToolUse для Bash, который блокирует команды git push, когда вы на ветке main. Заставьте Claude (и себя) использовать feature-ветки.
Далее: В Блоке 9 мы вырываемся за пределы локального терминала. MCP-серверы подключают Claude к GitHub, базам данных, Slack и десяткам других инструментов – превращая его из помощника по коду в полноценный движок рабочего процесса разработки.
Готовы проверить себя?
Пройти квиз →