1. Hooks — отдельный слой, а не «ещё один tool»
Когда внешний tool уже прошёл preflight, а его claims всё равно замыкаются на код, tests и review, появляется следующий вопрос: что внутри самого Claude Code повторяется так часто, что пора автоматизировать? Вот отсюда и растут hooks.
Когда вы впервые слышите про hooks, легко принять их за ещё одну интеграцию, но hook отвечает совсем на другой вопрос. Tool, MCP или plugin capability — это про «откуда взять данные или куда сходить». Hook — про «что автоматически сделать, когда внутри Claude Code произошло определённое событие». MCP — дверь наружу: issue tracker, мониторинг, документация, база данных, браузер. Hook — датчик и автоматика внутри дома. Дверь не решает, когда включить свет в коридоре, — решает датчик движения. Так и hook не нужен, чтобы «получить данные из Jira». Он нужен, чтобы после редактирования файла прогнать форматтер, перед записью в защищённый путь остановить действие или в начале сессии напомнить правила проекта.
Из-за этого hooks почти никогда не стоят в центре архитектуры. Они не заменяют task spec, human review и tests — убирают рутинные микро-действия, которые вы и так делаете снова и снова. Пытается «думать вместо вас» — тревожный сигнал. Помогает не забыть простое, повторяемое, проверяемое действие — его территория.
В Workflow Kit это особенно хорошо видно. Файл вроде .claude/hooks/format-on-edit.json не знает бизнес-логики Commerce OS — что такое заказ, возврат или MRR. Он автоматизирует одну привычку: изменил Claude код в нужной зоне — сразу прогони formatter. Скромно, полезно, без драматургии — лучший тип автоматизации.
2. Событие → условие → действие
Термин event-driven automation звучит строго, а суть простая: вы не запускаете команду вручную каждый раз, а система сама реагирует на событие. Не «я вспомнил и запустил formatter», а «произошло событие — formatter вызвался сам». Не «шаг 1, потом шаг 2», а «случилось X — проверь Y и выполни Z».
Самая бытовая аналогия — датчик движения в коридоре. Движение — это event. Условие «только ночью» — matcher. Включить лампу — handler. Движения нет — лампа молчит. Движение днём — фильтр не пропустил, лампа молчит. Движение ночью — фильтр подошёл, лампа зажглась. Hook устроен ровно так, только вместо коридора у вас lifecycle инструментов, файлов и сессий.
flowchart TD
A[Внутри Claude Code произошло событие] --> B{Matcher подходит?}
B -- Нет --> C[Hook молчит]
B -- Да --> D[Запускается handler]
D --> E[Полезное действие: форматирование, блокировка, напоминание]
Из этой схемы следует важная вещь: hook не существует сам по себе. Пока событие не случилось, он спит — не «периодически умничает», а ждёт момента. Потому hooks и хороши для событийной механики вокруг workflow: перед инструментом, после редактирования, в начале или конце сессии. Для длинных рассуждений, анализа кодовой базы и сложных решений нужны другие механизмы.
И ещё одна полезная мысль. Hooks кажутся магией ровно до того момента, пока вы не проговорите фразу вслух: «Когда Claude изменил TypeScript-файл в src/, запусти форматтер». Всё, осталась инженерная формула.
Hook = событие + условие + действие.
3. Состав hook: event, matcher, handler
Сейчас самое важное — научиться читать hook как маленький контракт из трёх частей, а не «JSON, который иногда запускается». Слова английские, смысл земной: event — событие, matcher — фильтр, handler — обработчик. Удобнее всего в таблице:
| Часть | Главный вопрос | Что означает |
|---|---|---|
|
Когда? | В какой момент lifecycle Claude Code вообще стоит реагировать |
|
При каком условии? | Как сузить срабатывание до нужных путей, инструментов или ситуаций |
|
Что сделать? | Какую команду или скрипт реально выполнить |
Здесь полезно не путать hook с уже знакомыми сущностями. Skill вы вызываете как повторяемую процедуру — вручную или по trigger. Agent получает роль и отдельный контекст. Hook ничего не исследует и не планирует — срабатывает, когда совпал шаблон. Это его сила и его предел. Тянет засунуть в hook пол-оркестра сложных шагов — инструмент выбран не тот.
Ещё один важный момент: точные имена событий, синтаксис matcher и структура конфига могут немного меняться между версиями Claude Code. Держимся модели из трёх частей, а не «этот ключ называется только так». Актуальный синтаксис сверяете через /hooks и текущую справку.
4. Три группы event
Полный список событий конкретной версии смотрится в инструменте, а заучивать его наизусть — романтика уровня ручной правки XML в пятницу вечером. Но одну карту в голове держать стоит: почти все полезные hooks укладываются в три группы — before tool use, after tool use / file changes и session lifecycle.
| Группа событий | Что означает по-человечески | Типичные сценарии |
|---|---|---|
| Before tool use | Сработать до опасного или важного действия | заблокировать запись в защищённый путь, попросить подтверждение, не дать выполнить рискованную команду |
| After tool use / file changes | Сработать после действия или изменения файла | форматирование, короткий отчёт, запуск локальной проверки, напоминание |
| Session lifecycle | Сработать на этапах жизни сессии | показать баннер в начале, сохранить состояние, отправить уведомление, загрузить полезный контекст |
Группа before tool use — это ваш «вахтёр на входе». Она особенно полезна там, где важно не забыть про границы. Например, вы не хотите, чтобы Claude автоматически редактировал .env или что-то под payments/. Тогда before-hook может увидеть попытку записи и вовремя её остановить. Это не про удобство, а про защитный контур.
Группа after tool use — наоборот, про реакцию после действия. Если Claude уже изменил файл, здесь уместны форматирование, запуск лёгкой проверки или понятное короткое сообщение в лог. Именно сюда обычно попадает базовый format-on-edit hook. Он никого не останавливает и не спорит с вами о смысле жизни. Он просто делает маленькую рутинную вещь сразу после правки.
Группа session lifecycle часто недооценивается, а зря. Иногда полезнее не блокировать и не форматировать, а просто в начале сессии напомнить правила проекта. Например: «Проверьте git status», «Не трогайте payments/ без отдельного плана», «Используйте только approved commands». Это мелочь, но именно из таких мелочей потом складывается командная дисциплина.
Заметьте: все эти группы описывают внутреннюю жизнь Claude Code, а не внешний мир. Hook не про то, что «в Jira появился новый тикет». Hook про то, что «внутри моей текущей работы наступил момент, на который стоит автоматически отреагировать».
5. matcher: точность вместо навязчивости
Если event отвечает за момент, то matcher отвечает за точность. И именно здесь чаще всего начинаются настоящие педагогические приключения. Новички любят написать что-нибудь широкое вроде «на все файлы» или «на все команды», а потом удивляться, что автоматизация срабатывает чаще, чем уведомления от банковского приложения. Проблема не в самом hook, а в слишком широком matcher.
Matcher — это фильтр. Он отвечает на вопрос: в каких именно обстоятельствах после события нужно запускать обработчик. Фильтр может смотреть на путь к файлу, тип инструмента, шаблон команды, иногда — на дополнительные признаки контекста. Но важнее не список возможностей, а принцип: matcher должен быть узким настолько, насколько это разумно.
Посмотрите на разницу между двумя мыслями. Первая: «После любого изменения любого файла запускай formatter». Вторая: «После изменения файлов в src/, если это ts или tsx, запускай formatter». Вторая мысль скучнее. А скучные мысли в автоматизации, как правило, безопаснее.
Для первого чтения нам важна сама форма hook, а не финальная конфигурация для проекта. Поэтому ниже — схематический пример matcher для форматирования:
{
"event": "afterFileEdit",
"matcher": { "paths": ["src/**/*.ts", "src/**/*.tsx"] },
"handler": { "command": "prettier --write {{file}}" }
}
Точные пути и команда зависят от структуры repo и того, какой formatter принят в проекте, но логика та же. Hook не трогает конфиги, markdown, shell-скрипты и чужие директории. Он реагирует только на ту зону, ради которой вообще был задуман.
Теперь другой сценарий — защита чувствительных путей. Здесь matcher уже не про расширение файла, а про рискованную область проекта:
{
"event": "beforeToolUse",
"matcher": { "tool": "Write", "paths": ["**/payments/**", "**/.env*"] },
"handler": { "command": "scripts/block-protected-write.sh" }
}
Такой фильтр уже работает как охранник на нужной двери. Он не мешает редактировать обычный код, но не даёт бездумно лезть в опасные зоны. И это очень хорошая привычка для Workflow Kit: не пытаться поставить одну гигантскую ловушку на всё подряд, а ставить точечные рамки там, где blast radius действительно велик.
Если сомневаетесь, делайте matcher уже, а не шире. Шумный hook быстро приучает команду его игнорировать. А hook, которому перестали доверять, фактически уже мёртв — просто ещё лежит в репозитории.
6. handler: граница между конфигом и действием
После event и matcher остаётся самая земная часть — handler. Он отвечает на вопрос: что конкретно выполнить, когда всё совпало. И это лучший момент, чтобы окончательно развеять магию. Handler — не тайный интеллект, не скрытый subagent и не маленький оркестр. Чаще всего это просто команда или скрипт.
Иногда handler совсем небольшой: вызвать formatter на файле. Иногда это shell-скрипт, который печатает напоминание. Иногда — guard-скрипт, который проверяет путь и завершает выполнение с нужным статусом. Смысл один: hook нашёл нужную ситуацию, а handler сделал одну понятную вещь.
Например, handler на уровне сессии может быть буквально таким:
#!/usr/bin/env bash
echo "Проверьте git status и scope задачи" # напоминание
echo "Не трогайте payments/ без отдельного плана" # правило проекта
Да, это уже полноценный handler. Никакого волшебства. Просто маленький скрипт, который помогает не забыть контекст в начале работы.
Полезно держать в голове две практические границы. Во-первых, handler должен быть предсказуемым. Если после одного edit у вас запускается гигантская цепочка команд на двадцать секунд, вы довольно быстро возненавидите собственную автоматизацию. Во-вторых, handler должен быть узко полезным. Если вы вдруг понимаете, что он уже похож на мини-платформу с пятью ветками поведения, логами, эвристиками и внутренней философией, возможно, это уже не hook-задача, а отдельный script/tool/skill.
Да, handler обычно получает часть контекста события: путь к файлу, имя инструмента или другой payload. Но глубоко в технические детали передачи этих значений мы сегодня не уходим. На уровне ментальной модели достаточно понимать: hook не только знает, что произошло, но и может передать обработчику данные, чтобы тот сработал не «вообще», а на конкретном файле или действии.
7. Первый hook в Workflow Kit
Теперь давайте соберём всё вместе на артефакте, который действительно живёт в нашей проектной линии. В Claude Workflow Kit for Team hooks — это не абстрактная теория, а обычные файлы репозитория внутри .claude/hooks/. Команда поддерживает их так же, как CLAUDE.md, skills и agents. То есть hook — это процессный артефакт, а не кусочек «магии внутри Commerce OS».
Ниже — базовые, схематические версии таких hooks. Они нужны не затем, чтобы копировать их как есть, а затем, чтобы научиться читать hook как процессный артефакт команды: событие, фильтр, действие. Как только вы переходите к реальному репозиторию, сначала проверяются matcher, побочные эффекты и путь отключения.
Первый базовый пример — наш уже знакомый format-on-edit:
// .claude/hooks/format-on-edit.json
{
"event": "afterFileEdit",
"matcher": { "paths": ["src/**/*.ts", "src/**/*.tsx"] },
"handler": { "command": "prettier --write {{file}}" }
}
Если читать этот файл как обычное предложение, получается очень наглядно: после редактирования файла, если путь попадает в src/**/*.ts(x), запусти formatter. Никакого «искусственного интеллекта внутри hook». Просто хорошая инженерная дисциплина, упакованная в маленький конфиг.
Второй пример — защита чувствительных зон. В Workflow Kit вполне естественно держать отдельный hook, который не даёт случайно писать в области, где ошибки стоят дорого:
// .claude/hooks/block-protected-paths.json
{
"event": "beforeToolUse",
"matcher": { "tool": "Write", "paths": ["**/payments/**", "**/.env*"] },
"handler": { "command": "scripts/block-protected-write.sh" }
}
Здесь хорошо видно различие ролей. Event — «перед использованием инструмента записи». Matcher — «только если запись идёт в payments/ или .env*». Handler — «вызови защитный скрипт». Такой hook не делает проект умнее. Он делает проект спокойнее.
И, наконец, более мягкий сценарий — баннер в начале сессии. Он вообще ничего не блокирует, зато помогает быстро заземлиться в правила текущего репозитория:
// .claude/hooks/session-banner.json
{
"event": "sessionStart",
"handler": { "command": "scripts/session-banner.sh" }
}
#!/usr/bin/env bash
echo "Проверьте git status и scope задачи" # напоминание
echo "Если задача нетривиальная — начните с плана" # ещё одно правило
Заметьте, как аккуратно складывается общая картина. Один hook помогает с чистотой кода. Второй — с безопасностью. Третий — с дисциплиной начала работы. Все три устроены одинаково. И если вы научились читать один, вы уже умеете читать остальные.
Поэтому самый полезный навык этой лекции звучит очень просто: когда вы открываете hook-конфиг, не смотрите на него как на «ещё один JSON». Читайте его как договорённость команды:
Когда произошло это, и только если совпало вот это условие, нужно автоматически сделать вот это действие.
Прочитали конфиг по этой формуле — и сразу видите три части контракта: event отвечает «когда», matcher — «при каком условии», handler — «что сделать». Собранные вместе, они и дают ваш первый осмысленный hook в Workflow Kit. А вот какие задачи стоит доверять hook, а какие он только испортит, и как раскатывать его по шагам — тема следующей лекции.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ