Przejdź do głównej zawartości
Claude Code Autor: 16 min czytania
Opublikowano:

Claude Code hooks po polsku, 10 praktycznych przykładów 2026

Hooks w Claude Code, tutorial PL: PreToolUse, PostToolUse, UserPromptSubmit, SessionStart. 10 gotowych hooków do skopiowania, antywzorce, troubleshooting.

Spis treści

Aktualizacja: wrzesień 2026. Hooks to najbardziej niedocenione feature Claude Code. Pozwalają zamienić CLI z "lepszego chatu z kodem" w prawdziwy agentic system z gwarancjami: brak destrukcyjnych komend, automatyczna formatowanie, custom validation, audit log. W tym tutorialu pokazuję 5 typów hooków, syntax w settings.json i 10 gotowych przykładów do skopiowania.

TL;DR, hooks w 5 punktach:

  • Programowalne triggery w określonych momentach sesji Claude Code
  • 5 najważniejszych eventów: PreToolUse, PostToolUse, UserPromptSubmit, Stop, SessionStart (dokumentacja opisuje ich znacznie więcej)
  • Konfiguracja w .claude/settings.json (per-projekt) lub ~/.claude/settings.json (global)
  • Komenda to dowolny shell (bash, python, node), dane dostaje jako JSON na stdin, exit code 2 blokuje akcję
  • Standard use case: blokuj rm -rf, auto-format po edytach, audit log

Czym są hooks w Claude Code

Hooks to konfigurowalne triggery uruchamiane w określonych momentach sesji Claude Code. Każdy hook to wpis w settings.json, który mówi: "kiedy stanie się X, wykonaj komendę Y". Jeśli Y zakończy się kodem 2, Claude Code zablokuje akcję X (na eventach, które da się blokować, np. PreToolUse).

Analogicznie do git hooków (pre-commit, post-receive), tylko że tutaj triggerami są nie operacje git, tylko operacje agenta: użycie narzędzia (PreToolUse / PostToolUse), wysłanie prompta (UserPromptSubmit), koniec odpowiedzi Claude (Stop), początek sesji (SessionStart).

Realnie hooks są tym, co zamienia Claude Code z "AI chat w terminalu" w prawdziwy system, który zatrzymuje agenta przed zrobieniem czegoś głupiego (jak rm -rf node_modules bez backup), albo automatyzuje workflow, którego inaczej trzeba pilnować ręcznie (jak format po każdej edycji).

5 najważniejszych typów hooków w Claude Code

5 najczęściej używanych eventów hooków, kiedy się uruchamiają
Typ hooka Kiedy się uruchamia Typowy use case
PreToolUse Przed wywołaniem narzędzia (Bash, Edit, Write) Blokuj destrukcyjne komendy, validation
PostToolUse Po wywołaniu narzędzia Auto-format, lint, generation derived files
UserPromptSubmit Gdy użytkownik wysyła prompt Wzbogacenie kontekstu (branch name, autor)
Stop Gdy Claude kończy odpowiedź (co turę; koniec całej sesji to osobny event SessionEnd) Uruchom testy, generuj summary, audit log
SessionStart Na początku sesji Ładuj env vars, sprawdzaj prereq

Konfiguracja w settings.json

Hooks definiujesz w .claude/settings.json w roocie projektu (per-projekt) lub ~/.claude/settings.json (globalnie). Format:

{
  "hooks": {
    "TypHooka": [
      {
        "matcher": "PatternMatcher",
        "hooks": [
          {
            "type": "command",
            "command": "shell command tutaj"
          }
        ]
      }
    ]
  }
}

matcher to filter, który decyduje, dla jakich narzędzi/promptów hook ma się uruchomić. Dla PreToolUse i PostToolUse matcher to nazwa narzędzia (Bash, Edit, Write, Glob, Grep, Read). Dla UserPromptSubmit i Stop matcher zazwyczaj jest pusty (uruchamia się zawsze).

Twój pierwszy hook, blokowanie rm -rf

Zacznijmy od najprostszego i najużyteczniejszego hooka, blokady niebezpiecznego rm -rf.

Plik .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "CMD=$(jq -r '.tool_input.command'); if echo \"$CMD\" | grep -qE 'rm -rf|sudo rm'; then echo 'BLOCKED: destructive rm command' >&2; exit 2; fi"
          }
        ]
      }
    ]
  }
}

Od teraz każda próba Claude'a użycia rm -rf w Bash kończy się blokadą: hook czyta JSON ze stdin (pole tool_input.command), a exit 2 plus komunikat na stderr "BLOCKED: destructive rm command" trafia do Claude, który przejdzie do alternatywnej strategii (np. git rm, mv do trash). Zmiany w pliku ustawień Claude Code zwykle wyłapuje automatycznie, bez restartu.

10 praktycznych hooków do skopiowania

1. Blokuj rm -rf i destrukcyjne bash

{
  "PreToolUse": [{
    "matcher": "Bash",
    "hooks": [{
      "type": "command",
      "command": "CMD=$(jq -r '.tool_input.command'); if echo \"$CMD\" | grep -qE 'rm -rf|sudo rm|chmod 000|dd if='; then echo 'BLOCKED destructive command' >&2; exit 2; fi"
    }]
  }]
}

2. Auto-format po Edit (Prettier / Ruff)

{
  "PostToolUse": [{
    "matcher": "Edit|Write",
    "hooks": [{
      "type": "command",
      "command": "FILE=$(jq -r '.tool_input.file_path'); if [[ \"$FILE\" == *.ts ]] || [[ \"$FILE\" == *.js ]]; then npx prettier --write \"$FILE\"; elif [[ \"$FILE\" == *.py ]]; then ruff format \"$FILE\"; fi"
    }]
  }]
}

3. Blokuj edit plików .env i secrets

{
  "PreToolUse": [{
    "matcher": "Edit|Write",
    "hooks": [{
      "type": "command",
      "command": "FILE=$(jq -r '.tool_input.file_path // empty'); if echo \"$FILE\" | grep -qE '\\.env|secrets|credentials|\\.pem$'; then echo 'BLOCKED: edit on secrets file' >&2; exit 2; fi"
    }]
  }]
}

4. Auto-uruchom testy, gdy Claude kończy odpowiedź (Stop)

{
  "Stop": [{
    "hooks": [{
      "type": "command",
      "command": "if [ -f package.json ]; then npm test --silent 2>&1 | tail -20; elif [ -f pyproject.toml ]; then pytest -q 2>&1 | tail -20; fi"
    }]
  }]
}

5. Dodaj branch i autor do każdego prompta (UserPromptSubmit)

{
  "UserPromptSubmit": [{
    "hooks": [{
      "type": "command",
      "command": "echo \"Kontekst: branch=$(git branch --show-current), autor=$(git config user.email)\""
    }]
  }]
}

6. Wymuszaj że każdy commit ma conventional commit prefix

{
  "PreToolUse": [{
    "matcher": "Bash",
    "hooks": [{
      "type": "command",
      "command": "CMD=$(jq -r '.tool_input.command'); if echo \"$CMD\" | grep -qE 'git commit'; then if ! echo \"$CMD\" | grep -qE '(feat|fix|chore|docs|refactor|test|style|perf|build|ci)(\\(.*\\))?:'; then echo 'BLOCKED: commit message must start with conventional prefix' >&2; exit 2; fi; fi"
    }]
  }]
}

7. Audit log wszystkich tool uses (PostToolUse)

{
  "PostToolUse": [{
    "hooks": [{
      "type": "command",
      "command": "jq -c '{t: (now | todate), tool: .tool_name, input: .tool_input}' >> .claude/audit.log"
    }]
  }]
}

8. SessionStart, sprawdź czy CLAUDE.md istnieje

{
  "SessionStart": [{
    "hooks": [{
      "type": "command",
      "command": "if [ ! -f CLAUDE.md ]; then echo 'Uwaga: w repo brak CLAUDE.md, zaproponuj /init'; fi"
    }]
  }]
}

9. Blokuj wywołania zewnętrznego curla do unknown domains

{
  "PreToolUse": [{
    "matcher": "Bash",
    "hooks": [{
      "type": "command",
      "command": "CMD=$(jq -r '.tool_input.command'); if echo \"$CMD\" | grep -qE '^curl '; then DOMAIN=$(echo \"$CMD\" | grep -oE 'https?://[^/ ]+' | head -1); ALLOWED='api.github.com|api.linear.app|api.anthropic.com'; if ! echo \"$DOMAIN\" | grep -qE \"$ALLOWED\"; then echo \"BLOCKED curl to: $DOMAIN\" >&2; exit 2; fi; fi"
    }]
  }]
}

10. PostToolUse, regeneracja plików derived (np. types z OpenAPI)

{
  "PostToolUse": [{
    "matcher": "Edit|Write",
    "hooks": [{
      "type": "command",
      "command": "FILE=$(jq -r '.tool_input.file_path'); if [[ \"$FILE\" == *openapi.yaml ]] || [[ \"$FILE\" == *schema.prisma ]]; then npm run generate --silent 2>&1 | tail -10; fi"
    }]
  }]
}

Matchery i tool patterns

Matcher dla PreToolUse i PostToolUse to nazwa narzędzia. Możesz użyć pipe | żeby objąć kilka narzędzi: "matcher": "Edit|Write". Najczęstsze nazwy:

  • Bash, wywołania shell
  • Edit, edycja istniejącego pliku
  • Write, utworzenie nowego pliku
  • Read, odczyt pliku
  • Glob, szukanie plików po wzorze
  • Grep, szukanie w treści plików
  • WebFetch, fetch URL
  • WebSearch, search web

Dla MCP tools matcher to mcp__<server_name>__<tool_name>, np. mcp__github__create_issue.

Dane wejściowe hooka (JSON na stdin)

Claude Code nie przekazuje kontekstu operacji w zmiennych środowiskowych, tylko jako JSON na standardowe wejście (stdin) hooka. Najważniejsze pola:

  • session_id, cwd, hook_event_name, transcript_path, wspólne dla wszystkich eventów
  • tool_name, nazwa narzędzia (np. "Bash", "Edit"), w PreToolUse i PostToolUse
  • tool_input, wejście narzędzia, np. tool_input.command dla Bash albo tool_input.file_path dla Edit/Write
  • tool_response, wynik narzędzia (tylko w PostToolUse)

W skrypcie hooka czytasz je przez jq, np. CMD=$(jq -r '.tool_input.command'). Ze zmiennych środowiskowych dostępne są m.in. $CLAUDE_PROJECT_DIR (katalog projektu), przydatny do ścieżek do skryptów hooków.

Antywzorce, czego unikać

  1. Zbyt rygorystyczne blokady, jeśli zablokujesz rm całkowicie, Claude nie usunie node_modules przed reinstall. Bądź selektywny (rm -rf na critical paths).
  2. Slow hooks, hook PreToolUse który trwa 5s blokuje każdą operację o 5s. Trzymaj hooki pod 1s. Wszystko cięższe (testy, lint full) → Stop hook.
  3. Niedeterministyczne hooks, hook który czasem fail, czasem pass = nieprzewidywalny Claude. Każdy hook powinien być reprodukowalny.
  4. Brak echo w blokadach, jeśli blokujesz coś, zawsze drukuj wyjaśnienie na stderr i kończ kodem 2, wtedy trafi do Claude jako powód blokady.
  5. Hardcoded paths, używaj zmiennych env i $(pwd), hook ma działać niezależnie od lokalizacji.

Troubleshooting

Najczęstsze problemy z hookami i jak je naprawić:

  • Hook nie odpala się, sprawdź syntax JSON (npx jsonlint .claude/settings.json). Najczęstsza przyczyna 90% problemów.
  • Hook nie blokuje, choć powinien, sprawdź, czy kończy się exit 2 (exit 1 to błąd nieblokujący), i zapisz wejście do pliku (cat > /tmp/hook-input.json), żeby zobaczyć, jakie pola naprawdę dostajesz.
  • Hook za wolny, profiluj time <komenda>. Sprawdź czy używasz cache (npm install, prettier --check zamiast --write na dużej liście plików).
  • Permission denied, hook to dowolny shell, więc musi być wykonywalny. Skrypty Python/Node potrzebują shebang lub explicit interpreter.
  • Logi nigdzie nie idą, uruchom Claude Code z flagą --debug, log sesji trafia do ~/.claude/debug/.

Co dalej

Hooks to początek. Pełen workflow z Claude Code to hooks + slash commands + MCP servers + Agent SDK + Anthropic API. Każda warstwa ma swoją niszę:

Hooks template pack w kursie

W Kursie Claude Code po polsku (349 zł brutto, 220 stron PDF, dożywotni dostęp) dostajesz pack 10 production-ready hooków + dokumentację każdego + repo GitHub template. Plus moduł 4 dedykowany hookom (25 stron) z deeper dive niż ten artykuł.

Zobacz pełny program kursu, 349 zł →

Najczęściej zadawane pytania

Co to są hooks w Claude Code?

Hooks to konfigurowalne triggery uruchamiane w określonych momentach sesji Claude Code, np. przed użyciem narzędzia (PreToolUse), po edycji pliku (PostToolUse), gdy użytkownik wysyła prompt (UserPromptSubmit), gdy Claude kończy odpowiedź (Stop), na początku sesji (SessionStart). Dokumentacja opisuje też dziesiątki innych eventów, m.in. SessionEnd, PreCompact, SubagentStop i Notification. Pozwalają automatyzować workflow, blokować destrukcyjne komendy, dodawać validację i kontekst.

Gdzie zapisuje się konfigurację hooków?

W pliku .claude/settings.json w roocie projektu (per-projekt) lub ~/.claude/settings.json (globalnie). Zmiany w hookach w plikach ustawień Claude Code zwykle wyłapuje automatycznie (file watcher), bez restartu sesji.

Czy hooks blokują komendy?

Tak. Blokuje exit code 2: jeśli hook PreToolUse zakończy się kodem 2, Claude Code nie wykona narzędzia, a tekst ze stderr trafi do Claude jako powód blokady. Inne niezerowe kody (np. exit 1) to błąd nieblokujący, akcja idzie dalej. Alternatywnie hook może zwrócić na stdout JSON z permissionDecision: deny.

Jakie są typowe use case dla hooków?

Pięć najczęstszych: 1) Blokuj rm -rf i inne destrukcyjne komendy. 2) Auto-formatuj kod po każdej edycji (Prettier, ruff). 3) Dodawaj kontekst do każdego prompta (np. nazwa branchu, autor). 4) Uruchamiaj testy automatycznie, gdy Claude kończy odpowiedź. 5) Loguj wszystkie tool uses do audytu.

Czy hook może modyfikować input narzędzia?

Tak, dla niektórych typów hooków. PreToolUse może zatrzymać wywołanie (exit 2 albo JSON z decyzją). UserPromptSubmit i SessionStart mogą dodać kontekst: zwykły tekst wypisany na stdout trafia do kontekstu Claude (np. aktualna gałąź gita). PostToolUse działa po fakcie, narzędzie już się wykonało.

Czy hooks działają w Claude Code w CI?

Tak, ale wymaga uwagi. W CI Claude Code jest uruchamiany headless (claude -p albo Claude Agent SDK), więc hooks muszą być deterministyczne i nie zależeć od interaktywnego inputu. Też pamiętaj o env vars i sciezkach absolutnych.

Jak debugować hook który nie działa?

1) Uruchom Claude Code z flagą --debug, log sesji trafia do ~/.claude/debug/. 2) Zapisz wejście hooka do pliku (cat > /tmp/hook-input.json) i sprawdź, jakie pola dostajesz na stdin. 3) Pamiętaj, że blokuje tylko exit 2, nie exit 1. 4) Sprawdź syntax JSON w settings.json (najczęstsza przyczyna).

Czy mogę użyć hooków Python / Node zamiast bash?

Tak. Komenda w hooku to dowolne wywołanie shell, więc python ./hooks/validate.py lub node ./hooks/check.js działają normalnie. Pamiętaj, że hook dostaje dane jako JSON na stdin, powinien być szybki (typowo < 1 s) i zwracać exit code (0 OK, 2 blokada).

Czy hooks działają z Claude Agent SDK?

Tak, Agent SDK też obsługuje hooki, szczegóły konfiguracji (hooki w kodzie albo wczytanie plików ustawień) opisuje dokumentacja SDK.

Czy są gotowe hooki do pobrania?

Tak. W Kursie Claude Code po polsku dostajesz pack 10 gotowych hooków template (deny destructive, auto-format, pre-commit lint, custom validation, session start init). Inne hooki znajdziesz w Anthropic docs i community repo.

Jak wyłączyć tymczasowo hook?

Najprościej ustawić "disableAllHooks": true w settings.json albo jednorazowo przy starcie: claude --settings '{"disableAllHooks": true}'. Osobnej flagi --disable-hooks nie ma. Hooków zarządzanych przez organizację (managed) nie wyłączysz z ustawień użytkownika.

Czy hook może być asynchroniczny?

Standardowo Claude Code czeka na zakończenie hooka (domyślny timeout dla hooków typu command to 600 s). Jeśli potrzebujesz pracy w tle, zrób fire-and-forget (command &) z pełną świadomością, że jego rezultat nie wpłynie na sesję.

Chcesz opanować Claude Code i agentic coding?

220 stron PDF dla developerów i osób bez kodu. Dożywotni dostęp.

349 zł
Zobacz kurs Claude Code →