Почему это важно именно вам
Десять дней назад вы не знали, что такое hooks. Сейчас вы знаете пять типов, двадцать событий, правила матчеров и exit-коды. Это хорошо, но ещё не работает. Знание, которое лежит по отдельным урокам, не превращается само по себе в систему.
Сегодня — сборка. Не новая теория, а архитектура из того, что уже изучено. Конкретный вопрос: как выглядит минимальный production-стек hooks для человека, который работает с документами, отчётами и письмами каждый день?
Если вы настроите то, что будет в «Задании на сегодня», — Claude перестанет быть инструментом, который нужно постоянно контролировать. Он начнёт сам отчитываться о своих действиях, предупреждать вас о завершении задач и работать с защитой от разрушительных операций. Это не фича — это рабочий процесс, который держится сам.
Что это такое
Прежде чем собирать — короткое резюме того, что изучили в фазе 5. Не полный курс, а карта: где что лежит.
Типы hooks (День 41) — пять видов, каждый для своего уровня перехвата:
command— выполняет shell-скрипт; самый универсальныйhttp— отправляет POST на URL; для интеграций с внешними сервисамиmcp_tool— вызывает инструмент на подключённом MCP-сервере как реакцию на событие; пригодится в Фазе 6prompt— одноходовая оценка моделью, возвращает вердикт{"ok": true/false}agent— тот же вердикт, но проверяющий субагент может читать файлы и запускать проверки (экспериментально)
В ежедневной практике директора нужны первые два. mcp_tool и agent — для более продвинутых сценариев.
События (День 42) — двадцать точек перехвата, но для работы хватает пяти:
| Событие | Когда срабатывает |
|---|---|
SessionStart |
Claude начинает сессию |
UserPromptSubmit |
Пользователь отправил запрос, до обработки |
PreToolUse |
Claude собирается вызвать инструмент |
PostToolUse |
Инструмент вызван и завершил работу |
Stop |
Claude завершил ответ и ждёт следующего ввода |
Остальные — SubagentStop, PreCompact, различные варианты Notification — нужны в редких специализированных сценариях.
Матчеры (День 43) — как указать, на какой именно инструмент реагировать:
"matcher": "Edit" // точная строка
"matcher": "Edit|Write" // pipe-separated для нескольких
"matcher": "^(Bash|Edit)$" // regexp
Поле if позволяет добавить условие по содержимому события — например, смотреть на конкретный аргумент команды.
Exit codes и JSON (День 44) — как hook управляет поведением Claude:
0— всё в порядке, Claude продолжает2— заблокировать операцию; Claude не выполнит инструмент- Любой другой — ошибка, но Claude всё равно продолжит (если не
2)
Если hook возвращает JSON в stdout, Claude читает поля:
- "continue": false — остановить сессию
- {"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "allow"}} — явное решение по разрешению; значения allow, deny, ask, defer
- {"hookSpecificOutput": {"hookEventName": "UserPromptSubmit", "additionalContext": "текст"}} — добавить текст в контекст (для UserPromptSubmit). Поля prompt_injection не существует
Не путайте блокировку операции и остановку сессии
Одну операцию отклоняют двумя способами: код выхода 2 или JSON с permissionDecision: "deny" на PreToolUse. А "continue": false завершает всю сессию целиком. Не путайте эти два механизма — последствия разные.
Как работает на практике
Абстрактные механизмы понятны. Теперь — конкретный сценарий: «Director's hook stack». Минимальный набор из четырёх hooks, которые реально полезны в ежедневной работе.
Hook 1: Лог изменённых файлов
Событие: PostToolUse
Matcher: Edit|Write
Что делает: записывает в лог-файл дату, имя инструмента и путь к изменённому файлу
Зачем: вы отдали Claude задачу и ушли на встречу. Вернулись через час. Что именно было изменено? Без лога — нужно вручную сравнивать git diff или вспоминать. С логом — один взгляд на ~/.claude/audit.log.
#!/bin/bash
# ~/.claude/hooks/log-edits.sh
exec 2>> ~/.claude/hooks-errors.log
INPUT=$(cat)
TOOL_NAME=$(jq -r '.tool_name' <<<"$INPUT")
FILE_PATH=$(jq -r '.tool_input.file_path // "неизвестен"' <<<"$INPUT")
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
echo "${TIMESTAMP} | ${TOOL_NAME} | ${FILE_PATH}" >> ~/.claude/audit.log
exit 0
Hook 2: Уведомление в Telegram при завершении
Событие: Stop
Что делает: отправляет POST на Telegram Bot API с текстом «Claude завершил задачу» и временем
Зачем: Claude работает с большим файлом — вы занимаетесь чем-то другим. Когда он закончит — телефон вибрирует. Не нужно переключаться каждые три минуты чтобы проверить статус.
#!/bin/bash
# ~/.claude/hooks/notify-stop.sh
exec 2>> ~/.claude/hooks-errors.log
BOT_TOKEN="${TELEGRAM_BOT_TOKEN}"
CHAT_ID="${TELEGRAM_CHAT_ID}"
TIMESTAMP=$(date '+%H:%M:%S')
MESSAGE="✓ Claude завершил задачу в ${TIMESTAMP}"
curl -s -X POST \
"https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d "chat_id=${CHAT_ID}&text=${MESSAGE}" \
> /dev/null
exit 0
Не хардкодьте токены в скриптах
TELEGRAM_BOT_TOKEN и TELEGRAM_CHAT_ID берутся из переменных окружения, которые заданы в ~/.zshenv. Если положить токен прямо в скрипт — это файл на диске, который синхронизируется в облако. Переменные окружения в ~/.zshenv безопаснее.
Hook 3: Автодобавление даты к каждому запросу
Событие: UserPromptSubmit
Что делает: возвращает JSON с additionalContext внутри hookSpecificOutput — текст попадает в контекст запроса (в самом чате он не отображается)
Зачем: Claude не знает текущую дату без явного указания. Если вы пишете «подготовь отчёт за прошлую неделю» — Claude не знает, какая сейчас неделя. Этот hook решает задачу один раз и навсегда.
#!/bin/bash
# ~/.claude/hooks/inject-date.sh
exec 2>> ~/.claude/hooks-errors.log
DATE=$(date '+%Y-%m-%d, %A')
WEEKNUM=$(date '+%V')
python3 -c "
import json
print(json.dumps({
'hookSpecificOutput': {
'hookEventName': 'UserPromptSubmit',
'additionalContext': f'[Контекст: сегодня {\"$DATE\"}, неделя №{\"$WEEKNUM\"}, часовой пояс UTC+3]'
}
}))
"
exit 0
python3 для JSON — не перестраховка
Если дата содержит символы, которые ломают JSON (этого не будет, но пусть будет принцип): конкатенация строк bash ломается на любом спецсимволе. python3 -c "json.dumps(...)" — единственный надёжный способ формировать JSON программно. Привыкайте к этому паттерну.
Hook 4: Блокировка опасных команд Bash
Событие: PreToolUse
Matcher: Bash
Что делает: смотрит на команду, которую Claude собирается выполнить; если там есть rm -rf или похожее — возвращает exit 2
Зачем: Claude иногда предлагает «почистить временные файлы» или «удалить старую папку». Большинство раз это безопасно. Но один раз из ста — не то дерево. Hook позволяет перехватить именно опасные варианты, не блокируя весь Bash.
#!/bin/bash
# ~/.claude/hooks/guard-bash.sh
exec 2>> ~/.claude/hooks-errors.log
INPUT=$(cat)
COMMAND=$(jq -r '.tool_input.command // ""' <<<"$INPUT")
# Опасные паттерны
DANGEROUS_PATTERNS=(
"rm -rf /"
"rm -rf ~"
"rm -rf \$HOME"
"chmod -R 777"
"dd if="
"> /etc/"
)
for PATTERN in "${DANGEROUS_PATTERNS[@]}"; do
if echo "${COMMAND}" | grep -qF "${PATTERN}"; then
echo "BLOCKED: опасная команда обнаружена: ${PATTERN}" >&2
echo "BLOCKED: ${COMMAND}" >> ~/.claude/audit.log
exit 2
fi
done
exit 0
Этот hook — не замена осторожности
Список паттернов неполный — невозможно перечислить все опасные варианты. Hook ловит очевидные случаи. Для критических папок используйте PreToolUse с более строгой логикой или просто не работайте в autonomy режиме без присмотра.
Полный settings.json
Все четыре hooks в одном файле. Это кладётся в ~/.claude/settings.json — глобально, для всех проектов.
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/inject-date.sh"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/guard-bash.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/log-edits.sh"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/notify-stop.sh"
}
]
}
]
}
}
После того как файл создан — сделайте все четыре скрипта исполняемыми:
chmod +x ~/.claude/hooks/*.sh
И создайте директорию для логов, если её нет:
mkdir -p ~/.claude/hooks
touch ~/.claude/audit.log ~/.claude/hooks-errors.log
Частые ошибки
Скрипт молча падает. Claude продолжает работу — exit code отличный от 2 не останавливает его. Вы думаете, что лог пишется. На самом деле скрипт упал на второй строке. Без exec 2>> ~/.claude/hooks-errors.log в начале каждого скрипта вы об этом никогда не узнаете. Добавьте эту строку первой — до любой другой логики.
Дублирование hooks в проектном и глобальном settings. Если log-edits.sh прописан и в ~/.claude/settings.json, и в .claude/settings.json внутри проекта — он сработает дважды. Каждая строка в логе появится два раза. Правило простое: глобальные hooks (аудит, уведомления, дата) — только в ~/.claude/settings.json. Проектные (специфические блокировки, проектный контекст) — только в .claude/settings.json проекта.
JSON сломан из-за спецсимволов. Если в подставляемый текст попадают кавычки, обратными слешами или переносами строк — конкатенация bash сформирует невалидный JSON. Claude не поймёт его и проигнорирует. Всегда используйте python3 -c "json.dumps(...)" для формирования JSON в скриптах — это единственный надёжный способ.
hook уведомления срабатывает слишком часто. Stop — это завершение каждого ответа, не завершение сессии. Если Claude пишет пять ответов в диалоге — придёт пять уведомлений. Для коротких интерактивных сессий это раздражает. Решение: добавьте в скрипт проверку на длительность сессии или используйте SessionEnd вместо Stop — оно срабатывает только когда сессия закрыта полностью.
Блокирующий hook замедляет работу. Каждый PreToolUse hook запускает отдельный процесс. Если у вас три матчера на Bash и каждый скрипт делает что-то медленное (сетевой запрос, тяжёлый grep) — Claude будет ощутимо тормозить. Держите guard-скрипты лёгкими: только grep по строке, exit, ничего лишнего.
Когда нужно / когда нет
Это важнее, чем знать синтаксис. Hook — это инфраструктура: её нужно создать, поддерживать, отлаживать когда что-то идёт не так. Плохо написанный hook хуже, чем отсутствие hook.
Используйте hooks когда:
- Нужна автоматическая реакция на конкретное событие без участия пользователя
- Нужна интеграция с внешним сервисом (Telegram, webhook, n8n)
- Нужна блокировка конкретной операции по чёткому правилу
- Нужен аудит-лог — история действий, которую нельзя выключить
Достаточно CLAUDE.md когда:
- Нужно изменить стиль или поведение Claude («всегда отвечай по-русски», «форматируй таблицы в Markdown», «не сокращай числа»)
- Нужно дать постоянный контекст о проекте, команде, терминологии
- Нужно задать роль или тон
Достаточно skill или агента когда:
- Нужно переиспользовать конкретный рабочий процесс с командами
- Нужна многошаговая логика с условиями
- Процесс запускается явно, не автоматически
Ключевой принцип разграничения
Hooks — это инфраструктурный слой: что происходит вокруг Claude, до и после него. CLAUDE.md — поведенческий слой: как Claude думает и отвечает внутри сессии. Skills и агенты — процессный слой: конкретные рабочие процессы. Смешивать их — источник путаницы и сложно отлаживаемых систем. Если вы ловите себя на мысли «напишу hook, который скажет Claude делать X» — это, скорее всего, задача для CLAUDE.md.
Не нужно ничего когда:
- Задача разовая — настройка hook занимает больше времени, чем сама задача
- Нет чёткого правила — «иногда блокируй, иногда нет» не работает в коде
- Вы не готовы поддерживать скрипт — broken hook молча не работает; лучше никакого hook, чем сломанный
Связь с другими уроками
День 41 — первое знакомство с hooks: что это, зачем, пять типов. Сегодняшний урок предполагает, что вы его прошли.
День 42 — полный список событий; именно оттуда взяты UserPromptSubmit, PreToolUse, PostToolUse, Stop. Если не помните, чем Stop отличается от SessionEnd — вернитесь.
День 43 — матчеры; синтаксис "matcher": "Edit|Write" и поле if разобраны там.
День 44 — exit codes; принципиальное различие между exit 0, exit 2 и остальными. Без этого guard-hook в Hook 4 непонятен.
Дни 45-46 — command и http hooks; скрипты выше построены на этих принципах.
День 47 — контекст через хуки на UserPromptSubmit; Hook 3 из сегодняшнего урока — прямое применение того материала.
Дни 48-49 — практика аудита и уведомлений; сегодня объединяем обе практики в единую конфигурацию.
День 8 («Режимы разрешений») — autonomy-режим без hooks это повышенный риск; hooks и permission-mode работают в паре. Если включён автономный режим — PreToolUse guard становится обязательным, не опциональным.
Задание на сегодня
Создайте три файла и проверьте, что всё работает.
Шаг 1. Создайте директорию и заготовьте скрипты:
mkdir -p ~/.claude/hooks
touch ~/.claude/audit.log ~/.claude/hooks-errors.log
Шаг 2. Создайте ~/.claude/hooks/inject-date.sh и ~/.claude/hooks/log-edits.sh — код выше в разделе «Как работает на практике». Сделайте их исполняемыми:
chmod +x ~/.claude/hooks/inject-date.sh
chmod +x ~/.claude/hooks/log-edits.sh
Шаг 3. Обновите ~/.claude/settings.json — добавьте блок hooks из раздела «Полный settings.json». Если файл не существует — создайте его с нуля.
Шаг 4. Запустите короткую тестовую сессию: попросите Claude создать или отредактировать любой тестовый файл.
Критерий выполнено:
- cat ~/.claude/audit.log — показывает хотя бы одну строку с операцией Edit или Write
- cat ~/.claude/hooks-errors.log — пустой или не существует (ошибок нет)
- Спросите Claude «какое сегодня число» — он отвечает верно, хотя вы этого не писали (в самом диалоге блок с датой не виден: он уходит в контекст системным напоминанием)
Уведомление в Telegram (Hook 2) и guard-bash (Hook 4) — опциональны на этом шаге; настройте их если есть Telegram-бот и токен в ~/.zshenv.
Резюме
Фаза 5 — десять дней, от «что такое hooks» до рабочей production-конфигурации. Вот что осталось:
- Пять типов hooks:
command,http,mcp_tool,prompt,agent. В ежедневной практике нужны первые два. - Пять ключевых событий:
SessionStart,UserPromptSubmit,PreToolUse,PostToolUse,Stop. Полный список сегодня — больше тридцати событий; это справочник, а не рабочий набор. - Матчеры: точная строка,
pipe|separated, regexp, полеif. Начинайте с pipe-separated — этого достаточно для 90% задач. - Exit codes:
0— продолжить,2— заблокировать, остальное — ошибка без блокировки. - Director's hook stack: четыре hook для реального рабочего процесса — лог файлов, уведомление в Telegram, дата в промте, guard на rm.
- Главное правило распределения: hooks — инфраструктура вокруг Claude; поведение Claude — через CLAUDE.md; рабочие процессы — через skills и агентов.
- Главная практическая проблема: тихие ошибки.
exec 2>> ~/.claude/hooks-errors.log— первая строка каждого скрипта.
Следующая фаза — MCP. Если hooks это «что происходит вокруг Claude», то MCP это «к чему Claude имеет доступ». День 51 — старт.