Хуки Claude Code: як автоматизувати дії агента і не підірватися на власних налаштуваннях

22 хв. читання

Хуки Claude Code — це користувацькі shell-команди (а також HTTP-ендпоінти і промпти), які агент запускає автоматично в конкретних точках свого життєвого циклу: перед викликом інструмента, після запису файлу, на старті сесії, коли зупиняється. Головна відмінність від промпта чи навички: хук спрацьовує гарантовано, а не «якщо модель вирішить». Це найпотужніший важіль налаштування Claude Code — і водночас найнебезпечніший, бо командний хук виконується з повними правами вашого користувача в системі.

Хуки — швидкозмінна частина Claude Code: офіційний перелік подій уже виріс приблизно до 30, тому будь-який гайд на цю тему має термін придатності, і дату звірки варто тримати в голові.

Нижче — робоча ментальна модель механізму, розбір settings.json з прикладами JSON, повна логіка exit-кодів, три перевірені за документацією рецепти і чесний розбір ризиків із датованими інцидентами, а не загальними словами «будьте обережні з shell».

Що таке хуки і навіщо вони потрібні

Хук — це зв’язка «подія → умова → дія». Коли в Claude Code настає подія (наприклад, агент збирається виконати bash-команду), система перевіряє ваші налаштування, і якщо умова збіглася, запускає задану команду. Офіційна документація формулює суть через одне слово — детермінізм: хуки дають передбачуваний контроль над поведінкою агента, гарантуючи, що потрібна дія станеться завжди, а не залежатиме від того, чи «згадає» модель про інструкцію.

Це ключова межа між хуком і сусідніми механізмами розширення. Навичка (skill) — інструкція, якій модель може дотриматись, а може й ні. MCP-інструмент — функція, яку модель викличе, якщо визнає за потрібне. Хук же не питає модель: умова виконана — команда запущена. Таку саму логіку детермінованого контролю незалежно описують і російськомовні розбори теми, і офіційний гайд Anthropic.

Практичний висновок: хуки потрібні там, де «попросити модель» недостатньо надійно. Автоформатування коду, заборона правити секрети, запуск тестів, аудит-лог кожної команди, сповіщення на телефон — усе це має відбуватися щоразу, а не через раз.

МеханізмХто вирішує, запускатиКоли обирати
ХукУмова в settings.json (детерміновано)Дія зобов’язана статися завжди: формат, гейт, лог
Навичка (skill)Модель — за контекстомПотрібна гнучка процедура, де доречне судження моделі
MCP-інструментМодель — викликає за потребиДоступ до зовнішніх даних і API як до інструмента
СубагентМодель — делегує завданняВажка ізольована робота в окремому контексті
Sandboxing / permission-правилаРушій Claude CodeОбмежити файли й мережу, дозволити/заборонити інструмент

Ще один недооцінений плюс: командні та HTTP-хуки майже не витрачають токени моделі. Форматувальник, лінтер чи перевірка запускаються як звичайний процес ОС, а не як міркування LLM — спільнота прямо цінує це як «автоматизацію за нуль токенів». Навичка чи субагент на те саме завдання з’їли б частину контекстного вікна; хук — ні.

Хуки з’явилися в Claude Code не одразу: за офіційним CHANGELOG репозиторію anthropics/claude-code їх випустили у версії v1.0.38. Це той випадок, коли точну версію релізу корисно знати — майже жоден сторонній гайд її не називає, а вона пояснює, чому перелік подій відтоді так розрісся.

Як оголосити хук у settings.json

Хуки описуються декларативно у файлі settings.json. Конфігурація має три рівні вкладеності, і розуміння цієї структури знімає більшу частину запитань:

  1. Подія — на що реагуємо (PreToolUse, PostToolUse, Stop тощо).
  2. Matcher-група — фільтр, коли саме спрацьовувати (наприклад, «лише для інструмента Bash»).
  3. Обробники (handlers) — одна чи кілька команд, які запускаються при збігу.

Мінімальний приклад: перед кожним викликом Bash проганяти власний скрипт-перевірку.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/Users/me/.claude/hooks/check-bash.sh"
          }
        ]
      }
    ]
  }
}

Поле matcher трактується за простими правилами. Порожнє, "*" або відсутнє — збігається завжди. Рядок лише з літер, цифр, _, -, пробілів, ком і | — точний збіг або список точних значень через | (наприклад, "Edit|Write"). Будь-який інший символ перетворює значення на JavaScript-регулярний вираз без якорів — зручно, але легко вистрелити собі в ногу, якщо не пам’ятати про це.

Обробник буває п’яти типів: command (shell-команда), http (POST на ендпоінт), mcp_tool, prompt і agent. У переважній більшості практичних випадків ви пишете саме command.

Де лежить файл — визначає область дії хука. Це важливо з погляду безпеки: хук із чужого репозиторію діє так само, як ваш власний.

РозташуванняОбластьКомітиться в репозиторій
~/.claude/settings.jsonУсі ваші проєктиНі, локально на машині
.claude/settings.jsonОдин проєктТак, потрапляє в git
.claude/settings.local.jsonОдин проєктНі, у .gitignore
Managed policy settingsУся організаціяЗадає адміністратор
hooks/hooks.json плагінаПроєкти з плагіномЧерез маркетплейс плагінів
Frontmatter навички/субагентаПри активації навичкиРазом із навичкою

Перевірити, які хуки взагалі зареєстровані, допомагає вбудована команда /hooks — вона відкриває read-only список усіх подій із числом хуків, matcher’ами, типом і файлом-джерелом. Змінювати хуки просто з меню не можна: лише правкою JSON або через прохання до агента.

Події життєвого циклу: 30 точок, з яких ходових — десяток

Ось той самий розрив, який важливо зафіксувати явно. Більшість туторіалів 2026 року перелічують 9–13 «подій життєвого циклу»: один із топових англомовних гайдів прямо озаглавлений «All 12 Lifecycle Events». Актуальний офіційний reference на липень 2026 року містить їх близько 30 — від SessionStart і Setup до Elicitation і SessionEnd. Це не помилка авторів гайдів, а протухання контенту: перелік розширюється швидше, ніж матеріали встигають оновлюватися. Повну таблицю тримає першоджерело; тут — ходові події, які закривають майже всі реальні сценарії.

ПодіяКоли спрацьовуєМоже заблокувати дію
SessionStartСтарт сесії Claude Code
UserPromptSubmitКористувач надіслав запитТак (може відхилити/доповнити промпт)
PreToolUseПеред викликом будь-якого інструментаТак — єдине з повним контролем рішення
PostToolUseОдразу після виконання інструментаНі — інструмент уже відпрацював
NotificationАгент чекає на відповідь/дозвіл
StopАгент завершує хідТак (може повернути його в роботу)
SubagentStopЗавершився субагентТак
PreCompactПеред стисненням контексту
SessionEndКінець сесії

Події зручно ділити за кадансом — як часто вони спрацьовують. Офіційний reference виділяє три групи: раз на сесію (SessionStart, SessionEnd), раз на хід (UserPromptSubmit, Stop, StopFailure) і на кожен виклик інструмента всередині агентного циклу (PreToolUse, PostToolUse). Це одразу підказує, де хук смикатиметься десятки разів за завдання (і має бути швидким), а де — одноразово.

Практичний кістяк: PreToolUse — для заборон і перевірок до дії; PostToolUse — для реакції після (формат, тести); Notification — щоб не пропустити, що агент вас чекає; Stop — щоб не дати завершити, поки не виконано умову; SessionStart — щоб підвантажити контекст. Решта подій існує під тонкі сценарії, і лізти в них варто, лише коли ходових не вистачає.

Exit-коди і як хук блокує дію

Хук спілкується з Claude Code двома каналами: кодом повернення процесу і JSON на stdout. Почнемо з кодів — тут у конкурентів трапляється пряма помилка.

  • Exit 0 — успіх. Claude Code читає stdout; якщо там валідний JSON, він його розбирає та враховує.
  • Exit 2 — блокувальна помилка. Для PreToolUse це скасовує виклик інструмента; stdout ігнорується, а текст зі stderr передається моделі як причина відмови.
  • Будь-який інший код — неблокувальна помилка для більшості подій (виняток — WorktreeCreate, де будь-який ненульовий код скасовує операцію).

Тут важлива поправка до поширеного джерела: популярний туторіал DataCamp приписує коду exit 3 значення «Deferred execution». В офіційному reference такого коду немає — є лише 0, 2 і «інше». Слово «defer» в документації стосується поля permissionDecision, а не коду повернення. Якщо ви читали про «exit 3» — це неточний переказ, не закладайте його у свої скрипти.

Точний контроль над дозволами дає не код, а JSON. У події PreToolUse є унікальна можливість: повернути в hookSpecificOutput.permissionDecision одне з чотирьох рішень — allow (пропустити без запиту), deny (заборонити виклик), ask (запитати користувача) або defer (акуратно вийти, не втручаючись). Якщо кілька PreToolUse-хуків повернули різні рішення, пріоритет такий: deny > defer > ask > allow. Приклад відповіді, яка жорстко блокує команду:

{
  "hookSpecificOutput": {
    "permissionDecision": "deny",
    "permissionDecisionReason": "Правка .env заборонена політикою проєкту"
  }
}

На вхід кожен командний хук отримує JSON через stdin. Спільні для всіх подій поля: session_id, prompt_id, transcript_path (шлях до JSON-транскрипту розмови), cwd, permission_mode і hook_event_name; для подій-інструментів додаються tool_name і tool_input. HTTP-хуки отримують той самий JSON тілом POST-запиту. Звідси просте правило: скрипт-хук читає stdin, парсить потрібні поля і вирішує, що робити.

Окремо про PostToolUse: він не може відкотити вже виконану дію. Exit 2 покаже моделі ваш stderr як зворотний зв’язок, але інструмент до цього моменту вже відпрацював. Тому заборони вішають на PreToolUse (до дії), а PostToolUse використовують для того, що доречно робити після — форматування, запуску перевірок, логування.

Три робочі рецепти: формат, гейт на секрети, сповіщення

Нижче — три готові сценарії, зібрані за офіційним guide. Кожен — це command-хук; шлях до скрипта підставте свій.

1. Автоформатування після Edit/Write. Класичний PostToolUse: щойно агент записав файл, проганяємо форматувальник. Економить рев’ю і тримає стиль рівним — і все це за нуль токенів моделі.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }
        ]
      }
    ]
  }
}

2. Блокування правки .env та інших захищених файлів. Це PreToolUse з рішенням deny. Скрипт читає tool_input зі stdin, дивиться шлях і, якщо він веде до секрету або в .git, повертає exit 2 з причиною в stderr (або JSON із permissionDecision: deny). Агент не зможе торкнутися файлу, навіть якщо «дуже захоче» — на відміну від текстової інструкції в промпті, яку модель може проігнорувати.

3. Десктоп-сповіщення, коли агент чекає на вас. Подія Notification спрацьовує, коли Claude Code зупинився в очікуванні відповіді або дозволу. Хук на macOS може смикнути системний банер:

{
  "hooks": {
    "Notification": [
      {
        "matcher": "*",
        "hooks": [
          { "type": "command", "command": "osascript -e 'display notification \"Claude чекає на відповідь\" with title \"Claude Code\"'" }
        ]
      }
    ]
  }
}

Для тривалих завдань є важлива деталь. За замовчуванням хук блокує роботу агента, поки не завершиться. Якщо перевірка важка (повний прогін тестів, деплой), задайте в command-хука поле "async": true — він піде у фон, а агент продовжить роботу; таймаут за замовчуванням — 10 хвилин. Додаткове поле "asyncRewake": true «розбудить» агента, якщо фоновий хук завершиться з exit 2. Цю зв’язку майже не описують у гайдах, хоча саме вона дозволяє вбудувати тривалі перевірки без просідання швидкості роботи.

Скільки це коштує? Не в токенах (їх хуки майже не витрачають), а в праці на налаштування і в ризику зламати потік. Корисно оцінювати хуки за цією рамкою до впровадження:

ХукЩо даєЩо зламає при помилці у скрипті
Автоформат (PostToolUse)Єдиний стиль без ручного рев’юЗіпсований файл, якщо форматувальник падає
Гейт на секрети (PreToolUse deny)Заборона правити .env/.gitХибні блокування, агент «застрягає»
Сповіщення (Notification)Не пропустити очікування агентаСпам банерів при частих паузах
Async-перевірка (тести/деплой)Тривалі гейти без блокуванняНепомічений провал, якщо забути asyncRewake

Де ламається: шари захисту та їхні слабкі місця

Тут найчастіша прогалина конкурентів: хуки подають як єдиний абсолютний бар’єр. Насправді захист багатошаровий, і в кожного шару своя межа.

Хук-deny сильніший за режим обходу прав. PreToolUse-хуки спрацьовують до перевірки режиму дозволів. Хук, що повернув permissionDecision: deny, блокує інструмент навіть у режимі bypassPermissions і з прапорцем --dangerously-skip-permissions. Зворотне неправильне: allow від хука не скасовує deny-правила з налаштувань. Тобто для жорсткої заборони PreToolUse-хук надійніший, ніж правила дозволів самі по собі.

Чому це не абстракція — показав суміжний баг. Adversa AI 2 квітня 2026 року описала, що легасі regex-парсер Claude Code переставав застосовувати deny-правила дозволів, якщо bash-команда містила понад 50 підкоманд (через &&, || або ;), і падав у загальний дозвільний запит. Виправлений парсер існував у кодовій базі, але на дату звіту не був у публічній збірці. Практичний висновок рівно той самий: для критичних заборон спирайтеся на PreToolUse-хук, а не лише на allow/deny в settings.json.

Але й хук — не бетон. Усередині обробника є best-effort фільтр if, яким зручно обмежувати спрацьовування за вмістом bash-команди. Офіційна документація чесно попереджає: цей фільтр fail-open — якщо команду не вдалося розпарсити, хук запуститься в будь-якому разі. Багато практиків інтуїтивно вважають if жорсткою стіною; для справжнього hard-deny документація прямо рекомендує permission-систему, а не фільтр у хуку.

Stop-хук може залипнути. Хук на події Stop вміє повертати агента в роботу, поки не виконано умову — але це ж створює ризик нескінченного циклу. Захист вбудований: Claude Code примусово завершує хід після 8 поспіль блокувань Stop-хуком без прогресу. Якщо вашій перевірці легітимно потрібно більше ітерацій, ліміт піднімається змінною оточення CLAUDE_CODE_STOP_HOOK_BLOCK_CAP.

Це той клас завдань, де детермінований хук чесніший за агентну автоматизацію: одна річ — навичка, яка веде базу знань і сама вирішує, що і коли записати, і зовсім інша — жорсткий гейт, який зобов’язаний спрацювати при кожному коміті. Якщо вам потрібен не гарантований тригер, а гнучкий автономний помічник — це вже інший клас інструмента, і хук тут не заміна.

Безпека і ризики: хук — це довільний код з повними правами

Головна теза розділу пряма: командний хук виконується з повними правами вашого системного користувача. Офіційний дисклеймер не залишає двозначності — хук може прочитати, змінити чи видалити будь-який файл, до якого у вас є доступ, виконати довільний bash, сходити в мережу, дістатися до змінних оточення з ключами. Незалежні security-розбори формулюють те саме. Звідси правило: будь-який хук треба прочитати і протестувати до того, як він потрапить у конфіг.

Небезпеку посилює те, що settings.json психологічно сприймається як «метадані», а не як виконуваний код. Це робить хуки тихим вектором supply-chain атак — і це вже не гіпотеза.

CVE-2025-59536 і CVE-2026-21852. Дослідники Check Point (Авів Доненфельд, Одед Вануну) показали, що хук SessionStart із .claude/settings.json чужого репозиторію виконувався без явного підтвердження користувача — на відміну від звичайних bash-команд. Через це вдавалося дійти до віддаленого виконання коду та ексфільтрації API-ключа (підміна ANTHROPIC_BASE_URL). Перший баг отримав CVSS 8.7 (High), другий — 5.3. CVE-2026-21852 опублікований Anthropic 21 січня 2026 року, публічне розкриття Check Point — 25 лютого 2026 року; на дату звіту обидві вразливості вже були повністю пропатчені.

Кампанія Shai-Hulud. Той самий SessionStart-хук використали як механізм персистентності supply-chain малварі в npm-пакетах. Техніка «впровадити SessionStart-хук через .claude/settings.json із пакета» вперше з’явилася у Wave 3 кампанії (пакети SAP CAP-JS/MBT, квітень 2026 року, близько 4 пакетів) і повернулася у Wave 5: 19 травня 2026 року через скомпрометований акаунт мейнтейнера приблизно за годину опублікували, за даними Socket через Snyk, 637 версій у 323 пакетах (@antv/* і ще понад 310); у звіті BleepingComputer і в GitHub-issue фігурує цифра 639 версій — розбіжність на пару версій пояснюється різним моментом знімка. Хук переживає перезапуск і запускає код атакувальника при наступному відкритті Claude Code — ще до будь-якого введення користувача. Хронологія Wave 3 → Wave 5 наочно показує, що це еволюція однієї техніки, а не розрізнені інциденти.

Претензія спільноти. GitHub-issue #49778 (створений 17 квітня, закритий як not_planned 26 червня 2026 року) формулює архітектурну проблему: у активних хуків немає постійного індикатора в інтерфейсі, і немає підтвердження, коли хук реєструє сторонній процес — npm postinstall, плагін, навичку. Показово, що Shai-Hulud Wave 5 (19 травня) на практиці реалізувала рівно той ризик, який issue описав теоретично.

Що з цим робити:

  • Не довіряйте .claude/settings.json із чужих і клонованих репозиторіїв. Після клонування запустіть /hooks і подивіться, що зареєстровано.
  • Для команд і організацій є жорсткі важелі: allowManagedHooksOnly блокує користувацькі, проєктні та плагінні хуки, а disableAllHooks: true вимикає хуки зовсім. Вимкнути managed-хуки може лише disableAllHooks, заданий на рівні managed-політики — пересічний користувач їх не зніме.
  • Суміжна лінія захисту — sandboxed Bash tool: він окремо обмежує файлову систему і мережу та доповнює, а не замінює PreToolUse-deny хуки.

Екосистема при цьому жива: найбільша відкрита колекція прикладів disler/claude-code-hooks-mastery набрала 3822 зірки і 627 форків (знімок на 11 липня 2026 року). Готові хуки — це зручно, але кожен із них — чужий код із вашими правами, тож правило «прочитав і перевірив» поширюється і на них.

Варто відділяти цей матеріал від схожого за назвою Agent SDK hooks: якщо ви будуєте застосунок на Claude Agent SDK, там хуки — це програмні callback-функції в коді (TypeScript/Python), а не JSON-конфіг у settings.json. Механіка близька, спосіб під’єднання різний. Схожа екосистема розширень — навички, MCP, хуки — стала стандартом і в продуктів на базі Claude Code: наприклад, постійного ШІ-колегу в Slack збирають на тій самій зв’язці.

FAQ

Чим PreToolUse відрізняється від PostToolUse простими словами?

PreToolUse спрацьовує до виклику інструмента і може його заблокувати, дозволити або відправити на підтвердження — це єдина подія з повним контролем рішення. PostToolUse спрацьовує після: він бачить результат і може дати моделі зворотний зв’язок, але скасувати вже виконану дію не здатен. Заборони вішають на перший, реакції (формат, тести, логи) — на другий.

Хук з exit-кодом 3 існує?

Ні. Офіційний reference описує лише exit 0 (успіх), exit 2 (блокувальна помилка) і «будь-який інший код» як неблокувальну помилку. Значення «Deferred execution» для exit 3 трапляється в сторонньому туторіалі DataCamp, але це неточність: «defer» — це одне зі значень поля permissionDecision, а не код повернення процесу.

Скільки подій життєвого циклу в Claude Code насправді?

На липень 2026 року офіційний довідник перелічує близько 30 подій. Багато гайдів називають 9–13 — вони писалися раніше і просто застаріли, бо перелік активно розширюється. Ходових при цьому близько десятка: PreToolUse, PostToolUse, UserPromptSubmit, Notification, Stop, SubagentStop, SessionStart, PreCompact, SessionEnd.

Чи можуть хуки нашкодити комп’ютеру?

Так, якщо хук шкідливий. Командний хук виконується з повними правами вашого користувача і може робити все, що можете ви. Уже задокументовані реальні випадки: CVE-2025-59536 (RCE через SessionStart-хук чужого репозиторію, пропатчено) і кампанія Shai-Hulud, де SessionStart-хук у npm-пакетах слугував механізмом закріплення малварі. Тому чужі settings.json не запускають наосліп.

Чи витрачають хуки токени моделі?

Практично ні. Командні та HTTP-хуки — це звичайні процеси ОС і мережеві запити, вони не йдуть через контекст моделі. Саме тому форматувальники, лінтери та перевірки на хуках вважаються «безкоштовною» в токенах автоматизацією, на відміну від навичок і субагентів, які витрачають частину контекстного вікна.

Як заборонити агентові чіпати певні файли?

Повісьте PreToolUse-хук на інструменти Edit|WriteBash, якщо правки йдуть командами), який читає шлях із tool_input і повертає permissionDecision: deny для захищених шляхів на кшталт .env або .git. Такий хук тримається навіть у режимі обходу прав. Для організацій жорсткіше — allowManagedHooksOnly і disableAllHooks на рівні managed-політики.

Курс «Claude Code з нуля до продакшену» · модуль «Конфіг, пам'ять, навички». Повна програма і два маршрути навчання — на сторінці курсу.

Попередній урок: MCP у Claude Code: налаштування, Tool Search

Поділитися
Зв'язатися:
Крипто- та data-аналітик, інженер-програміст (факультет комп'ютерних наук ХНУРЕ). В IT з 2008 року: адміністрував корпоративний моніторинг у «Vodafone Україна», сім років розробляв і просував веб-проєкти, п'ять років керував маркетингом на метриках — конверсія, CTR, ROI, LTV.Криптовалютними ринками займаюся з 2021 року: ончейн-метрики, токеноміка, макроекономічні індикатори. Розробив власну data-driven модель аналізу ринку на 30+ метрик. Стек — Python (pandas, NumPy, SciPy, matplotlib), математична статистика та EDA; збір і звірку даних автоматизую AI-агентами.Принцип — «Don't trust, verify»: кожна цифра перевірена за першоджерелом, ключові — щонайменше за двома незалежними; прогнози — лише сценарії з умовами. Теза без даних не публікується.