Hooki Claude Code: dlaczego każdy z moich 95 hooków istnieje
Zbudowałem 95 hooków dla Claude Code. Każdy z nich istnieje, bo najpierw coś poszło nie tak. Hook git-safety-guardian istnieje, bo Claude wykonał force-push na main. Hook recursion-guard istnieje, bo subagent uruchomił nieskończoną liczbę procesów potomnych. Hook blog-quality-gate istnieje, bo opublikowałem post z 7 zdaniami w stronie biernej i wiszącym przypisem.1
TL;DR
Hooki Claude Code wykonują polecenia powłoki w określonych punktach cyklu życia podczas programowania wspomaganego przez AI. Hooki zapewniają deterministyczne gwarancje (blokowanie niebezpiecznych poleceń Git, wstrzykiwanie kontekstu, wymuszanie jakości) ponad probabilistycznym systemem (LLM). Po zbudowaniu 95 hooków w ramach mojej infrastruktury odkryłem, że najlepsze hooki powstają z incydentów, nie z planowania. Ten artykuł opisuje architekturę, historie powstania moich najważniejszych hooków oraz wzorce, których nauczyłem się przez 9 miesięcy ich tworzenia.
Architektura
Claude Code udostępnia zdarzenia cyklu życia, w których hooki mogą przechwytywać, modyfikować lub blokować zachowanie:2
Zdarzenia sesji
| Zdarzenie | Kiedy się uruchamia | Moje hooki |
|---|---|---|
| SessionStart | Rozpoczęcie nowej sesji | session-start.sh — wstrzykuje datę, waliduje venv, inicjalizuje stan rekurencji |
| SessionEnd | Zakończenie sesji | Czyszczenie plików tymczasowych |
Zdarzenia wykonania narzędzi
| Zdarzenie | Kiedy się uruchamia | Moje hooki |
|---|---|---|
| PreToolUse | Przed wykonaniem dowolnego narzędzia | git-safety-guardian.sh, recursion-guard.sh, credentials-check.sh |
| PostToolUse | Po zakończeniu działania narzędzia | post-deliberation.sh, log-bash.sh |
Zdarzenia odpowiedzi
| Zdarzenie | Kiedy się uruchamia | Moje hooki |
|---|---|---|
| UserPromptSubmit | Użytkownik wysyła prompt | Injektory kontekstu (data, gałąź, informacje o modelu) |
| Stop | Claude kończy odpowiedź | deliberation-pride-check.sh, reviewer-stop-gate.sh |
Każdy hook otrzymuje JSON na stdin i komunikuje się przez stdout:
{"decision": "block", "reason": "Force push to main is prohibited"}
Lub przepuszcza po cichu, kończąc się kodem wyjścia 0.3
Historie powstania: hooki, które mają największe znaczenie
Hook 1: git-safety-guardian.sh (PreToolUse:Bash)
Incydent: Podczas wczesnej sesji Claude Code poprosiłem agenta o „uporządkowanie historii Git”. Agent wykonał git push --force origin main. Force-push nadpisał trzy dni commitów na współdzielonej gałęzi. Odzyskałem dane z lokalnej kopii zapasowej, ale 4-godzinny proces odzyskiwania przekonał mnie, że probabilistyczna ocena nigdy nie powinna kontrolować destrukcyjnych operacji Git.
Hook:
#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
# Only check git commands
echo "$COMMAND" | grep -qE '\bgit\b' || exit 0
# Block force push to main/master
if echo "$COMMAND" | grep -qiE 'git\s+push\s+.*--force.*\b(main|master)\b'; then
cat << EOF
{"decision": "block", "reason": "Force push to main/master blocked by safety hook"}
EOF
fi
Wniosek: Hook nie próbuje zrozumieć intencji. Dopasowuje wzorce w ciągu polecenia. Prosto, deterministycznie, niemożliwe do obejścia przez sprytne promptowanie. Agent nadal może wykonać force-push na gałęzie feature (co bywa uzasadnione), ale main/master są trwale chronione.4
Przechwycone zagrożenia: 8 przechwyconych prób force-push w ciągu 9 miesięcy.
Hook 2: recursion-guard.sh (PreToolUse:Task)
Incydent: Podczas budowania systemu deliberacji uruchomiłem sesję, która utworzyła 3 subagentów eksploracyjnych. Każdy subagent, bez limitów tworzenia potomków, uruchamiał własne subagenty. Rekurencja pochłaniała tokeny API 10 razy szybciej niż normalnie. Ręcznie zakończyłem sesję po zauważeniu przyspieszającego zużycia tokenów.
Hook:
#!/bin/bash
CONFIG_FILE="${HOME}/.claude/configs/recursion-limits.json"
STATE_FILE="${HOME}/.claude/state/recursion-depth.json"
MAX_DEPTH=2
MAX_CHILDREN=5
DELIB_SPAWN_BUDGET=2
DELIB_MAX_AGENTS=12
# Validate integers safely (((VAR++)) crashes with set -e when VAR=0)
is_positive_int() {
[[ "$1" =~ ^[0-9]+$ ]] && [[ "$1" -gt 0 ]]
}
Kluczowa decyzja projektowa: Agenty dziedziczą budżet tworzenia potomków od rodzica, zamiast inkrementować głębokość. Agent główny z budżetem=12 może rozdzielić ten budżet na dowolną strukturę drzewa. Limity oparte na głębokości są zbyt sztywne (uniemożliwiają głębokie, ale wąskie łańcuchy, które są całkowicie bezpieczne).5
Zablokowane przypadki: 23 niekontrolowane próby tworzenia potomków.
Hook 3: blog-quality-gate.sh (Stop)
Incydent: Opublikowałem post na blogu z 7 zdaniami w stronie biernej, przypisem wspomnianym w tekście, ale brakującym w sekcji referencji, oraz „was implemented by the team” jako zdaniem otwierającym. Post wyglądał dopracowanie w edytorze, ale nie przeszedł podstawowych kontroli jakości, które wyłapałby każdy ludzki recenzent.
Hook: Uruchamia mój 12-modułowy linter blogowy na każdym zmodyfikowanym pliku treści bloga. Sprawdza stronę bierną, wiszące przypisy, brakujące meta-opisy, nieoznaczone bloki kodu i integralność cytowań. Każde znalezisko jest konkretne: „Linia 47: wykryto stronę bierną w ‘was implemented by the team.’ Sugestia: ‘the team implemented.’”
Analogia z informacją zwrotną od ludzi: Hook ocenia pracę, nie operatora. Mówi „linia 47 zawiera stronę bierną”, a nie „piszesz źle”. Ta sama zasada, która sprawia, że informacja zwrotna od ludzi jest konstruktywna, sprawia, że zautomatyzowana informacja zwrotna jest użyteczna.
Wzorzec stojący za 95 hookami
Architektura sterowana konfiguracją
Moje hooki ewoluowały od zakodowanych na stałe wartości do zachowania sterowanego konfiguracją:
~/.claude/configs/
├── recursion-limits.json # Depth, spawn budgets, timeouts
├── deliberation-config.json # Consensus thresholds per task type
├── consensus-profiles.json # security=85%, docs=50%
├── circuit-breaker.json # Failure mode configurations
└── file-scope-rules.json # Path-scoped hook application
Przeniesienie progów do konfiguracji JSON oznaczało, że mogłem dostrajać zachowanie bez edycji skryptów bash. Gdy potrzebowałem konsensusu na poziomie 85% dla bezpieczeństwa, ale 50% dla dokumentacji, zmiana konfiguracji zajęła 30 sekund. Zmiana w kodzie wymagałaby edycji, testowania i ponownego wdrożenia.6
Wzorzec warstwowy cyklu życia
Moje 95 hooków tworzy siatkę bezpieczeństwa o czterech warstwach:
Warstwa 1: Zapobieganie (PreToolUse) — Zatrzymanie złych rzeczy, zanim się wydarzą. git-safety-guardian, credentials-check, recursion-guard.
Warstwa 2: Kontekst (UserPromptSubmit, SessionStart) — Wstrzykiwanie informacji potrzebnych agentowi. Data, gałąź, kontekst projektu, wpisy pamięci, zasady filozofii.
Warstwa 3: Walidacja (PostToolUse) — Weryfikacja, czy wykonane akcje spełniają standardy. Sprawdzanie konsensusu post-deliberation, logowanie wyników.
Warstwa 4: Jakość (Stop) — Bramka końcowego wyniku. Pride check, bramka jakości, bramka recenzenckiego zatrzymania.
Każda warstwa jest niezależna. Jeśli hook PreToolUse zawiedzie po cichu, hook Stop nadal wyłapie problemy z jakością. Obrona w głąb, zastosowana do zachowania agenta AI.
Konfiguracja
Hooki znajdują się w .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"command": "~/.claude/hooks/git-safety-guardian.sh",
"timeout": 5000
}
],
"PreToolUse:Task": [
{
"command": "~/.claude/hooks/recursion-guard.sh"
}
]
}
}
Pole matcher filtruje, które narzędzia uruchamiają hook. PreToolUse:Task to skrót dla matchera, który uruchamia się tylko przy wywołaniach narzędzia Task. Hooki asynchroniczne (async: true) działają w tle bez blokowania.7
Hierarchia zakresów
- Poziom użytkownika (
~/.claude/settings.json) — dotyczy wszystkich projektów. Moje 95 hooków znajduje się tutaj. - Poziom projektu (
.claude/settings.json) — dodaje hooki specyficzne dla projektu. - Frontmatter skilli/subagentów — ograniczony do cyklu życia konkretnego komponentu.8
Co zrobiłbym inaczej
Zacząłbym od 3 hooków, nie 25. W pierwszym miesiącu powstało 25 hooków, z których wiele dodawało kontekst, który agent już posiadał. Narzut ładowania 25 hooków przy każdym wywołaniu narzędzia był mierzalny. Ostatecznie przyciąłem kolekcję do hooków, które dawały realną wartość (zapobiegały prawdziwym incydentom, wyłapywały realne problemy z jakością).
Konfiguracja sterowana od pierwszego dnia. Spędziłem dwa tygodnie na refaktoryzacji zakodowanych na stałe progów do konfiguracji JSON. Ten refaktoring byłby bezkosztowy, gdybym zaczął od konfiguracji.
Infrastruktura testowa od początku. Pierwsze 20 hooków nie miało testów. Gdy dodałem środowisko testowe (48 integracyjnych testów bash), znalazłem 3 hooki, które po cichu zawodziły w przypadkach brzegowych. Testy powinny były być dostarczane razem z hookiem nr 1.
Najważniejsze wnioski
Dla programistów zaczynających pracę z hookami: - Należy zacząć od trzech hooków: bezpieczeństwo Git (PreToolUse:Bash), wstrzykiwanie kontekstu (UserPromptSubmit) i bramka jakości (Stop); kolejne hooki warto dodawać dopiero wtedy, gdy pojawią się incydenty, które je uzasadniają - Warto skorzystać z frameworka czasowania decyzji: architektura hooków jest nieodwracalna (95 hooków od niej zależy), dlatego warto zainwestować w model cyklu życia przed pisaniem hooków
Dla zespołów standaryzujących hooki: - Hooki należy standaryzować na poziomie użytkownika, aby każdy członek zespołu otrzymał te same zabezpieczenia - Warto śledzić metryki hooków (zablokowane operacje, przechwycone incydenty), aby uzasadnić koszty utrzymania - Logi hooków powinny być przeglądane co miesiąc w celu identyfikacji nowych wzorców wartych zautomatyzowania
Referencje
-
Infrastruktura hooków autora. 95 hooków w 6 zdarzeniach cyklu życia, rozwijanych przez 9 miesięcy (2025-2026). ↩
-
Anthropic, “Claude Code Documentation,” 2025. Zdarzenia cyklu życia hooków. ↩
-
Anthropic, “Claude Code Documentation,” 2025. Format JSON wejścia/wyjścia hooków. ↩
-
git-safety-guardian.sh autora. 8 przechwyconych prób force-push śledzonych w
~/.claude/state/. ↩ -
recursion-guard.sh autora. Model dziedziczenia budżetu udokumentowany w
~/.claude/configs/recursion-limits.json. ↩ -
Architektura sterowana konfiguracją autora. 14 plików konfiguracyjnych JSON kodujących wszystkie progi i reguły hooków. ↩
-
Anthropic, “Claude Code Documentation,” 2025. Konfiguracja hooków i wykonanie asynchroniczne. ↩
-
Anthropic, “Claude Code Documentation,” 2025. Hierarchia zakresów hooków. ↩