Hooki Claude Code nie działają w systemie Windows: przyczyny i rozwiązania
Ten sam hook, który na Macu działa bez zarzutu, w systemie Windows nie robi nic, albo co gorsza blokuje każde polecenie. Prawie zawsze winna jest powłoka. Oto jak Claude Code uruchamia hooki w systemie Windows i jak sprawić, żeby twoje działały niezawodnie.
KRÓTKA ODPOWIEDŹ
W systemie Windows Claude Code uruchamia command hooka za pomocą Git Bash, a gdy Git Bash nie jest zainstalowany, za pomocą PowerShell. Określ, o którą chodzi, przez "shell": "powershell" lub "shell": "bash", ogranicz stdout do jednego obiektu JSON (żadnych echo z profilu), używaj kodu wyjścia 2 do blokowania i zaktualizuj Claude Code (w wersjach do 2.1.310 naprawiono kilka błędów hooków w Windows). Debuguj za pomocą /hooks i claude --debug.
Która powłoka uruchamia twój hook
Claude Code przekazuje ciąg command do powłoki: sh -c w systemach macOS i Linux, Git Bash w systemie Windows lub PowerShell, gdy Git Bash nie jest zainstalowany. To jedno zdanie z dokumentacji hooków wyjaśnia większość zgłoszeń typu „na moim Macu działa”. Polecenie napisane dla PowerShell zawodzi w Git Bash, skrypt bash zawodzi w PowerShell, a to, którą powłokę dostaniesz, zależy od tego, czy akurat masz zainstalowany Git for Windows.
Wyeliminuj zgadywanie za pomocą pola shell. Przyjmuje ono "bash" lub "powershell":
Jeśli chcesz używać Git Bash, a Claude Code nie może go znaleźć, zainstaluj Git for Windows lub ustaw CLAUDE_CODE_GIT_BASH_PATH na jego lokalizację, a potem rozpocznij nową sesję.
Objawy i ich przyczyny
| Co widzisz | Prawdopodobna przyczyna | Rozwiązanie |
|---|---|---|
| Wygląda na to, że hook nigdy się nie uruchamia | Stara wersja Claude Code, złe zdarzenie lub matcher, nieprawidłowy JSON w ustawieniach | Zaktualizuj; sprawdź /hooks; usuń komentarze i przecinki na końcu |
ParserError lub „unexpected token” | Składnia PowerShell trafia do Git Bash albo odwrotnie | Ustaw shell jawnie |
| Dane wyjściowe hooka „does not start with {” | Coś zostało wypisane przed JSON, często przez profil powłoki | Wycisz dane wypisywane przez profil; logi kieruj do stderr |
Nie można znaleźć ścieżki z mieszanymi \ i / | Windowsowa zmienna ścieżki połączona z sufiksem w stylu Unix | Użyj formy exec: program w command, każdy argument w args |
powershell: Permission denied z Git Bash | Zgłaszane sporadycznie w 2.1.283 i 2.1.304–2.1.305 (#103910, otwarte) | Użyj "shell": "powershell", żeby Git Bash nie pośredniczył |
| Hook strażnik przepuszcza wszystko | Kod wyjścia 1 zamiast 2 albo błąd fail-open w starszych wersjach | Kończ z kodem 2, żeby blokować; zaktualizuj do 2.1.310 lub nowszej |
| Hook kończy się natychmiast bez danych wyjściowych | Program z podsystemu GUI, na który powłoka nie czeka | Użyj programu konsolowego albo poczekaj na proces |
Tylko JSON na stdout
Claude Code odczytuje standardowe wyjście hooka jako jego odpowiedź. Zasada w dokumentacji jest krótka: nie wypisuj na stdout niczego poza obiektem JSON. W systemie Windows łatwo ją złamać w podstępny sposób: Git Bash i niektóre konfiguracje nadal wczytują profil powłoki, a bezwarunkowe echo w tym profilu zostaje doklejone przed twoim JSON. Hook „działa” wtedy w terminalu, ale zawodzi w Claude Code.
Zamiast tego loguj do pliku lub do stderr, a dane wypisywane przez profil uzależnij od tego, czy powłoka jest interaktywna.
Kody wyjścia: 2 blokuje, 1 nie
Kod wyjścia 0 oznacza sukces. Kod wyjścia 2 to błąd blokujący: przy zdarzeniach, które mogą blokować, Claude Code zatrzymuje akcję i pokazuje twoje stderr. Kod wyjścia 1 bez prawidłowego JSON to błąd nieblokujący i akcja zostaje wykonana. Jeśli twój hook egzekwuje zasady, używaj kodu wyjścia 2.
Nie każde zdarzenie można zablokować w ten sposób. Kod wyjścia hooka Notification jest ignorowany. Hook Stop, który kończy się kodem 2, sprawia, że Claude pracuje dalej. Hook PermissionRequest całkowicie ignoruje kod 2. Decyduje za pomocą obiektu decision w swoim JSON.
Claude Code 2.1.309 naprawił błąd, przez który hooki PowerShell nie blokowały, gdy program hooka kończył się kodem 2. Jeśli twój strażnik w PowerShell wydaje się ignorowany, najpierw sprawdź wersję.
Poprawki dla Windows, dla których warto zrobić aktualizację
Lista zmian Anthropic zawiera długą serię poprawek hooków w Windows. Te wyjaśniają stare wątki na forach:
| Wersja | Poprawka |
|---|---|
| 2.1.47 | Hooki PreToolUse i PostToolUse po cichu zawodziły w systemie Windows; teraz działają z Git Bash zamiast cmd.exe |
| 2.1.161 | Hooki, które jawnie wywołują bash (/usr/bin/bash script.sh), kończyły się błędem „command not found” |
| 2.1.299 | Hooki PreToolUse i PermissionRequest bez ustawionej powłoki działały w trybie fail-open bez Git for Windows; nieudany strażnik teraz blokuje |
| 2.1.309 | Hooki PowerShell nie blokowały przy kodzie wyjścia 2; strażnicy z "shell": "powershell" działali w trybie fail-open bez Git for Windows |
| 2.1.310 | Strażnicy, których polecenie składało się wyłącznie z ciągów w cudzysłowie (na przykład ścieżki w cudzysłowie), działali w trybie fail-open bez Git Bash |
Starsze zgłoszenie zatytułowane „No hook is working on Windows” (#10450) dotyczyło wersji 2.0.27; jeden z komentujących ustalił, że stdin nie docierał do poleceń hooków. Jeśli używasz tak starej wersji, zaktualizuj ją, zanim zaczniesz debugować cokolwiek innego.
Bezpośrednie wywoływanie programu
Jeśli twój hook jest skompilowanym programem, możesz pominąć powłokę, używając formy exec (pole args; shell jest ignorowane, gdy ustawiono args). W systemie Windows forma exec wymaga, żeby command wskazywało prawdziwy plik wykonywalny, taki jak .exe; nakładek .cmd i .bat (w tym większości tego, co instaluje npm) nie da się uruchomić bez powłoki. Wskaż plik .exe albo użyj formy shell.
Jedna lekcja z budowy naszego własnego pomocnika do hooków: w systemie Windows powłoka nie czeka na program zbudowany dla podsystemu GUI, który uruchamia. Powłoka natychmiast wraca, agent odczytuje puste dane wyjściowe, a hook wygląda na martwy. Programy hooków muszą być programami konsolowymi.
Hooki pluginów i ścieżki
Hooki pluginów, które budują ścieżki takie jak ${CLAUDE_PLUGIN_ROOT}/hooks/run.sh, nie działały w systemie Windows między v2.1.2 a v2.1.12 (#18610): zmienna rozwija się do ścieżki z ukośnikami odwrotnymi, a dodanie sufiksu ze zwykłym ukośnikiem daje mieszaną ścieżkę, której bash nie potrafi rozwiązać. Obecna dokumentacja podaje czyste rozwiązanie: używaj formy exec zawsze, gdy hook odwołuje się do symbolu zastępczego ścieżki. Umieść program w command, a każdy argument w args, na przykład "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/scripts/format.js"]. Każdy element jest przekazywany jako jeden argument, bez powłoki, która mogłaby go zniekształcić.
Lista kontrolna debugowania
/hooksotwiera listę tylko do odczytu wszystkich skonfigurowanych hooków i ich źródeł.claude --debug(lub/debugw trakcie sesji) pokazuje każde uruchomienie hooka, jego dane wyjściowe i kod wyjścia.claude --debug-file <path>zapisuje to do pliku.- Zweryfikuj JSON. Pliki ustawień to ścisły JSON; jeden przecinek na końcu wyłącza cały plik.
- Sprawdź matcher. W matcherach wielkość liter ma znaczenie;
"*",""lub brak matchera dopasowuje wszystko. - Uruchom polecenie samodzielnie w tej samej powłoce, której użyje Claude Code, przekazując przez potok przykładowy JSON.
- Sprawdź limit czasu. Hooki poleceń mają domyślnie 600 sekund; hook, który czeka na człowieka, potrzebuje tego zapasu.
Żeby wyłączyć wszystkie hooki na czas szukania przyczyny, ustaw "disableAllHooks": true.
Jeśli chodziło ci tylko o powiadomienia i zatwierdzenia
Wiele konfiguracji hooków w Windows powstaje z jednego powodu: żeby wiedzieć, kiedy Claude Code cię potrzebuje, i móc mu odpowiedzieć. Pet Island robi to bez żadnych skryptów. Łączy się z Claude Code jednym kliknięciem, załatwia za ciebie szczegóły związane z Windows i umieszcza każdą prośbę o zgodę, pytanie i plan na małej wyspie u góry ekranu, razem z poleceniem lub diffem, gdzie je zatwierdzasz lub odrzucasz. Działa też wtedy, gdy Claude Code jest uruchomiony w WSL.
CZĘSTE PYTANIA
Która powłoka uruchamia hooki Claude Code w systemie Windows?
Git Bash, a gdy Git Bash nie jest zainstalowany, PowerShell. Ustaw "shell": "powershell" lub "shell": "bash" w hooku, żeby wybrać jawnie.
Dlaczego mój hook Claude Code działa w terminalu, ale nie w Claude Code?
Zwykle przez dodatkowe dane wyjściowe: profil powłoki, który wypisuje tekst przez echo, zostaje doklejony przed JSON hooka. Wypisuj na stdout tylko obiekt JSON.
Jak sprawić, żeby hook zablokował wywołanie narzędzia?
Zakończ go kodem 2 (lub zwróć decyzję deny w JSON). Kod wyjścia 1 to błąd nieblokujący i akcja zostaje wykonana. Hooki PermissionRequest ignorują kod 2 i zamiast tego używają obiektu decision.
Czy polecenie hooka może być plikiem .cmd lub .bat?
Nie w formie exec. W systemie Windows musi ono wskazywać prawdziwy plik wykonywalny, taki jak .exe. Do uruchamiania plików .cmd lub .bat użyj formy shell.
Jak sprawdzić, dlaczego hook zawiódł?
Uruchom claude --debug lub wpisz /debug, a za pomocą /hooks sprawdź, które hooki są wczytane.
Źródła
Każde ustawienie i zachowanie opisane na tej stronie zostało sprawdzone z tymi stronami 26 października 2026. Agenci szybko się zmieniają; jeśli coś przestało się zgadzać, obowiązuje strona oficjalna.
- Dokumentacja Claude Code: Hooks reference
- Dokumentacja Claude Code: Hooks guide
- Claude Code: CHANGELOG
- Zgłoszenie #10450: No hook is working on Windows
- Zgłoszenie #18610: Plugin hooks cannot execute scripts on Windows
- Zgłoszenie #103910: Hooks intermittently fail to spawn powershell (Git Bash)