Почему это важно именно вам
Каждый раз, когда вы начинаете диалог с Claude по рабочей задаче, вы мысленно готовите преамбулу. «Сегодня вторник, у нас совет директоров в пятницу, поэтому нужно...» или «Сейчас конец месяца, закрываем отчётный период, поэтому цифры нужны за май...». Этот контекст вы каждый раз добавляете вручную — или забываете добавить, и тогда получаете ответ без учёта ситуации.
Или представьте: вы ведёте переписку с несколькими отделами и хотите, чтобы Claude всегда знал, что писать нужно в корпоративном стиле — без сленга, с обращением на «вы», с подписью. Каждый раз объяснять это заново — раздражает. Вынести в CLAUDE.md — помогает, но не всегда: иногда нужно добавлять что-то динамическое, зависящее от текущего момента: дня недели, времени суток, статуса задачи.
Prompt hooks решают именно эту задачу. Вместо того чтобы каждый раз вручную дописывать контекст, вы один раз описываете правило: «перед каждым моим запросом — добавь вот эту информацию». Claude получает расширенный промт автоматически. Вы этого не видите, не думаете об этом — оно просто работает. Это как шаблон письма в почтовом клиенте: вы пишете только суть, а подпись, тема и копии подставляются сами.
Что это такое
В жизненном цикле Claude Code есть несколько ключевых событий. Одно из них — UserPromptSubmit: момент, когда вы нажали Enter и ваш запрос отправился к Claude, но Claude ещё не начал отвечать. Это идеальная точка для вмешательства: запрос уже сформирован, но его ещё можно дополнить.
Добавить контекст в этой точке умеет хук типа command: он печатает JSON с полем additionalContext, и этот текст Claude видит вместе с вашим запросом. Схема простая: ваш текст плюс additionalContext от хука — и это уходит модели. Тип prompt устроен иначе: он не выполняет команду, а одним обращением к модели выносит вердикт {"ok": true/false}. Схема простая: ваш текст + текст от hook = финальный промт для Claude.
Хук на `UserPromptSubmit` — это не подсказка Claude, а добавка к вашему запросу
Разница принципиальная. Инструкция в CLAUDE.md говорит Claude «веди себя так всегда». Хук типа command на UserPromptSubmit говорит «к этому конкретному запросу добавь вот это прямо сейчас». Одно статично, другое динамично и может меняться каждую секунду.
Есть и родственный тип — agent. Как и prompt, он возвращает вердикт {"ok": ...}, но проверяющий субагент может по дороге читать файлы и запускать проверки. Помечен как экспериментальный. Он не добавляет текст, а именно проверяет: отдельный Claude-процесс, который выполняет какую-то проверку или действие параллельно с основным. Например, можно настроить agent-hook на событие Stop, который запускает отдельную сессию для проверки корректности финального результата. Это мощный инструмент, но более дорогой — каждый запуск субагента тратит токены. Об этом подробнее — в уроке про субагентов (День 21), а сегодня сосредоточимся на prompt.
Аналогия из бизнеса: представьте секретаря, который каждое ваше письмо перед отправкой дополняет шаблонной преамбулой — реквизитами, датой, ссылкой на предыдущую переписку. Вы пишете только суть, он оборачивает в стандартную форму. Prompt hook — это такой секретарь для ваших запросов к Claude.
Важный нюанс: prompt hooks работают прозрачно для вас. Вы не видите в интерфейсе, что именно добавилось к вашему запросу — вы видите только свой исходный текст. Но Claude получает уже расширенную версию. Если хотите проверить, что добавляется, попросите Claude показать полный текст полученного промта — он честно его воспроизведёт.
Как работает на практике
Hooks настраиваются в файле .claude/settings.json — в разделе hooks. Давайте разберём конкретный пример: hook, который автоматически добавляет текущую дату и день недели к каждому вашему запросу.
Шаг 1. Откройте файл настроек.
Файл .claude/settings.json находится в корне вашего рабочего проекта. Если его нет — создайте. Если есть раздел hooks — добавьте в него, если нет — создайте раздел.
Шаг 2. Опишите hook в конфигурации.
{
"hooks": {
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "printf '{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Сегодня %s\"}}' \"$(date '+%A, %d %B %Y, %H:%M')\""
}
]
}
]
}
}
Что здесь происходит:
UserPromptSubmit— событие: вы отправили запрос.- У события
UserPromptSubmitmatcher не поддерживается: поле молча игнорируется, и хук срабатывает на каждый ваш запрос. Если нужно реагировать не всегда — проверяйте текст внутри скрипта, читая полеpromptиз JSON на стандартном входе. type: "command"— обычный командный хук. На событииUserPromptSubmitон может добавить текст в контекст запроса: для этого печатает JSON с полемadditionalContext. Типpromptустроен иначе — это одноходовое обращение к модели, которое возвращает вердикт{"ok": true/false}, и поляcommandу него нет вовсе.command— команда, которую запустит система. Здесьprintfпечатает JSON с текущей датой; всё, что попало вadditionalContext, Claude увидит как часть контекста запроса (в самом чате этот текст не отображается).
Шаг 3. Проверьте результат.
После сохранения настроек начните новую сессию Claude Code и задайте любой вопрос. В начале сессии вы можете попросить Claude: «Покажи мне полный текст запроса, который ты получил». Вы увидите, что ваш исходный вопрос дополнен строкой с датой.
У `UserPromptSubmit` матчера нет
Поле matcher на этом событии молча игнорируется — хук срабатывает на каждый запрос. Чтобы реагировать выборочно, читайте поле prompt из JSON на стандартном входе. Это удобно: один hook добавляет контекст для деловых писем, другой — для аналитики, третий — для задач с дедлайнами.
Шаг 4. Более полезный пример — hook для рабочего контекста.
Вместо инлайн-команды echo можно запускать скрипт. Создайте файл ~/.claude/hooks/work_context.sh:
#!/bin/bash
DAY=$(date '+%A')
DATE=$(date '+%d.%m.%Y')
HOUR=$(date '+%H')
# Определяем часть дня
if [ "$HOUR" -lt 12 ]; then
PART="утро"
elif [ "$HOUR" -lt 18 ]; then
PART="рабочий день"
else
PART="вечер"
fi
echo "Контекст: $DATE, $DAY, $PART. Москва, UTC+3."
Сделайте скрипт исполняемым: chmod +x ~/.claude/hooks/work_context.sh
Обновите settings.json:
{
"hooks": {
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/work_context.sh"
}
]
}
]
}
}
Теперь каждый ваш запрос автоматически получает временной контекст. Claude будет знать, что сейчас вторник вечером — и не будет предлагать созвониться «сегодня в 3 часа дня». Не будет писать «С добрым утром» в ответе на вечернее письмо. Не будет рекомендовать «успеть до конца дня» в 23:45.
Для директора, работающего в разное время суток — рано утром до детей, поздно вечером после — это особенно ценно. Claude перестаёт быть собеседником, который не знает, который сейчас час.
Шаг 5. Несколько hooks на одно событие.
Вы можете добавить несколько hooks в массив для одного события. Они выполнятся последовательно, и весь их вывод объединится в одну добавку к запросу:
{
"hooks": {
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/work_context.sh"
},
{
"type": "command",
"command": "printf '{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Отвечай кратко, без вступлений.\"}}'"
}
]
}
]
}
}
Первый hook добавляет временной контекст, второй — инструкцию по стилю. В итоге Claude получает оба.
Шаг 6. Hook на событие Stop — проверка выполнения.
Есть ещё одно полезное применение: hook на событие Stop. Оно срабатывает, когда Claude заканчивает отвечать. Hook типа prompt на Stop позволяет автоматически добавить в конец задачи проверочный вопрос.
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "prompt",
"prompt": "Оцени по данным события, выполнена ли задача полностью: $ARGUMENTS. Ответь JSON: {\"ok\": true} если можно завершать, или {\"ok\": false, \"reason\": \"что осталось\"}."
}
]
}
]
}
}
Это работает как встроенный контролёр: Claude не просто остановится, а сначала ответит на вопрос «ты точно закончил?».
Hook типа prompt на Stop может создать бесконечный цикл
Если хук на Stop возвращает {"ok": false, "reason": …}, Claude получает reason как следующую инструкцию и продолжает работу — а по её окончании Stop срабатывает снова. Claude Code сам обрывает петлю после восьми блокировок подряд. Чтобы избежать петли, убедитесь, что hook на Stop возвращает текст только при определённых условиях, а не всегда. Матчера у Stop нет: проверяйте в промте поле stop_hook_active из входного JSON и возвращайте {"ok": true}, если цикл уже идёт.
Частые ошибки
Ошибка 1: Hook добавляет слишком много текста.
Если ваш скрипт возвращает несколько абзацев контекста, Claude тратит токены на его обработку и иногда начинает «отвечать» на добавленный контекст, а не на ваш вопрос. Правило: hook типа prompt должен добавлять не больше 1-2 строк. Это маркер, а не эссе.
Как исправить: сокращайте вывод hook до минимума. Дату — в одну строку, флаг стиля — в одно слово. Детальный контекст лучше держать в CLAUDE.md.
Ошибка 2: Скрипт hook падает с ошибкой — Claude ничего не получает.
Если команда завершается с ненулевым кодом выхода, контекст не добавится. Вы думаете, что контекст добавлен, — а его нет. В транскрипте при этом появится строка hook error и первая строка stderr — так что упавший хук не молчит; полный вывод смотрите в отладочном логе (/debug или claude --debug).
Как исправить: тестируйте команду вручную в терминале перед добавлением в settings.json. Запустите ~/.claude/hooks/work_context.sh и убедитесь, что он выводит текст и завершается с кодом 0. Добавьте в скрипт обработку ошибок: если что-то пошло не так — всё равно выводить пустую строку, а не падать.
Ошибка 3: Путаница между prompt и agent.
Оба типа возвращают вердикт {"ok": …}, а не текст. Разница в другом: prompt — одно обращение к модели по данным события, agent — субагент, который может по дороге читать файлы и запускать проверки. А «добавить дату» — это вообще command-хук с additionalContext. Если вы хотите «запустить проверку в параллельном процессе» — agent. Использование agent там, где нужен prompt, приводит к запуску лишних Claude-сессий и трате бюджета.
Как исправить: простое правило — если результат нужен как текст в запросе, выбирайте prompt. Если нужно что-то выполнить как отдельную задачу — agent.
Ошибка 4: Hook настроен глобально, а нужен только для одного проекта.
Если добавить hook в ~/.claude/settings.json (глобальные настройки), он будет работать во всех проектах. Рабочий контекст для проекта по недвижимости не нужен в личных задачах — и наоборот.
Как исправить: для проектно-специфичных hooks используйте .claude/settings.json в папке конкретного проекта. Для универсальных (дата, временная зона) — можно и в глобальных. Это стандартная иерархия настроек Claude Code: глобальные → проектные, проектные имеют приоритет там, где определены.
Когда нужно / когда нет
Используйте prompt hooks, если:
- Вы регулярно начинаете запросы с одного и того же контекста: «сегодня среда», «пишем на русском», «формат — короткий», «стиль — официальный». Всё, что вы копируете из предыдущего диалога в новый — кандидат для hook.
- Контекст динамический и меняется сам по себе: дата, день недели, время суток, статус флага в файле. Статичный контекст лучше держать в CLAUDE.md, динамический — в hook.
- Вы хотите добавить автоматическую самопроверку на событии Stop: Claude должен перед завершением убедиться, что задача выполнена полностью.
- Вы работаете в разных режимах — например, «режим редактирования документов» и «режим аналитики» — и хотите, чтобы Claude автоматически переключался в нужный стиль в зависимости от содержимого запроса (через
matcher).
Не используйте prompt hooks, если:
- Контекст статичный и не меняется. Роль, стиль, ограничения — это в CLAUDE.md (День 11). Hook здесь избыточен.
- Хотите добавить длинную инструкцию к каждому запросу. Длинный hook убивает фокус Claude и тратит токены. Всё, что больше двух строк, — в CLAUDE.md или в системный промт.
- Нужно что-то выполнить, а не добавить текст. Если нужно «логировать каждый запрос в файл» — это другой тип hook, не
prompt. Этоcommandhook (День 45) или hook сtype: "command". - Вы не уверены, что скрипт надёжен. Упавший хук помечается в транскрипте строкой
hook error, но контекст при этом не добавится — а заметить это в потоке работы легко не успеть.
Нулевой порог применения
Самый простой prompt hook — это однострочный echo. Не нужен Python, не нужен bash-профи. Если вы умеете написать echo "Сегодня $(date)" в терминале — вы уже умеете писать prompt hooks.
Связь с другими уроками
День 41 — Что такое hooks и как они работают. Базовая архитектура событий, типы хуков, структура settings.json. Если prompt hooks кажутся магией — вернитесь туда: там объясняется, как система знает, когда вызывать ваш скрипт.
День 11 — CLAUDE.md: инструкции для Claude. Статичный контекст — туда. Динамический — в prompt hook. Понимание разницы между этими двумя механизмами экономит время и токены. CLAUDE.md и hooks дополняют друг друга: один задаёт постоянное поведение, второй добавляет ситуативный контекст.
День 42 — 20+ событий hooks. Если prompt hook работает на уровне «что Claude получил», то PreToolUse/PostToolUse работают на уровне «что Claude делает с инструментами». Когда освоите prompt hooks — следующий уровень именно там: перехватывать вызовы инструментов, добавлять проверки перед чтением файлов, логировать каждое действие.
Задание на сегодня
Откройте .claude/settings.json в вашем рабочем проекте (или создайте его, если нет) и добавьте один command-хук на событие UserPromptSubmit.
Hook должен добавлять к каждому запросу текущую дату в формате «ДД.ММ.ГГГГ» через echo "$(date '+%d.%m.%Y')".
Критерий «выполнено»: запустите новую сессию Claude Code, напишите любой вопрос, затем спросите Claude: «Что именно ты получил как запрос? Покажи полный текст». Если в ответе есть сегодняшняя дата — задание выполнено.
На это уйдёт не больше пяти минут. Если настройки уже есть — три минуты.
Резюме
- Хук типа
commandнаUserPromptSubmitдобавляет вывод скрипта к вашему запросу — черезadditionalContextили простым текстом на stdout. Типprompt— другое: одноходовая оценка моделью с вердиктом{"ok": …}. - Это инструмент для динамического контекста: дата, день недели, время суток, текущий режим работы — всё, что меняется и что вы устали добавлять вручную.
- Hook на событие
Stopпозволяет добавить автоматическую самопроверку: Claude перед завершением ответит на вопрос «задача выполнена полностью?». - Частые ошибки: слишком длинный вывод hook, падение скрипта без видимых ошибок, путаница между типами
promptиagent. - Правило применения: динамический контекст — в hook, статичный — в CLAUDE.md. Если можно написать одной строкой
echo— смело используйте.