Хуки 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 и выводит каждый запрос разрешения, вопрос и план на маленький остров в верхней части экрана вместе с командой или диффом, где вы разрешаете или запрещаете действие. Он работает и тогда, когда 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)