Хуки Claude Code не працюють у Windows: причини й рішення
Хук, який чудово працює на Mac, у Windows нічого не робить або, що гірше, блокує кожну команду. Майже завжди справа в оболонці. Нижче описано, як Claude Code запускає хуки у Windows і як зробити ваші хуки надійними.
КОРОТКО
У Windows Claude Code запускає command хука через Git Bash, а якщо Git Bash не встановлено, через PowerShell. Явно вкажіть потрібну оболонку за допомогою "shell": "powershell" або "shell": "bash", виводьте в stdout лише один об’єкт JSON (без echo з профілю), використовуйте код виходу 2 для блокування й оновіть Claude Code (кілька помилок хуків у Windows виправлено у версіях до 2.1.310). Для налагодження використовуйте /hooks і claude --debug.
Яка оболонка запускає ваш хук
Claude Code передає рядок command оболонці: sh -c у macOS і Linux, Git Bash у Windows або PowerShell, якщо Git Bash не встановлено. Це одне речення з довідника з хуків пояснює більшість скарг «а на моєму Mac працює». Команда, написана для PowerShell, падає в Git Bash, bash-скрипт падає в PowerShell, а яка оболонка вам дістанеться, залежить від того, чи встановлено випадково Git for Windows.
Приберіть невизначеність за допомогою поля shell. Воно приймає "bash" або "powershell":
Якщо вам потрібен Git Bash, а Claude Code не може його знайти, встановіть Git for Windows або вкажіть його розташування в CLAUDE_CODE_GIT_BASH_PATH, потім почніть нову сесію.
Симптоми та їхні причини
| Що ви бачите | Імовірна причина | Рішення |
|---|---|---|
| Хук, схоже, взагалі не запускається | Стара версія Claude Code, неправильна подія або matcher, некоректний JSON у налаштуваннях | Оновіться; перевірте /hooks; приберіть коментарі й кінцеві коми |
ParserError або «unexpected token» | Синтаксис PowerShell потрапляє в Git Bash або навпаки | Явно задайте shell |
| Виведення хука «does not start with {» | Перед JSON щось виводиться, часто профіль оболонки | Вимкніть виведення профілю; пишіть логи в stderr |
Не знаходиться шлях, у якому змішано \ і / | Змінну зі шляхом Windows склеєно із суфіксом у стилі Unix | Використовуйте exec-форму: програма в command, кожен аргумент в args |
powershell: Permission denied з Git Bash | Періодично трапляється у 2.1.283 і 2.1.304–2.1.305 (#103910, відкритий) | Використовуйте "shell": "powershell", щоб виключити Git Bash із ланцюжка |
| Захисний хук пропускає все | Код виходу 1 замість 2 або помилка fail-open у старих версіях | Для блокування завершуйте хук із кодом 2; оновіться до 2.1.310 або новішої |
| Хук миттєво завершується без виведення | Програма підсистеми GUI, завершення якої оболонка не чекає | Використовуйте консольну програму або чекайте завершення процесу |
У stdout лише JSON
Claude Code зчитує стандартне виведення хука як його відповідь. Правило в документації коротке: не виводьте в stdout нічого, крім об’єкта JSON. У Windows воно порушується непомітно: Git Bash і деякі конфігурації однаково завантажують профіль оболонки, і безумовний echo у цьому профілі додається перед вашим JSON. У результаті хук «працює» в терміналі й падає всередині Claude Code.
Пишіть логи у файл або в stderr, а виведення в профілі робіть лише для інтерактивної оболонки.
Коди виходу: 2 блокує, 1 ні
Код виходу 0 означає успіх. Код 2 означає блокувальну помилку: на подіях, які можна заблокувати, Claude Code зупиняє дію і показує ваш stderr. Код 1 без коректного JSON вважається неблокувальною помилкою, і дія виконується. Якщо хук забезпечує дотримання політики, використовуйте код 2.
Не кожну подію можна так заблокувати. Код виходу хука Notification ігнорується. Хук Stop, що завершився з кодом 2, змушує Claude продовжувати роботу. Хук PermissionRequest повністю ігнорує код 2. Він ухвалює рішення через об’єкт decision у своєму JSON.
У Claude Code 2.1.309 виправлено помилку, через яку хуки PowerShell не блокували дію, коли програма хука завершувалася з кодом 2. Якщо ваш захисний хук на PowerShell ніби ігнорується, спершу перевірте версію.
Виправлення для Windows, заради яких варто оновитися
У журналі змін Anthropic накопичилося багато виправлень хуків для Windows. Ось ті, які пояснюють старі обговорення на форумах:
| Версія | Виправлення |
|---|---|
| 2.1.47 | Хуки PreToolUse і PostToolUse мовчки не спрацьовували у Windows; тепер вони запускаються через Git Bash замість cmd.exe |
| 2.1.161 | Хуки, що явно викликають bash (/usr/bin/bash script.sh), падали з «command not found» |
| 2.1.299 | Хуки PreToolUse і PermissionRequest без заданої оболонки спрацьовували як fail-open без Git for Windows; тепер захисний хук, що впав, блокує дію |
| 2.1.309 | Хуки PowerShell не блокували при коді виходу 2; захисні хуки з "shell": "powershell" спрацьовували як fail-open без Git for Windows |
| 2.1.310 | Захисні хуки, у яких команда складалася лише з рядків у лапках (наприклад, шляху в лапках), спрацьовували як fail-open без Git Bash |
Старий issue із заголовком «No hook is working on Windows» (#10450) було створено для версії 2.0.27; один із коментаторів з’ясував, що stdin не доходив до команд хуків. Якщо у вас настільки стара версія, оновіться, перш ніж щось налагоджувати.
Прямий виклик програми
Якщо ваш хук — скомпільована програма, можна обійтися без оболонки, використовуючи exec-форму (поле args; якщо задано args, shell ігнорується). У Windows exec-форма вимагає, щоб command вказував на справжній виконуваний файл, наприклад .exe; обгортки .cmd і .bat (зокрема більшість того, що встановлює npm) неможливо запустити без оболонки. Вкажіть .exe або використовуйте форму з оболонкою.
Один урок із розробки нашого власного помічника для хуків: у Windows оболонка не чекає завершення програми, зібраної для підсистеми GUI. Оболонка одразу повертає керування, агент читає порожнє виведення, і хук виглядає мертвим. Програми хуків мають бути консольними.
Хуки плагінів і шляхи
Хуки плагінів, що збирають шляхи на кшталт ${CLAUDE_PLUGIN_ROOT}/hooks/run.sh, перестали працювати у Windows між v2.1.2 і v2.1.12 (#18610): змінна розгортається у шлях зі зворотними скісними рисками, а доданий суфікс із прямими скісними рисками дає змішаний шлях, який bash не може розв’язати. Актуальна документація пропонує чисте рішення: використовуйте exec-форму щоразу, коли хук посилається на плейсхолдер шляху. Помістіть програму в command, а кожен аргумент в args, наприклад "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/scripts/format.js"]. Кожен елемент передається як один аргумент, і немає оболонки, яка могла б його спотворити.
Чек-лист налагодження
/hooksвідкриває список усіх налаштованих хуків лише для читання із зазначенням, звідки взявся кожен.claude --debug(або/debugпосеред сесії) показує кожен запуск хука, його виведення й код виходу.claude --debug-file <path>записує це у файл.- Перевірте JSON. Файли налаштувань — це строгий JSON; одна кінцева кома вимикає весь файл.
- Перевірте matcher. Matcher чутливий до регістру;
"*",""або відсутність matcher збігається з усім. - Запустіть команду самі в тій самій оболонці, яку використовуватиме Claude Code, передавши на вхід приклад JSON.
- Подивіться на тайм-аут. У командних хуків за замовчуванням 600 секунд; хуку, який чекає на людину, потрібен цей запас.
Щоб на час розслідування вимкнути всі хуки, задайте "disableAllHooks": true.
Якщо вам потрібні були лише сповіщення й підтвердження
Багато конфігурацій хуків у Windows існують заради одного: дізнаватися, коли ви потрібні Claude Code, і відповідати йому. Pet Island робить це без жодних скриптів. Він підключається до Claude Code одним клацанням, сам розв’язує всі тонкощі Windows і виводить кожен запит дозволу, запитання і план на маленький острів у верхній частині екрана разом із командою або diff, де ви дозволяєте або забороняєте дію. Він працює і тоді, коли Claude Code запущено всередині WSL.
Поширені запитання
Яка оболонка запускає хуки Claude Code у Windows?
Git Bash, а якщо Git Bash не встановлено, PowerShell. Щоб вибрати явно, задайте в хуку "shell": "powershell" або "shell": "bash".
Чому мій хук Claude Code працює в терміналі, але не в Claude Code?
Зазвичай через зайве виведення: профіль оболонки, який виводить текст через echo, додає його перед JSON хука. Виводьте в stdout лише об’єкт JSON.
Як зробити, щоб хук блокував виклик інструмента?
Завершуйте хук із кодом 2 (або поверніть рішення deny у JSON). Код виходу 1 — це неблокувальна помилка, і дія виконується. Хуки PermissionRequest ігнорують код 2 і натомість використовують об’єкт decision.
Чи може командою хука бути файл .cmd або .bat?
Не в exec-формі. У Windows команда має вказувати на справжній виконуваний файл, наприклад .exe. Щоб запускати файли .cmd або .bat, використовуйте форму з оболонкою.
Як дізнатися, чому хук не спрацював?
Запустіть claude --debug або введіть /debug, а за допомогою /hooks подивіться, які хуки завантажено.
Джерела
Усі налаштування й описану поведінку на цій сторінці звірено з цими джерелами 26 жовтня 2026 р.. Агенти швидко змінюються; якщо щось уже не збігається, пріоритет має офіційна сторінка.
- Документація Claude Code: Hooks reference
- Документація Claude Code: Hooks guide
- Claude Code: CHANGELOG
- Issue #10450: No hook is working on Windows
- Issue #18610: Plugin hooks cannot execute scripts on Windows
- Issue #103910: Hooks intermittently fail to spawn powershell (Git Bash)