Preskočiť na obsah

Claude Code hooks: prečo naše hooky nerobili nič

Pre CTO a vývojárovHarness a kontroly · Aktualizované

Filip Papraneczakladateľ Digitaliko

Každý beh prešiel. Hook nerobil nič. Ilustrácia: súbor s nastaveniami, v ktorom príkaz hooku končí 2>/dev/null || true, vedľa radu zelených kontrol, ktoré nič nedokazujú.Každý beh prešiel. Hook nerobil nič. Ilustrácia: súbor s nastaveniami, v ktorom príkaz hooku končí 2>/dev/null || true, vedľa radu zelených kontrol, ktoré nič nedokazujú.

Tímy pridávajú Claude Code hooky, aby AI agenti nemohli narobiť škodu, a potom predpokladajú, že fungujú. Naše prechádzali pri každom behu a pritom nerobili nič. Hook, ktorý potichu nerobí nič, je horší než žiadny, lebo naň všetci prestanú pozerať. Oprava sú štyri lacné kontroly, ktoré si môže skopírovať každý tím.

Krátka odpoveď: hook stíchne, keď jeho výstup nikam nejde, keď jeho cesta neexistuje alebo keď niekto prepíše jeho exit kód. Všetky tri veci kontrolujte v CI. A hook, na ktorom záleží najviac, dajte na udalosť Stop, aby agent nemohol povedať „hotovo“, kým sú testy červené.

Ako Claude Code hooky vôbec niečo blokujú?

Hook je príkaz shellu, ktorý Claude Code spustí pri udalosti. PreToolUse beží pred volaním nástroja, Stop, keď chce agent skončiť. Príkaz dostane udalosť ako JSON objekt na stdin.

Rozhoduje exit kód:

  • Exit 0 pustí ďalej.
  • Exit 2 zablokuje. To, čo hook zapísal do stderr, ide späť agentovi ako dôvod.
  • Akýkoľvek iný kód je neblokujúca chyba. Claude Code pokračuje.

To je celá dohoda. Všetko, čo sa nám pokazilo, sa pokazilo vnútri nej.

Prečo naše hooky nerobili nič?

Dva hooky v našej firemnej konfigurácii mlčali týždeň, od prvého dňa. Tri príčiny, každá sama osebe neškodná:

  • Umlčaný. Oba písali svoju jedinú správu do stderr. Príkaz v nastaveniach končil 2>/dev/null. Agent nepočul ani slovo.
  • Chýbajúci. Oba používali relatívnu cestu. V session spustenej vo vnorenom repozitári cesta neexistovala. Exit 127, príkaz nenájdený.
  • Zamaskovaný. || true na konci zmenilo 127 na 0. Pri blokujúcej udalosti rovnako zmení 2 na 0. Každý beh „prešiel“.
Vľavo hook, ktorý mlčal: príkaz bash tools/hooks/guard.sh 2>/dev/null || true a tri príčiny: relatívna cesta (exit 127), stderr do /dev/null a || true, ktoré zmení exit kód na 0. Vpravo Stop hook v štyroch krokoch: stop_hook_active, spustí typecheck, lint a testy, pri červených vráti decision: block s logom chyby.Vľavo hook, ktorý mlčal: príkaz bash tools/hooks/guard.sh 2>/dev/null || true a tri príčiny: relatívna cesta (exit 127), stderr do /dev/null a || true, ktoré zmení exit kód na 0. Vpravo Stop hook v štyroch krokoch: stop_hook_active, spustí typecheck, lint a testy, pri červených vráti decision: block s logom chyby.

Nikto si to nevšimol, lebo hook, ktorý mlčí, vyzerá presne ako zdravý. Našli sme to až pri analýze vlastných Claude Code session.

Pokazený vzor, zjednodušene:

{ "type": "command", "command": "bash tools/hooks/guard.sh 2>/dev/null || true" }

Opravený, z nášho verejného startera:

{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/push-gate.sh" }

Ktoré štyri kontroly odhalia hook, ktorý mlčí?

Do nášho validátora sme pridali kontrolu, ktorá beží v CI našich repozitárov. Štyri grepy nad .claude/settings.json, nič sa nespúšťa:

KontrolaČo odhalíOprava
Skript existujeCestu, ktorá neexistuje"$CLAUDE_PROJECT_DIR"/... alebo absolútna cesta
Skript je spustiteľnýHook, ktorý beží len náhodouchmod +x
stderr sa nezahadzuje, keď doň skript píšeUmlčaný hookOdstrániť 2>/dev/null
PreToolUse hook nekončí || trueBlok prepísaný na prechodOdstrániť || true

Kontrolu sme otestovali na skutočnej chybe. Stará konfigurácia hlásila kritické chyby, opravená prešla.

Nie každé || true je chyba. Náš uvítací hook beží na SessionStart s 2>/dev/null || true naschvál. Pozdrav nesmie nikdy zhodiť session. Kontrola to hlási iba tam, kde sa čaká blok.

Ponaučenie v jednej vete, ako ho máme v hooku proti AI podpisom: „A rule is a request. This is the lock.“ Pravidlo je prosba, hook je zámok. A zámok potrebuje vlastný test.

Ešte nedávno mal agent pravidlá len v rules súboroch a niekedy ich nedodržal. Tak sme z nich spravili kontroly, ktoré sa nedajú obísť.

Filip Papranec
Filip Papranec
zakladateľ Digitaliko

Ktorý hook naozaj stráži?

Stop hook. Agent, ktorý povie „hotovo“, kým sú testy červené, stojí seniora jedno kolo review. Stop hook ho prinúti najprv to opraviť.

Naša verzia z verejného startera, mierne skrátená:

#!/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 0
cd "${CLAUDE_PROJECT_DIR:-.}" 2>/dev/null || exit 0
out=$(GATE_SKIP_INSTALL=1 GATE_SCRIPTS="typecheck lint test" bash scripts/gate.sh checks 2>&1) && exit 0
jq -n --arg r "Checks are red. Fix them before you say the task is done:
$out" '{decision: "block", reason: $r}'

Krok po kroku robí toto:

  1. Prečíta stop_hook_active

    Ak je true, agent už pokračuje kvôli tomuto hooku. Hook ho pustí, aby sa netočil donekonečna.

  2. Spustí kontroly

    Typecheck, lint a testy, tie isté ako v CI.

  3. Zablokuje s dôvodom

    Pri červených kontrolách vráti decision: block a ako dôvod log chyby.

  4. Agent opraví príčinu

    Prečíta log, opraví chybu a skúsi skončiť znova.

Blokuje JSON odpoveďou, nie exit kódom. Agent tak pracuje ďalej a dôvod, ktorý dostane, je presne to, čo zlyhalo.

Je to včasné varovanie, nie brána. V našej slučke agenta beží rozhodujúca kontrola znova po session, v kóde, na ktorý agent nedosiahne. Hook iba ušetrí jedno kolo.

Čo sa pokazilo v našom vlastnom Stop hooku?

Stop hook našej slučky mal vlastnú tichú chybu. Nastavoval pevný, minimálny PATH bez používateľských adresárov s nástrojmi, takže v repozitároch na Bune chýbali nástroje, ktoré kontroly potrebujú. Bránu navyše hľadal na jednom pevnom mieste, ktoré existovalo iba na stroji agenta. Jeden PR opravil oboje: plný PATH a hľadanie brány relatívne k samotnému hooku.

Claude Code hooky pre tím: kde začať?

Prejdite si, čo z toho vaše repozitáre už majú. Každý bod je pár riadkov v nastaveniach alebo v CI:

Najľahšie sa prehliadne tretí bod. Náš hook proti AI podpisom číta vstup cez jq, potom skúsi python3, potom sed. Chýbajúce jq nesmie zo zámku urobiť tiché povolenie. Relatívne cesty sa zas rozbijú vo vnorených repozitároch a worktree.

Začať môžete od Claude Code production startera: push gate, hľadanie tajomstiev a Stop hook, licencia MIT.

Kde majú hooky miesto vedľa súborov s pravidlami, rozoberáme v článku Pravidlá pre AI kód v tíme. Ako to zaviesť v celom tíme, je v článku Ako zaviesť AI do vývojového tímu. Čo smie agent bez opýtania a kedy je skip permissions bezpečné, je v článku Claude Code permissions.

Chcete hooky, ktoré vo vašich repozitároch naozaj držia?

Hooky, brány a CI nastavujeme priamo v repozitári tímu v službe AI-native SDLC pre vývojové tímy. Chýbajú vášmu tímu skôr ruky než pravidlá? Pozrite si seniorského vývojára do tímu. AI dnes píše všetok náš kód a za výsledok ručí senior. Od roku 2023 sme dodali 15+ produkčných projektov.

Ozveme sa do dvoch pracovných dní a spolu vyberieme, čo vyriešime ako prvé.

Ak sa chcete najprv porozprávať, dohodnite si meeting na 15 minút s Filipom.

Kedy ste naposledy overili, že vaše hooky ešte blokujú?

V skratke

  • Hook stíchne, keď sa jeho stderr zahodí, cesta neexistuje alebo || true prepíše exit kód.
  • Štyri grepy nad .claude/settings.json v CI odhalia všetky tri.
  • Stop hook nepustí „hotovo“, kým sú testy červené, a blokuje iba raz.
  • Rozhodujúca kontrola beží znova v CI, kde ju agent nemôže zmeniť.

Časté otázky

Čo sú Claude Code hooks?

Príkazy shellu, ktoré Claude Code spustí pri udalosti, napríklad PreToolUse pred volaním nástroja alebo Stop, keď chce agent skončiť. Hook dostane udalosť ako JSON na stdin a rozhodne exit kódom alebo JSON odpoveďou.

Ako Claude Code hook zablokuje príkaz?

Exit kódom 2. Claude Code vtedy akciu zablokuje a to, čo hook zapísal do stderr, vráti agentovi ako dôvod. Exit 0 ju pustí. Akýkoľvek iný kód je neblokujúca chyba a agent pokračuje.

Prečo môj Claude Code hook nebeží?

Najčastejšie pre relatívnu cestu, ktorá v adresári session neexistuje, pre stderr zahodený cez 2>/dev/null alebo pre || true na konci, ktoré prepíše exit kód. Cestu začnite "$CLAUDE_PROJECT_DIR" a konfiguráciu hookov kontrolujte v CI.

Čo znamená stop_hook_active?

Je true, keď agent už pokračuje preto, že ho Stop hook zablokoval. Keď je true, skončite hneď. Inak ho kontrola, ktorú agent nevie opraviť, blokuje donekonečna.

Stačí Stop hook ako brána kvality?

Nie. Je to včasné varovanie vnútri session. Tie isté kontroly pustite znova v CI a v ochrane vetvy, kde ich agent nemôže zmeniť.

Opýtajte sa AI na tento článok

AI pri odpovedi využije aj naše ďalšie články a skúsenosti z reálnych projektov.

ChatGPTClaudePerplexity
Engineering

Ostatné články

Harness a kontroly

Playwright MCP: AI agent overí zmenu v prehliadači

Playwright MCP dáva AI agentovi skutočný prehliadač. Ako ho používame, aby agent overil svoju zmenu v bežiacej aplikácii a vrátil PASS alebo FAIL so screenshotmi, čo tým chytíme oproti unit testom a kedy sú lepšie obyčajné Playwright skripty.

Harness a kontroly

LLM as a judge: AI recenzent, ktorý sa snaží prácu vyvrátiť

LLM as a judge znamená, že jazykový model hodnotí prácu iného modelu podľa spísaných kritérií. Ako ho používame na každom pull requeste nášho AI agenta: najprv strojové kontroly, potom čerstvá session len na čítanie, ktorá má prácu vyvrátiť, typovaný verdikt a pravidlá, ktoré pribudli po jeho chybách.

Harness a kontroly

AI code review s Claude Code v CI: čo AI prehliadne

Ako robíme AI code review s Claude Code na každom pull requeste jednou zdieľanou GitHub Action: čo má AI recenzent hľadať, ako bolo zelené a mlčalo, čo prehliadne a prečo schvaľuje len človek.

Čas prestať plánovať a začať riešiť.

Kontakt

  • Digitaliko s.r.o.
    Šípková 377/17
    958 03 Malé Uherce, Slovensko
  • Ozvite sa nám
    info@digitaliko.com
    +421 950 595 506
    WhatsApp