раздел 06 · подстраница 3
5 готовых hooks
Боевые hooks, которые работают у меня прямо сейчас. Копируйте в ~/.claude/settings.json (или проектный .claude/settings.json).
Зачем
Эти пять закрывают типовые потребности: автоформат, уведомления, защита секретов, авто-тесты, авто-коммиты. Их хватает, чтобы Claude перестал ломать стиль кода и забывать про CI.
1. Авто-формат после Edit/Write
Black для .py, prettier для .ts/.tsx/.js/.json.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "for f in $CLAUDE_FILE_PATHS; do case \"$f\" in *.py) command -v black >/dev/null && black -q \"$f\" ;; *.ts|*.tsx|*.js|*.jsx|*.json|*.md) command -v prettier >/dev/null && prettier --write --log-level error \"$f\" ;; esac; done; exit 0"
}
]
}
]
}
}
Тонкости:
command -v ... >/dev/null- не падать, если форматтера нет.exit 0в конце - hook никогда не должен блокировать сохранение.- Поддержите все расширения, иначе Claude будет править стиль обратно после форматтера.
2. macOS-уведомление после Stop
Звук + всплывашка, чтобы заметить, когда Claude закончил длинную задачу.
{
"hooks": {
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "afplay /System/Library/Sounds/Ping.aiff & osascript -e 'display notification \"Claude finished\" with title \"Claude Code\" sound name \"Ping\"' ; exit 0"
}
]
}
],
"Notification": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "afplay /System/Library/Sounds/Tink.aiff ; exit 0"
}
]
}
]
}
}
Для Linux замените osascript на notify-send "Claude" "finished".
3. Блок чтения .env через PreToolUse
Жёсткая защита: Claude никогда не прочитает файлы с секретами, даже если попросите.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Read|Bash",
"hooks": [
{
"type": "command",
"command": "case \"$CLAUDE_FILE_PATHS$CLAUDE_TOOL_INPUT\" in *\".env\"*|*\"credentials\"*|*\"id_rsa\"*|*\".pem\"*) echo 'BLOCKED: secret file' >&2; exit 1 ;; esac; exit 0"
}
]
}
]
}
}
exit 1 блокирует вызов. Claude получит ошибку и попытается обойти - попросите его не настаивать и читать .env.example.
4. Авто-pytest при изменениях в backend/
После любой правки файлов в backend/ - прогон тестов соответствующего модуля.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/auto-pytest.sh"
}
]
}
]
}
}
.claude/hooks/auto-pytest.sh:
#!/usr/bin/env bash
set -e
# фильтруем только backend/*.py
files=""
for f in $CLAUDE_FILE_PATHS; do
case "$f" in
backend/*.py) files="$files $f" ;;
esac
done
[ -z "$files" ] && exit 0
# запускаем pytest только для изменённых модулей
cd backend
timeout 60s pytest -x --tb=short -q $files 2>&1 | tail -30 || {
echo "TESTS FAILED" >&2
exit 2
}
exit 0
exit 2 - soft block: Claude увидит сообщение и пойдёт чинить тесты.
5. Авто-коммит после Stop
В feature-ветке Claude закончил - сразу git add -A && git commit с авто-сгенерированным сообщением. Используется в долгих параллельных сессиях, чтобы не терять прогресс.
{
"hooks": {
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/auto-commit.sh"
}
]
}
]
}
}
.claude/hooks/auto-commit.sh:
#!/usr/bin/env bash
set -e
# только не на main/master
branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
case "$branch" in
main|master|"") exit 0 ;;
esac
# есть ли что коммитить
[ -z "$(git status --porcelain)" ] && exit 0
# короткий summary через первые 3 изменённых файла
files=$(git diff --name-only --cached HEAD 2>/dev/null | head -3 | tr '\n' ',' | sed 's/,$//')
[ -z "$files" ] && files=$(git status --porcelain | awk '{print $2}' | head -3 | tr '\n' ',' | sed 's/,$//')
git add -A
git commit -m "wip: auto-commit ($files)
Co-authored-by: Claude Code <noreply@anthropic.com>" --no-verify || true
exit 0
Как поставить все пять
Один файл ~/.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Read|Bash",
"hooks": [{ "type": "command", "command": "case \"$CLAUDE_FILE_PATHS$CLAUDE_TOOL_INPUT\" in *\".env\"*|*\"credentials\"*) echo 'BLOCKED' >&2; exit 1 ;; esac; exit 0" }]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{ "type": "command", "command": "for f in $CLAUDE_FILE_PATHS; do case \"$f\" in *.py) black -q \"$f\" 2>/dev/null ;; *.ts|*.tsx|*.js|*.json|*.md) prettier --write --log-level error \"$f\" 2>/dev/null ;; esac; done; exit 0" },
{ "type": "command", "command": ".claude/hooks/auto-pytest.sh" }
]
}
],
"Stop": [
{
"matcher": "*",
"hooks": [
{ "type": "command", "command": "osascript -e 'display notification \"Claude finished\" with title \"Claude Code\"' ; exit 0" },
{ "type": "command", "command": ".claude/hooks/auto-commit.sh" }
]
}
]
}
}
И сделать скрипты исполняемыми:
chmod +x .claude/hooks/*.sh
Антипаттерны
- Запускать
npm test(вместоpytest -xпо конкретным файлам) на каждый Edit - сессия превратится в очередь ожиданий. - Авто-коммит на main без условия - ломается история.
- Уведомление на каждый Stop в чате с десятком ответов - спам, добавьте rate-limit.
- Не использовать
timeout- hook может зависнуть и заморозить Claude.