
Hooki w Claude Code: kompletny przewodnik (2026)
Skill może zostać zignorowany. To nie jest wada skilli, to cały zamysł: Claude czyta opis, decyduje, czy bieżące zadanie pasuje, i ładuje treść tylko, jeśli tak uważa. Przez większość czasu ta ocena jest trafna. Czasem nie jest, a zadanie, w którym ma to największe znaczenie — przegląd kodu tuż przed mergem, wpis w logu, który musi istnieć bez względu na wszystko — to dokładnie zadanie, w którym „prawdopodobnie" to za mało.
Hooki to druga połowa Claude Code. Hook to komenda powłoki, którą harness uruchamia przy konkretnym zdarzeniu, niezależnie od tego, czy jakikolwiek skill by o tym pomyślał. Żaden osąd modelu nie stoi między zdarzeniem a komendą. Uruchamia się, za każdym razem, w kolejności, a jej kod wyjścia może nawet zatrzymać Claude na miejscu. Jeśli kiedykolwiek chciałeś powiedzieć „zawsze sformatuj ten plik po edycji" albo „nigdy nie pozwól Claude dotknąć tego katalogu", hook to narzędzie zbudowane do tego zdania.
Ten przewodnik obejmuje, czym są hooki, schemat settings.json za nimi, sześć przepisów, które możesz wkleić już dziś, jak hooki i skille współpracują, i tryby awarii, które zjadają popołudnie, jeśli nie wiesz, gdzie ich szukać.
Czym naprawdę jest hook
Claude Code odpala nazwane zdarzenia podczas sesji: przed uruchomieniem narzędzia, po uruchomieniu narzędzia, gdy Claude kończy odpowiedź, gdy pojawiłoby się powiadomienie. Hook wiąże komendę powłoki z jednym z tych zdarzeń, opcjonalnie filtrowaną do konkretnych narzędzi. Harness uruchamia twoją komendę, przekazuje jej kontekst jako JSON na stdin, potem czyta kod wyjścia, żeby zdecydować, co się dzieje dalej.
Zdarzenia, których użyjesz najczęściej:
- PreToolUse — odpala się przed wykonaniem wywołania narzędzia. Hook tutaj może całkowicie zablokować wywołanie.
- PostToolUse — odpala się po zakończeniu wywołania narzędzia. Dobry do formatowania, testowania albo logowania tego, co się właśnie stało.
- Stop — odpala się, gdy Claude kończy swoją turę i ma zamiar oddać kontrolę z powrotem tobie.
- Notification — odpala się, gdy Claude Code pokazałby ci powiadomienie systemowe (prośby o uprawnienia, podpowiedzi bezczynności).
- UserPromptSubmit — odpala się, gdy wysyłasz wiadomość, zanim Claude ją zobaczy.
To jest mechanizm. Powód, dla którego to ma znaczenie, to gwarancja, jaką daje, a której skill strukturalnie nie potrafi dać.
Model mentalny: deterministyczne vs uznaniowe
To jedna idea warta zapamiętania, jeśli nie zapamiętasz nic więcej z tego przewodnika.
Skill jest uznaniowy. Claude czyta jego opis na początku sesji, a później decyduje, na podstawie twojej prośby, czy go załadować i się nim kierować. Dobre skille wyzwalają się niezawodnie, ale „niezawodnie" to wciąż prawdopodobieństwo, nie gwarancja. Claude może źle odczytać niejednoznaczny prompt, albo dwa skille mogą mieć nakładające się opisy, które mylą dopasowanie — tryb awarii, który omawiamy głębiej w naszym przewodniku o tym, dlaczego skille się nie wyzwalają.
Hook jest deterministyczny. Nie pyta Claude, czy ma się uruchomić. Nie czyta opisu i nie ocenia trafności. Harness widzi zdarzenie, a komenda się uruchamia, kropka. Jeśli zdarzeniem jest PostToolUse na narzędziu Edit, twój formatter uruchamia się po każdej edycji, w tym tej, którą Claude zrobił, myśląc o czymś zupełnie innym.
Ta różnica przekłada się wprost na to, po co po co sięgać:
| Skill | Hook | |
|---|---|---|
| Uruchamia się, gdy | Claude uzna to za istotne | Zdarzenie się odpala, za każdym razem |
| Może zostać pominięty | Tak, przez złe dopasowanie albo zajęty kontekst | Nie |
| Najlepszy do | Osądu, struktury, „jak dobrze zrobić X" | Egzekwowania, „X musi się zawsze wydarzyć" |
| Tryb awarii | Cichy brak wyzwolenia | Cichy zły kod wyjścia, albo blokowanie wszystkiego |
Jeśli zdanie, które egzekwujesz, zaczyna się od „Claude powinien zawsze..." albo „Claude nigdy nie może...", chcesz hooka. Jeśli zaczyna się od „gdy Claude robi X, powinien podejść do tego jak...", chcesz skilla. Formatowanie kodu po każdej edycji to hook; pisanie idiomatycznego Pythona to skill. Blokowanie commitów do main to hook; strukturyzowanie dobrego komunikatu commita to skill.
Anatomia hooka w settings.json
Hooki żyją pod kluczem hooks w .claude/settings.json (poziom projektu) albo ~/.claude/settings.json (poziom użytkownika), innym pliku niż CLAUDE.md i warto ich nie mylić: CLAUDE.md to proza, którą czyta Claude, settings.json to konfiguracja, którą wykonuje harness. Jeśli jeszcze nie skonfigurowałeś żadnego z nich, nasz przewodnik po CLAUDE.md i nasz pełny przewodnik konfiguracji obejmują resztę stosu, w którym żyje ten plik. Oto minimalny, ale kompletny przykład hooków, z adnotacjami:
{
"hooks": {
// The event name — PreToolUse, PostToolUse, Stop, Notification, etc.
"PostToolUse": [
{
// matcher filters which tool calls trigger this hook.
// Omit it (or use "*") to match every tool.
"matcher": "Edit|Write",
"hooks": [
{
// "command" is currently the only hook type.
"type": "command",
// The shell command to run. Receives event JSON on stdin.
"command": "npx prettier --write \"$(echo $CLAUDE_TOOL_INPUT | jq -r .file_path)\"",
// Optional: kill the command if it hangs.
"timeout": 15
}
]
}
]
}
}
Kilka rzeczy wartych wypunktowania, bo ludzie się na nich potykają.
Pole matcher operuje na nazwie narzędzia, nie na ścieżkach plików ani zawartości. "Edit|Write" pasuje do narzędzi Edit i Write; "Bash" pasuje do wywołań powłoki. Jeśli musisz filtrować po ścieżce pliku albo zawartości komendy, rób to wewnątrz swojego skryptu, czytając payload JSON, nie w matcherze.
Każdy klucz zdarzenia trzyma tablicę bloków matchera, a każdy blok matchera trzyma tablicę komend hooka, więc możesz przypiąć kilka komend do jednego matchera, albo jedną komendę do kilku matcherów, bez duplikowania konfiguracji.
Komenda otrzymuje payload zdarzenia jako JSON na stdin: nazwę narzędzia, wejście narzędzia, a dla PostToolUse — wynik narzędzia. Hook działający na konkretnym edytowanym pliku czyta ten JSON, zamiast zakładać, że katalog roboczy powłoki opowiada całą historię.
Kody wyjścia niosą znaczenie. Wyjście 0 znaczy „w porządku, kontynuuj". Niezerowe wyjście przy hooku PreToolUse blokuje wywołanie narzędzia i podaje stderr z powrotem Claude jako powód. Niezerowe wyjście przy PostToolUse jest po prostu logowane; narzędzie już się uruchomiło, więc nie ma już czego blokować.
Sześć przepisów, których możesz użyć już dziś
Są celowo wąskie. Skopiuj blok, dostosuj komendę i potwierdź, że robi to, czego oczekujesz, na pliku do wyrzucenia, zanim zaufasz mu przy realnej pracy.
1. Automatyczne formatowanie po każdej edycji
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "cd \"$CLAUDE_PROJECT_DIR\" && npx prettier --write . --ignore-unknown"
}
]
}
]
}
}
Uruchamia Prettiera po każdej edycji albo zapisie. Przy dużych repo zamień ogólne . na ścieżkę wyprowadzoną z JSON-a hooka, żeby formatować tylko dotknięty plik.
2. Blokowanie edycji chronionych ścieżek
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/guard_paths.py"
}
]
}
]
}
}
guard_paths.py czyta ścieżkę pliku z JSON-a na stdin, sprawdza ją względem listy zablokowanych (migrations/, .env, infra/prod/) i kończy się kodem 1 z komunikatem na stderr, jeśli pasuje. To najbliższa rzecz do twardej granicy uprawnień, jaką ma Claude Code.
3. Uruchamianie testów po zmianach w źródle
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "cd \"$CLAUDE_PROJECT_DIR\" && npm test -- --onlyChanged --silent"
}
]
}
]
}
}
Daje Claude natychmiastowy sygnał, gdy edycja psuje test, zamiast czekać, aż zauważysz to przy przeglądzie. Trzymaj komendę testu wąską (--onlyChanged, szybki podzbiór), bo inaczej staje się to przepisem szóstym w sekcji „kiedy nie" poniżej.
4. Powiadomienie na pulpicie, gdy Claude kończy
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude finished\" with title \"Claude Code\"'"
}
]
}
]
}
}
Specyficzne dla macOS (zamień na notify-send na Linuksie). Przydatne, gdy zaczynasz uruchamiać dłuższe autonomiczne tury i przestajesz cały czas obserwować terminal.
5. Logowanie każdej komendy basha
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.command' >> \"$CLAUDE_PROJECT_DIR/.claude/bash-history.log\""
}
]
}
]
}
}
Ślad audytowy, który nie zależy od tego, czy pamiętasz o sprawdzeniu transkryptu. Na współdzielonej maszynie albo w repo z wymogiem compliance, to jest bliskie obowiązkowego.
6. Bramka lintowania przed commitem
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/block_bad_commit.sh"
}
]
}
]
}
}
block_bad_commit.sh czyta stdin, sprawdza, czy komenda to git commit, i jeśli tak, najpierw uruchamia twój linter, kończąc się niezerowym kodem, jeśli ten zawiedzie. To zmienia „proszę, zlintuj przed commitem" z prośby, o której Claude może zapomnieć, w regułę, której nie może obejść.
DARMOWY PAKIET STARTOWY
Konfigurujesz hooki obok swoich pierwszych skilli? Wyślemy nasze 3 najwyżej ocenione skille plus checklistę instalacyjną, której używamy przed każdym testem SkillProof. Za darmo.
Odbierz darmowy pakiet startowyHooki i skille razem
To nie są konkurujące narzędzia; najlepsze setupy używają obu do tego, w czym każde jest dobre. Przykład z życia: testowany przez nas zespół chciał, żeby każdy commit był napisany w ich firmowym stylu — tryb rozkazujący, zakresowany prefiks, treść wyjaśniająca „dlaczego" — i chciał też, żeby commity były blokowane, jeśli diff dotyka migracji bazy danych bez pasującego pliku rollbacku.
Część stylistyczna to osąd. To, co liczy się jako dobre „dlaczego", zmienia się w zależności od zmiany, i nie ma skryptu shell, który niezawodnie napisze dobrą prozę. To robota skilla: coś jak Git Workflow Coach ładowany, gdy Claude ma zamiar zrobić commit, ucząc struktury i dając przykłady dobrych versus leniwych komunikatów commitów. Claude go czyta, stosuje osąd i pisze komunikat pasujący do wzorca, nie będąc wypełnieniem szablonu. Jeśli zespół prowadzi też ścisły red-green-refactor, Test-Driven Development to ten sam rodzaj dodatku „osąd, nie prawo": kształtuje sposób, w jaki Claude podchodzi do pracy, czego hook nie potrafi zrobić.
Reguła migracji nie jest osądem, jest prawem: albo plik rollbacku istnieje, albo nie, a zespół nie chciał, żeby „Claude zdecydował, że ten jednak go nie potrzebuje" było opcją. To hook PreToolUse z przepisu szóstego, dostosowany do sprawdzania sparowanego pliku zamiast uruchamiania lintera, blokujący samo wywołanie git commit, jeśli plik brakuje.
Uruchom je razem i dostaniesz dobry komunikat commita, który jest też gwarantowanie zgodny z kontrolą migracji, bo skill obsługuje część potrzebującą mózgu, a hook obsługuje część potrzebującą ściany. Żadne nie zastępuje drugiego. Skill nie może zagwarantować zgodności, a hook piszący „fix: various changes" przy każdym commicie byłby bezużyteczny. Nasza strona najlepszych skilli do kodowania rankinguje osądową stronę tego duetu według testowanego wyniku, jeśli wybierasz pierwszy skill do uruchomienia obok hooków.
Debugowanie hooków
Hooki zawodzą cicho częściej niż głośno. Oto, co zwykle się psuje.
Cudzysłowy. Komendy hooka to stringi powłoki wewnątrz stringów JSON, więc nieuciekniony " psuje parsowanie JSON, zanim twoja komenda w ogóle się uruchomi. W razie wątpliwości umieść prawdziwą logikę w pliku skryptu i niech komenda hooka po prostu go wywołuje (bash .claude/hooks/my-hook.sh), zamiast wklejać złożony jednolinijkowiec.
Kody wyjścia, które nie znaczą tego, co myślisz. Skrypt hooka, który trafia na niepowiązany błąd (brakująca zależność, odmowa uprawnień), kończy się niezerowym kodem tak samo jak hook, który celowo chce zablokować. Jeśli hook PreToolUse zaczyna blokować każde wywołanie narzędzia, a nie napisałeś go tak surowo, sprawdź, czy skrypt faktycznie zawodzi, zamiast oceniać.
Założenia o PATH. Hooki uruchamiają się w środowisku powłoki, które może nie pasować do twojego interaktywnego terminala. Komenda, która działa dobrze, gdy wpisujesz ją sama, może zawieść wewnątrz hooka, bo nvm, virtualenv albo narzędzie zainstalowane przez plugin powłoki nie są na PATH w tym kontekście. Używaj bezwzględnych ścieżek do binarek albo zaimportuj właściwe środowisko na początku skryptu.
Ciche założenia o stdin. Jeśli twój skrypt oczekuje JSON-a na stdin i go nie dostaje, bo testowałeś go uruchamiając bezpośrednio, a nie podając przykładowy payload przez pipe, będzie zachowywał się inaczej pod harnessem niż w twoim terminalu.
Timeouty. Hook bez timeoutu, który się zawiesza, zawiesi całą turę. Ustaw jawny timeout na wszystko, co dotyka sieci albo wolnego podprocesu.
Kiedy nie używać hooków
Hooki są tanie w napisaniu i łatwe w nadużyciu. Trybem awarii nie jest hook robiący złą rzecz, to hook robiący dobrą rzecz zbyt często. Hook PostToolUse uruchamiający pełny zestaw testów po każdej pojedynczej edycji zmienia pięciosekundową zmianę w dwuminutowe oczekiwanie, powtórzone dla każdej z dwudziestu edycji w sesji.
Zasada kciuka: jeśli komenda hooka zajmuje więcej niż sekundę czy dwie, zawęź matcher, zawęź to, co sprawdza, albo przenieś na rzadsze zdarzenie. Test-przy-każdej-edycji staje się test-przy-zapisie-pliku, które staje się test-przed-commitem, w miarę jak sprawdzenie robi się droższe. Dopasuj koszt hooka do częstości odpalania jego zdarzenia i rozważ, czy skill, który tylko ładuje kontekst i nie uruchamia procesu, jest lepszym dopasowaniem do wszystkiego, co nie jest ściśle egzekwowaniem.
Warto też nie sięgać po hook, żeby naprawić problem wyzwalania skilla. Jeśli skill nie odpala się, gdy powinien, naprawą jest lepszy opis, nie hook, bo hooki uruchamiają komendy powłoki i nie potrafią załadować treści skilla. Po ten tryb awarii zobacz dlaczego skille się nie wyzwalają.
PAKIET SKILLPROOF
Parowanie hooków z właściwymi skillami to większość dobrego setupu Claude Code. Developer Toolkit pakuje nasze najwyżej ocenione skille do kodowania, wstępnie sprawdzone pod kątem konfliktów wyzwalaczy, więc skillowa połowa tego duetu jest już zrobiona za ciebie.
Odbierz Developer Toolkit — 10 $FAQ
Czy hooki spowalniają każdą sesję Claude Code?
Tylko zdarzenia, do których je przypniesz, i tylko o tyle, ile zajmuje twoja komenda. Hook na PostToolUse dla Edit uruchamia się raz na edycję; szybki formatter jest niezauważalny, pełny zestaw testów daje się odczuć przy każdej edycji, co jest właśnie przypadkiem omówionym powyżej pod „kiedy nie używać hooków".
Czy hook może całkowicie powstrzymać Claude od czegoś?
Tak, po to są hooki PreToolUse. Zakończ się niezerowym kodem, a wywołanie narzędzia zostanie zablokowane, zanim się uruchomi, ze stderr zwykle pokazanym Claude jako powód. To mechanizm stojący za przepisem drugim (chronione ścieżki) i szóstym (bramka lintowania).
Gdzie umieścić konfigurację hooków, w ustawieniach projektu czy użytkownika?
Poziom projektu (.claude/settings.json, commitowany), jeśli ma się stosować do wszystkich w tej bazie kodu: formatowanie, chronione ścieżki, kontrole migracji. Poziom użytkownika (~/.claude/settings.json) dla osobistej preferencji, jak powiadomienie na pulpicie w przepisie czwartym.
Jaka jest różnica między hookiem a skillem mówiącym „zawsze formatuj kod"?
Hook faktycznie zawsze się uruchamia. Skill mówiący Claude, żeby zawsze formatował kod, wciąż jest instrukcją, którą Claude czyta i decyduje, czy się jej podporządkować; to mocny impuls, nie gwarancja, i konkuruje z innymi rzeczami w kontekście o uwagę w danej turze. Jeśli „zawsze" jest wymogiem, a nie preferencją, użyj hooka.
Mój hook w ogóle się nie uruchamia. Co sprawdzić najpierw?
Potwierdź, że plik ustawień to poprawny JSON (przecinek na końcu albo nieuciekniony cudzysłów może po cichu wyłączyć cały blok hooks) i że nazwa zdarzenia i matcher są dokładnie tak zapisane, jak oczekiwano; oba są wrażliwe na wielkość liter. Potem sprawdź, czy edytowałeś ustawienia projektu, gdy sesja czyta ustawienia użytkownika, albo odwrotnie.
★ 9.6/10 × 3
Darmowy pakiet startowy
3 skille z naszymi najwyższymi ocenami z testów plus checklista instalacji — zestaw, który sami wgralibyśmy na świeżą maszynę. Za darmo, na e-mail.