Автор: abavyka
Хук — команда, яку Claude Code запускає сам у потрібний момент, а не тому що модель так вирішила.
Що це
Ти пишеш у налаштуваннях: на таку подію запусти таку команду. Подія — це момент у роботі Claude Code: перед викликом tool, після нього, коли Claude чекає на тебе, коли закінчив відповідь, старт сесії, compaction, всього понад три десятки.
Різниця з CLAUDE.md в тому, що CLAUDE.md — порада, і модель може її не виконати. Хук спрацьовує завжди. Тому раніше і писав «що критично — хуки».
Найчастіше хук — shell-команда ("type": "command"). Ще є:
http— POST з даними події на твій URLmcp_tool— виклик tool на підключеному MCP-серверіprompt— одне питання до моделі, яка вирішує «так/ні», коли правилом не описатиagent— субагент, який може сам почитати файли і запустити команди перед рішенням (експериментальний)
Як влаштований
Конфіг у три рівні: подія → matcher (на який tool, наприклад Bash чи Edit|Write) → команди.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }
]
}
]
}
}Це приклад з доки: після кожного редагування файлу Prettier його форматує.
На вхід (stdin) хук отримує JSON: tool_name, tool_input (для Bash там command, для Edit — file_path), cwd, session_id.
Відповідає хук exit code:
0— все ок2— заблокувати дію, stderr іде Claude як пояснення, чому ні- будь-який інший — помилка хука, але дія йде далі
Тобто exit 1 нічого не блокує. Хочеш заборону — тільки exit 2.
Або хук пише JSON у stdout. Для PreToolUse це:
permissionDecision—allow,deny,askабоdeferupdatedInput— підмінити аргументи tool перед запускомadditionalContext— докинути Claude текст поруч з результатом
Де живуть
~/.claude/settings.json— усі твої проєкти.claude/settings.json— проєкт, комітиться, вся команда отримує ті самі хуки.claude/settings.local.json— проєкт, тільки ти- ще в плагінах (
hooks/hooks.json), у frontmatter скілів і субагентів, і в managed settings від адміна
Хуки з усіх рівнів складаються, а не перетирають один одного. Всі, що підійшли під подію, запускаються паралельно.
/hooks— подивитись усі хуки по подіях (тільки перегляд)"disableAllHooks": true— вимкнути всі. Вимкнути один, лишивши його в конфігу, не можна
Мої
guard-main— у репо цієї вікі,.claude/settings.json,PreToolUseнаBash. Не дає Claude закомітити чи запушити вmainі змерджити PR. Це воркераунд: на безкоштовному GitHub у приватного репо нема branch protectionpeon-ping—Notification,PermissionRequest,PostToolUseFailure. Голос пеона з Warcraft III, коли сесії треба моя увага. Корисний приколcc-status— ставить сама iTerm2 (Claude Code Integration). Показує в табі статус сесії: working, waiting, idle. Я мало юзаю, по суті це просто UIrtk—PreToolUseнаBash, переписує команду черезupdatedInput:git status→rtk git status, і Claude бачить стиснутий вивід
У guard-main є обгортка на sh, яка без Node 24 блокує коміт і пуш через exit 2. Без неї хук на Node 20 падав би з помилкою, а помилка, як вище, нічого не блокує.
Що ще можна
Приклади з доки і те, що згадував раніше:
- Prettier після кожного
Edit|Write— конфіг вище - Заборона редагувати
.env,package-lock.jsonі все в.git/—PreToolUseнаEdit|Write, скрипт дивитьсяfile_pathі робитьexit 2. Claude отримує пояснення і шукає інший шлях - Повернути важливе після compaction —
SessionStartз matchercompact, усе, що команда виведе в stdout, лягає в контекст. Наприкладgit log --oneline -5чи «юзаємо pnpm, не npm» - Typecheck після кожного редагування, а не проханням —
PostToolUseнаEdit|Writeзnpx tsc --noEmit 1>&2 || exit 2. НаPostToolUseexit 2нічого не відкочує (файл уже змінено), але помилки tsc ідуть Claude, і він їх фіксить - Не відпускати Claude, поки тести не зелені —
Stop-хук типуagent: субагент запускає тести, і якщо вони падають, Claude працює далі - Фільтр виводу — хук відсікає з лога на 10 000 рядків усе, крім
ERROR, до того, як це побачить Claude. Сотні токенів замість десятків тисяч.rtkякраз про це
Підводні камені
- Хук — не замок. Таймаут чи помилка хука дію не блокують, якщо не стоїть
onFailure: "block"(з 2.1.295). Для жорсткого allow/deny є permissions - Зате
denyз хука блокує навіть уbypassPermissions - Два хуки з
updatedInputна той самий tool — переможе той, що закінчив останнім, тобто випадковий - Файли, які ти сам додав через
@, йдуть у промпт без виклику tool, тожPreToolUseнаReadїх не бачить Stop-хук, який блокує 8 разів підряд без жодного tool між ними, Claude Code перебиває і закінчує відповідь- Хук запускає будь-яку команду з твоїми правами. Хуки з
.claude/settings.jsonчужого репо працюють уclaude -pнавіть без trust dialog. Склонував — подивись, що там у хуках
Почитати
- Hooks in Claude Code (англ.)
- Automating checks with hooks (англ.)
- CLAUDE.md
- Галюцинації
- Токени і ліміти
- Як почати і приклади: Automate actions with hooks (англ.)
- Усі події, exit codes і JSON: Hooks reference (англ.)
- Що працює до trust dialog: Configure permissions (англ.)
- Фільтр виводу хуком: Manage costs effectively (англ.)
- peon-ping (англ.)
- iTerm2 Claude Code Integration (англ.)
- rtk (англ.)