Hooki agenta — jedyny sposób na wymuszenie 'za każdym razem X'
Q13 · Rozszerzalność Ile masz aktywnych hooków (Stop, PreToolUse, PostToolUse, SessionStart…)?
Odpowiedź na maksa: “5+ zorkiestrowanych: auto-PR-watch, fix-on-review, wystawianie narzędzi MCP wewnątrz hooków.”
Dlaczego to ma znaczenie w 2026
Dział zatytułowany „Dlaczego to ma znaczenie w 2026”Hooki to jedyne miejsce w setupie AI, gdzie reguły stają się gwarancjami. Wszystko inne — CLAUDE.md, pliki pamięci, system prompt, slash commandy — to sugestia, którą model może zastosować, sparafrazować albo po cichu zapomnieć sześć tur w głąb pętli. Hook działa na poziomie shella: uruchamia się bezwarunkowo, harness blokuje lub przepuszcza wywołanie na podstawie kodu wyjścia, model nie ma głosu. Jeśli łapiesz się na pisaniu w pamięci “zawsze odpalaj formatter po edycji” albo “za każdym razem gdy skończysz ficzer, otwórz PR” — nie potrzebujesz lepszego prompta, potrzebujesz hooka.
W 2026 powierzchnia hooków wreszcie dogoniła ambicje. Claude Code ma 12+ zdarzeń cyklu życia. Cursor ma taki sam zestaw eventów plus dwa własne — beforeShellExecution i beforeMCPExecution — pokrywające dwie najryzykowniejsze powierzchnie narzędzi. Codex CLI nadal trzyma się starszego zdarzenia notify, ale na początku 2026 wprowadził pełnoprawny system hooks.json. Mur między “co agent chce zrobić” a “co mu pozwalasz” stał się przepuszczalny na Twoją korzyść — ale tylko jeśli zbudujesz hooki.
Senior IC spędzający 4–8 godzin dziennie z agentami bez hooków traci 30–60 minut dziennie na rzeczy, które hooki załatwiają za darmo: re-uruchamianie formattera, naprawianie kolejności importów, łapanie literówek rm -rf zanim trafią na dysk, ręczne otwieranie PR po każdym ficzerze. Próg “5+ zorkiestrowanych” nie chodzi o liczenie dla efektu — to moment, gdy harness zaczyna usuwać całe kategorie babysittingu z dnia.
Jak naprawdę wygląda “maksymalny wynik”
Dział zatytułowany „Jak naprawdę wygląda “maksymalny wynik””Pełną punktację za Q13 dostajesz wyłącznie, gdy wszystkie cztery poniższe są prawdą:
- Co najmniej 5 hooków aktywnych w cyklu życia agenta. Nie 5 komend w jednym hooku — 5 oddzielnych wpisów odpalających się na różnych eventach (
SessionStart,UserPromptSubmit,PreToolUse,PostToolUse,Stoplub odpowiednikach Cursor). Realny rozkład, nie jeden przerośniętyPostToolUse. - Co najmniej jeden hook jest zorkiestrowany — ustawia stan, który czyta następny. Klasyczny przykład:
PostToolUsezapisuje znaczniki “feature complete”;Stopje czyta i jeśli warunki pasują, pushuje branch i otwiera PR. Skok z “hooka” do “stacka hooków.” - Co najmniej jeden hook bot/review-loop. Albo auto-PR-on-stop, albo fix-on-review (Stop hook odpytuje otwarty PR o nowe komentarze CodeRabbit/Copilot/człowieka i budzi agenta), albo
PostToolUsere-odpalający testy i pingujący na Slacku. Hooki zamieniające agenta w pracownika pracującego, gdy odchodzisz od klawiatury. - Co najmniej jeden hook dotyka MCP.
beforeMCPExecutionw Cursor to oczywisty przypadek, ale ten sam kształt działa w Claude Code —PreToolUsematcher namcp__*logujący do Honeycomb/Langfuse, wymagający zatwierdzenia dla serwerów wysokiego ryzyka (Stripe, GitHub-write, AWS) albo przepisujący wejście tool.
Cokolwiek mniej — “mam jeden Stop hook, który gra dźwięk” albo “skopiowałem security gate z tutoriala i zapomniałem o nim” — to środkowy tier w Q13.
Aktualny krajobraz (zweryfikowany web-searchem)
Dział zatytułowany „Aktualny krajobraz (zweryfikowany web-searchem)”Eventy hooków w Claude Code
Dział zatytułowany „Eventy hooków w Claude Code”Powierzchnia hooków Claude Code (oficjalne docs) jest najbogatsza wśród agentowych CLI w 2026. Eventy mają trzy częstotliwości:
- Raz na sesję:
SessionStart,SessionEnd— wstrzykiwanie kontekstu środowiskowego, rozgrzewka cache, logowanie metadanych, dźwięk gdy wracasz do klawiatury. - Raz na turę:
UserPromptSubmit,Stop,StopFailure,Notification.UserPromptSubmitto jedyny hook mogący zablokować lub wzbogacić prompt, zanim Claude go zobaczy.Stopodpala się przy zakończeniu generowania; może zapobiec zakończeniu i zmusić agenta do dalszej pracy. - Raz na wywołanie tool:
PreToolUse,PostToolUse,SubagentStopplus eventy MCP.PreToolUseto jedyny hook mogący twardo zablokować tool (exit 2);PostToolUsema wejście i odpowiedź tool na stdin.
Konfiguracja siedzi w ~/.claude/settings.json (globalna) albo .claude/settings.json (per-projekt, wcommitowana do repo). Realny kształt:
{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/deny-dangerous.sh" } ] }, { "matcher": "mcp__github__.*", "hooks": [ { "type": "command", "command": "echo \"GitHub MCP: $(jq -r '.tool_name')\" >> ~/.claude/logs/mcp-audit.log" } ] } ], "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/format-and-typecheck.sh" } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/auto-pr-watch.sh" } ] } ], "SessionStart": [ { "hooks": [ { "type": "command", "command": "echo \"session=$CLAUDE_SESSION_ID branch=$(git rev-parse --abbrev-ref HEAD)\" >&2" } ] } ] }}Pole matcher to regex puszczany na nazwę narzędzia (Bash, Edit, Write, Read, Glob, Grep, Task albo mcp__<server>__<tool> dla MCP). Exit 2 z PreToolUse blokuje tool wraz z feedbackiem do Claude; exit 0 przepuszcza; każdy inny kod jest błędem hooka, który Claude loguje, ale nie blokuje.
Hooki w Cursor (te same eventy + dwa dodatkowe)
Dział zatytułowany „Hooki w Cursor (te same eventy + dwa dodatkowe)”Cursor wdrożył hooki pod koniec 2025 z tymi samymi nazwami eventów co Claude Code, plus dwoma własnymi (docs Cursor):
beforeShellExecution— odpala się, zanim agent uruchomi jakąkolwiek komendę shell. Matcher leci na stringa komendy. UstawfailClosed: true, by blokować przy błędzie hooka.beforeMCPExecution— odpala się przed każdym wywołaniem MCP. Hook dostaje komendę serwera,tool_nameitool_inputw JSON. Najczystsze miejsce w setupie 2026 do audytu, gatingu lub przepisywania wywołań MCP — szczególnie dla Stripe, GitHub-write, AWS lub wszystkiego, co rusza pieniędzmi.
Konfiguracja Cursor siedzi w .cursor/hooks.json (projekt) lub ~/.cursor/hooks.json (globalna):
{ "hooks": { "beforeShellExecution": [ { "matcher": "rm -rf|DROP TABLE|kubectl delete", "command": "~/.cursor/hooks/deny-dangerous.sh", "failClosed": true } ], "beforeMCPExecution": [ { "matcher": "stripe.*", "command": "~/.cursor/hooks/require-approval.sh", "failClosed": true } ], "stop": [ { "command": "~/.cursor/hooks/auto-pr-watch.sh" } ] }}Od stycznia 2026 Cursor przeniósł hooki na in-process runner — 10–20× szybciej niż poprzedni model spawnujący shell — można wreszcie odpalać hooki robiące realną robotę (typecheck, lint, format) bez laga przy każdym tool.
Hooki w Codex CLI + legacy event notify
Dział zatytułowany „Hooki w Codex CLI + legacy event notify”Historia hooków w Codex CLI jest najmłodsza z trójki. Nadal wspiera legacy konfigurację notify (oryginalny “desktopowy toast, gdy agent skończy”) — ale na początku 2026 OpenAI wypuścił hooks.json obejmujący pięć eventów: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Stop. Kształt blisko odzwierciedla Claude Code, siedzi w ~/.codex/hooks.json lub .codex/hooks.json, a Codex przekazuje JSON na stdin / czyta JSON ze stdout. Legacy tablica notify w config.toml nadal działa dla wąskiego “fire-and-forget”:
notify = ["bash", "-lc", "terminal-notifier -title 'Codex' -message 'Task complete'"]Jeśli zaczynasz od zera w 2026, omiń notify i pisz hooks.json od razu. Jeśli już używasz notify, zostaw to w spokoju, ale dołóż nowy system na wierzch — koegzystują bez problemu.
Realne hooki warte odpalenia
Dział zatytułowany „Realne hooki warte odpalenia”Próg “5+ zorkiestrowanych” łatwo zbić, gdy zaczniesz od pięciu hooków, które zarabiają na siebie od pierwszego dnia:
1. Auto-format + typecheck po każdej edycji. PostToolUse matcher na Edit|Write odpalający formatter (Prettier/Biome/Ruff) i typechecker, oddający błędy do Claude. Agent zapomina o formatterze raz na ~5 edycji; hook usuwa kategorię.
#!/usr/bin/env bashset -ecd "$CLAUDE_PROJECT_DIR"npm run format -- --write 2>&1 | tail -20 >&2npm run type-check 2>&1 | tail -20 >&22. Blokowanie niebezpiecznych komend shell. PreToolUse matcher na Bash, który skanuje komendę pod kątem rm -rf /, DROP TABLE, kubectl delete -A, gh repo delete itd. i exituje 2, gdy coś takiego zobaczy.
#!/usr/bin/env bashcmd=$(jq -r '.tool_input.command' <<< "$(cat)")if echo "$cmd" | grep -qE 'rm -rf (/|~|\\$HOME)|DROP TABLE|kubectl delete -A|gh repo delete'; then echo "blocked: dangerous command pattern: $cmd" >&2 exit 2fiexit 03. Auto-PR-watch na Stop. Stop hook sprawdzający, czy working tree ma commity ponad origin/<default> i, jeśli tak, pushuje branch i otwiera PR przez gh. Najbardziej dźwigniowy hook w setupie — zamienia “kod napisany” w “kod dostarczony” bez konieczności pamiętania.
4. Fix-on-review na Stop. Ten sam Stop hook, drugi branch: jeśli otwarty PR ma nowe komentarze od ostatniej sygnatury, obudź agenta (przez asyncRewake albo re-prompt). Krok orkiestracji — hook czyta stan, który zapisał wcześniej.
5. Audyt MCP / gate zatwierdzeń. Albo PreToolUse w Claude Code z matcherem mcp__* logującym każde wywołanie, albo beforeMCPExecution w Cursor wymagający zatwierdzenia dla serwerów wysokiego ryzyka (Stripe, AWS, GitHub-write). Nawet czyste logowanie zwraca się przy pierwszym debugowaniu “dlaczego agent wywołał ten tool 80 razy?”.
To pięć hooków. Z auto-PR-watch i fix-on-review dzielącymi stan w ~/.claude/auto-pr-state/<hash>.json masz też “zorkiestrowane”. Dorzuć SessionStart i beforeMCPExecution gate na płatnościach — jesteś ponad progiem.
Krok po kroku: budowanie stacka hooków
Dział zatytułowany „Krok po kroku: budowanie stacka hooków”-
Wybierz dwa hooki, które zarabiają pierwszego dnia. Auto-format-on-edit i deny-dangerous-bash. Bezdyskusyjne, fail-safe, demonstrują wartość przed inwestycją w orkiestrację. Zwykłe skrypty shell w
.claude/hooks/. -
Podłącz je w
settings.json. Poziom projektu (.claude/settings.json, wcommitowany) dla hooków zespołowych; poziom użytkownika (~/.claude/settings.json) dla osobistych (Slack, dźwięki). Cursor odwzorowuje to z.cursor/hooks.jsoni~/.cursor/hooks.json. -
Zweryfikuj, że hooki się odpalają. W Claude Code uruchom
/hooks, by zobaczyć aktywną konfigurację. Wyzwól ręcznie każdy event: edycja pliku (PostToolUse), nieszkodliwa komenda bash (PreToolUse przepuszcza),rm -rf /tmp/test-bad(PreToolUse blokuje). Czytaj stderr — tak się je debuguje. -
Dodaj trzeci hook: auto-PR-watch na Stop. Wyznacz default branch przez
gh repo view --json defaultBranchRef --jq .defaultBranchRef.name— nigdy nie hardkodujmainanimaster. Hook sprawdza niespchniete commity, tworzy feature branch, jeśli jesteś na default, pushuje,gh pr create. Plik stanu (~/.claude/auto-pr-state/<repo-hash>.json) z ostatnim branch/PR/SHA. -
Dodaj czwarty hook: fix-on-review. Ten sam Stop hook, drugi branch: jeśli istnieje PR, odpytuj
gh pr view <PR#> --comments, API komentarzy inline igh pr checks <PR#>. Jeśli coś jest nowsze niż sygnatura, zakończ wiadomością budzącą Claude. -
Dodaj piąty hook: audyt MCP lub gate zatwierdzeń. Claude Code:
PreToolUsematcher namcp__*logujący do pliku albo POSTujący do observability. Cursor:beforeMCPExecutiongatingujący serwery wysokiego ryzyka (stripe.*,aws.*) za interaktywnym promptem, zfailClosed: true. -
Przetestuj orkiestrację jawnie. Pełny ficzer end-to-end: kod, commit, Stop hook otwiera PR, bot reviews landują, Stop hook budzi agenta, merge. Pętla powinna działać, gdy patrzysz, nie sterujesz. Napraw bugi — zorkiestrowane hooki padają w zaskakujący sposób pierwsze kilka razy.
-
Dodaj SessionStart hook do wstrzykiwania kontekstu. Tanie, użyteczne, podbija licznik: zaloguj metadane sesji, branch, git status do stderr, by trafiło do transkryptu. Dwie linie shella, natychmiastowy zwrot.
-
Udokumentuj stack w
CLAUDE.md. Powiedz przyszłemu sobie, co robią hooki, gdzie są, jak je wyłączyć. Nieudokumentowane hooki dostają winę, gdy odpalają się w zaskakujący sposób. -
Przeglądaj co kwartał. Hooki gniją. Formatter zmienia flagi, serwer MCP jest deprecjonowany,
ghwypuszcza breaking change. Co kwartał odpal każdy hook z known-good inputem.
Typowe pułapki
Dział zatytułowany „Typowe pułapki”- Brak obsługi błędów. Hook padający bez stderr to duch — Claude leci dalej (albo nie) i nie wiesz dlaczego. Każdy hook powinien
set -euo pipefaili drukować jednolinijkowe podsumowanie do stderr. - Drogie hooki na gorącej ścieżce.
PreToolUsenaBashzajmujący 4 sekundy to 4-sekundowy podatek od każdej komendy. Profiluj; >200ms na gorącym evencie przenieś gdzie indziej albo cache’uj. - Blokujące hooki bez timeoutu. Hook wiszący na sieci/zatwierdzeniu blokuje całą pętlę. Ustaw timeout (HTTP hooki Claude Code mają
timeout; command hooki owiń wtimeout 10s). Decyduj per hook: timeout = blok czy przepuść. - Nieskończone pętle między hookami. Stop hook re-promptujący agenta, który wyzwala kolejny Stop, to klasyczna pułapka. Bramkuj re-prompty sygnaturą
(branch, head_sha, max_comment_id); odpalaj tylko gdy się zmieniła. - Hooki wyciekające sekrety. Hooki widzą tool input/output na stdin — w tym sekrety. Nigdy nie
echouj payloadu do publicznego logu. Redaktuj znane wzorce (sk-…,ghp_…) najpierw. - Project hooki bez graceful degradation. Jeśli zespół wcommitował
.claude/settings.jsonz hookiem wołającympnpm, każdy bezpnpmma zepsuty setup. Wykrywaj brakujące zależności i pomijaj z warningiem. - Hooki walczące z agentem zamiast mu pomagać. Hook exitujący 2 na każdej edycji
src/to wyłączanie agenta. Hooki kodyfikują reguły prawie zawsze prawdziwe, nie wrażenie, że agentowi dziś nie można ufać.
Jak zweryfikować, że jesteś na poziomie
Dział zatytułowany „Jak zweryfikować, że jesteś na poziomie”- Potrafisz wymienić z pamięci co najmniej 5 hooków aktywnych w Twoim setupie i na którym evencie odpala się każdy z nich.
-
.claude/settings.json(albo~/.claude/settings.json) ma jawne wpisy na co najmniej 3 różnych eventach — nie 5 hooków upchniętych naPostToolUse. - Co najmniej jeden hook czyta stan, który zapisuje inny hook (auto-PR-watch + fix-on-review, albo session-start logger + stop reporter).
- Masz co najmniej jeden hook dotykający MCP — albo logujący wywołania
mcp__*w Claude Code, albobeforeMCPExecutiongate w Cursor. - Twój auto-PR albo auto-review hook w ciągu ostatnich 7 dni faktycznie otworzył PR albo zaadresował komentarz bota bez Twojej interwencji.
- Każdy hook ma stderr, który można przeczytać po jego odpaleniu, oraz politykę kodu wyjścia, którą umiesz opisać.
- Twoje hooki są udokumentowane w
CLAUDE.md(co robią, gdzie są, jak je wyłączyć). - Możesz wyłączyć dowolny hook w mniej niż 10 sekund (zakomentowanie bloku w
settings.json) i faktycznie zrobiłeś to raz, by coś zdebugować.