Zespoły dodają hooki Claude Code, żeby agenci AI nie narobili szkód, a potem zakładają, że działają. Hook może przechodzić przy każdym uruchomieniu i nic nie robić. Hook, który po cichu nic nie robi, jest gorszy niż brak hooka, bo wszyscy przestają patrzeć. Rozwiązaniem są cztery tanie testy, które może skopiować każdy zespół.
Krótka odpowiedź: hook milknie, gdy jego wyjście nigdzie nie trafia, gdy jego ścieżka nie istnieje albo gdy ktoś nadpisuje jego kod wyjścia. Proszę sprawdzać wszystkie trzy w CI. A najważniejszy hook proszę podpiąć pod zdarzenie Stop, żeby agent nie mógł powiedzieć „gotowe”, dopóki testy są czerwone.
Jak hooki Claude Code w ogóle cokolwiek blokują?
Hook to polecenie powłoki, które Claude Code uruchamia przy zdarzeniu. PreToolUse działa przed wywołaniem narzędzia, Stop wtedy, gdy agent chce skończyć. Polecenie dostaje zdarzenie jako obiekt JSON na stdin.
Decyduje kod wyjścia:
Exit 0 przepuszcza.
Exit 2 blokuje. To, co hook zapisze na stderr, wraca do agenta jako powód.
Każdy inny kod to błąd nieblokujący. Claude Code pracuje dalej.
To cały kontrakt. Wszystko, co psuje się w hookach, psuje się w jego obrębie.
Dlaczego hook po cichu nic nie robi?
Hook może milczeć od pierwszego dnia i nikt tego nie zauważy. Zwykle z trzech powodów, z których każdy osobno jest niewinny:
Wyciszony. Hook zapisuje swój jedyny komunikat na stderr, ale polecenie w ustawieniach kończy się na 2>/dev/null. Agent nic nie słyszy.
Nieistniejący. Hook używa ścieżki względnej. W sesji uruchomionej w zagnieżdżonym repozytorium ta ścieżka nie istnieje. Exit 127, polecenie nie znalezione.
Zamaskowany.|| true na końcu zamienia 127 na 0. Przy zdarzeniu blokującym tak samo zamienia 2 na 0. Każde uruchomienie „przechodzi”.
Nikt tego nie zauważa, bo milczący hook wygląda dokładnie tak samo jak zdrowy. Znajdzie go dopiero analiza sesji Claude Code albo test w CI.
Proszę dodać do walidatora test, który działa w CI każdego repozytorium. Cztery grepy po .claude/settings.json, nic nie jest uruchamiane:
Test
Co wykrywa
Poprawka
Skrypt istnieje
Ścieżkę, która nie istnieje
"$CLAUDE_PROJECT_DIR"/... albo ścieżka bezwzględna
Skrypt jest wykonywalny
Hook, który działa tylko przypadkiem
chmod +x
stderr nie jest odrzucany, gdy skrypt na niego pisze
Wyciszony hook
Usunąć 2>/dev/null
Hook PreToolUse nie kończy się na || true
Blokadę zamienioną w przepustkę
Usunąć || true
Proszę przetestować ten test na prawdziwym błędzie: zepsuta konfiguracja musi zgłosić błędy krytyczne, poprawiona musi przejść.
Nie każde || true jest błędem. Hook powitalny na SessionStart może celowo używać 2>/dev/null || true, bo powitanie nigdy nie może zepsuć sesji. Test powinien zgłaszać tylko miejsca, w których oczekiwana jest blokada.
Lekcja w jednym zdaniu, tak jak stoi w naszym hooku przeciw podpisom AI: „A rule is a request. This is the lock.” Reguła jest prośbą, hook jest zamkiem. A zamek potrzebuje własnego testu.
Jeszcze niedawno agent miał swoje reguły tylko w plikach z regułami i czasem ich nie przestrzegał. Zamieniliśmy je więc w testy, których nie może obejść.
Filip Papranec
Założyciel Digitaliko
Który hook naprawdę blokuje?
Hook Stop. Agent, który mówi „gotowe”, gdy testy są czerwone, kosztuje seniora jedną rundę review. Hook Stop zmusza agenta, żeby najpierw to naprawił.
Nasza wersja z publicznego startera, lekko skrócona:
#!/bin/bash# Stop hook: the agent can't finish while the checks are red.in=$(cat)[ "$(printf '%s' "$in" | jq -r '.stop_hook_active // false')"=true ] &&exit 0cd"${CLAUDE_PROJECT_DIR:-.}"2>/dev/null ||exit 0out=$(GATE_SKIP_INSTALL=1 GATE_SCRIPTS="typecheck lint test" bash scripts/gate.sh checks 2>&1)&&exit 0jq -n --arg r "Checks are red. Fix them before you say the task is done:$out"'{decision: "block", reason: $r}'
Krok po kroku robi to:
01
Czyta stop_hook_active
Jeśli jest true, agent już kontynuuje przez ten hook. Hook go przepuszcza, żeby nie kręcił się w pętli.
02
Uruchamia testy
Typecheck, lint i testy, te same co w CI.
03
Blokuje z podaniem powodu
Gdy testy są czerwone, zwraca decision: block z logiem błędu jako powodem.
04
Agent usuwa przyczynę
Czyta log, naprawia błąd i znów próbuje skończyć.
Blokuje JSON-em, nie kodem wyjścia. Agent pracuje dalej, a powód, który dostaje, to dokładnie to, co się nie powiodło.
To wczesne ostrzeżenie, nie gate. Rozstrzygający test powinien uruchomić się ponownie po sesji, w kodzie, którego agent nie może dotknąć. Hook oszczędza tylko jedną rundę.
Na co uważać w hooku Stop?
Hook Stop też może mieć własny cichy błąd. Stały, minimalny PATH bez katalogów z narzędziami użytkownika sprawia, że w repozytoriach z Bun brakuje narzędzi potrzebnych do testów. Gate szukany w jednym stałym miejscu działa tylko na jednej maszynie. Proszę ustawić pełny PATH i szukać gate'u względem samego hooka.
Hooki Claude Code w zespole: od czego zacząć?
Proszę sprawdzić, co z tego Państwa repozytoria już mają. Każdy punkt to kilka linii w ustawieniach albo w CI:
Trzeci punkt najłatwiej przeoczyć. Nasz hook przeciw podpisom AI czyta wejście przez jq, potem awaryjnie przez python3, a następnie przez sed. Brak jq nigdy nie może zamienić zamka w ciche przepuszczanie. Ścieżki względne z kolei psują się w zagnieżdżonych repozytoriach i worktree.
Chcą Państwo hooków, które działają w Państwa repozytoriach?
Hooki, gate'y i CI konfigurujemy bezpośrednio w repozytorium zespołu w ramach AI-native SDLC dla zespołów deweloperskich. Państwa zespołowi brakuje raczej rąk do pracy niż reguł? Proszę zobaczyć seniora programistę dla Państwa zespołu. Większość naszego kodu pisze AI. Każdą zmianę sprawdza senior i to on odpowiada za produkcję. Od 2023 roku dostarczyliśmy ponad 15 projektów produkcyjnych.
Odezwiemy się w ciągu dwóch dni roboczych z kilkoma pytaniami o Państwa pracę. Potem ustalimy, czym zajmiemy się najpierw.
To polecenia powłoki, które Claude Code uruchamia przy zdarzeniach, np. PreToolUse przed wywołaniem narzędzia albo Stop, gdy agent chce skończyć. Hook dostaje zdarzenie jako JSON na stdin i decyduje kodem wyjścia lub odpowiedzią JSON.
Jak hook Claude Code blokuje polecenie?
Kodem wyjścia 2. Claude Code blokuje wtedy akcję i przekazuje agentowi jako powód to, co hook zapisał na stderr. Exit 0 ją przepuszcza. Każdy inny kod to błąd nieblokujący i agent pracuje dalej.
Dlaczego mój hook Claude Code się nie uruchamia?
Najczęściej przez ścieżkę względną, która nie istnieje w katalogu sesji, przez stderr odrzucany przez 2>/dev/null albo przez || true na końcu, które nadpisuje kod wyjścia. Proszę zaczynać ścieżkę od "$CLAUDE_PROJECT_DIR" i sprawdzać konfigurację hooków w CI.
Co oznacza stop_hook_active?
Ma wartość true, gdy agent już kontynuuje pracę, bo zablokował go hook Stop. Jeśli jest true, proszę od razu zakończyć. Inaczej test, którego agent nie potrafi naprawić, będzie go blokował bez końca.
Czy hook Stop wystarczy jako quality gate?
Nie. To wczesne ostrzeżenie w trakcie sesji. Te same testy proszę uruchomić ponownie w CI i w ochronie gałęzi, gdzie agent nie może ich zmienić.
Zapytaj AI o ten artykuł
AI przy odpowiedzi wykorzysta też nasze inne artykuły i doświadczenia z prawdziwych projektów.
Context engineering decyduje, co widzi agent AI piszący kod w trakcie pracy. Co trafia do AGENTS.md lub CLAUDE.md, które reguły ładują się tylko tam, gdzie obowiązują, jak zadanie staje się kontekstem i jak utrzymać całość w małym rozmiarze.
Playwright MCP daje agentowi AI prawdziwą przeglądarkę. Jak go używamy, żeby agent sprawdził własną zmianę w działającej aplikacji i oddał PASS lub FAIL ze zrzutami ekranu, co wychwytuje, a czego nie widzą testy jednostkowe, i kiedy lepszym narzędziem są zwykłe skrypty Playwright.
Jak uruchamiamy code review z Claude Code przy każdym pull requeście jedną wielokrotnego użytku GitHub Action: czego szuka recenzent AI, jak świecił na zielono i milczał, czego nie wyłapuje i dlaczego zatwierdza tylko człowiek.