JavaRush /Курси /Claude code /Hooks: event,

Hooks: event, matcher і handler

Claude code
Рівень 14 , Лекція 2
Відкрита

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 улаштований рівно так само, тільки замість коридору у вас життєвий цикл інструментів, файлів і сесій.

flowchart TD
    A[Усередині Claude Code сталася подія] --> B{Matcher підходить?}
    B -- Ні --> C[Hook мовчить]
    B -- Так --> D[Запускається handler]
    D --> E[Корисна дія: форматування, блокування, нагадування]

Із цієї схеми випливає важлива річ: hook не існує сам по собі. Поки подія не сталася, він спить — не «періодично розумує», а чекає моменту. Саме тому hooks і добрі для подієвої механіки навколо workflow: перед інструментом, після редагування, на початку або в кінці сесії. Для довгих міркувань, аналізу кодової бази й складних рішень потрібні інші механізми.

І ще одна корисна думка. Hooks здаються магією рівно до того моменту, поки ви не промовите фразу вголос: «Коли Claude змінив TypeScript-файл у src/, запусти formatter». Усе, лишилася інженерна формула.

Hook = подія + умова + дія.

3. Склад hook: event, matcher, handler

Зараз найважливіше — навчитися читати hook як маленький контракт із трьох частин, а не «JSON, який іноді запускається». Слова англійські, сенс земний: event — подія, matcher — фільтр, handler — обробник. Найзручніше це видно в таблиці:

Частина Головне питання Що означає
event
Коли? У який момент lifecycle Claude Code взагалі варто реагувати
matcher
За якої умови? Як звузити спрацьовування до потрібних шляхів, інструментів чи ситуацій
handler
Що зробити? Яку команду або скрипт реально виконати

Тут корисно не плутати 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, а які він лише зіпсує, і як розгортати його по кроках — тема наступної лекції.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ