Hooks v Claude Code: nastavení a 7 praktických příkladů
Markdown7 připravených háčků pro .claude/settings.json ke zkopírování a vložení: ochrana .env, prettier, force-push do main, dlouhé pomlčky a vývojový server. 4 typy obsluhy a 31 událostí.
Přečíst celý článek
Háčky v Claude Code jsou shellové příkazy, volání HTTP nebo krátké kontroly pomocí LLM, které se automaticky spustí před akcí Claude nebo po ní. Přidávají kontroly konkrétních událostí nástrojů, formátování po úpravě a aktuální kontext při zahájení relace. Odpovídající hook PreToolUse může odmítnout dané volání; tyto regex příklady jsou pomocné pojistky, nikoli bezpečnostní hranice všech přístupů k souborům či Gitu. Následuje přehled 4 typů obsluhy, 31 událostí životního cyklu, test „kdy pravidlo patří do háčku“, 7 háčků ke zkopírování do .claude/settings.json a 3 úskalí, na která jsem narazil.
Dokumentace Ailoot: API, klíče a nastavení.
Co jsou hooks v Claude Code?
Hlavní poznatek
Háček je shellový příkaz, volání HTTP, krátké zadání pro LLM nebo subagent, který Claude Code spustí v reakci na konkrétní událost životního cyklu. Na rozdíl od pokynů v CLAUDE.md, které model může ignorovat nebo zapomenout, se háček spustí pokaždé stejně: je to kód, ne doporučení.
Půl roku jsem měl pravidlo „nikdy neupravuj .env přímo“ v CLAUDE.md. Claude ho jednou měsíčně porušil. Ne ze zlého úmyslu; na konci dlouhé relace ho jednoduše zapomněl. Jednou se do .env dostal přebytečný token, jindy proměnná s duplicitním názvem přepsala tu používanou.
Přesunul jsem toto pravidlo do háčku, takže ho už nelze zapomenout. Když odpovídající nástroj přímé úpravy předá cestu .env, nastavený hook toto volání odmítne. Přesměrování Bash, skripty, nástroje MCP a další cesty potřebují samostatné kontroly; příklad nečiní soubor neměnným.
Háčky jsou shellové příkazy, koncové body HTTP nebo zadání pro LLM, které definujete a která se automaticky spouštějí v konkrétních okamžicích životního cyklu Claude Code.
Jinými slovy, háček je váš příkaz, který Claude Code spustí při konkrétní události. Každá úprava souboru, spuštění Bash, začátek relace nebo dokončení subagenta je událost, ke které můžete háček přiřadit.
Proč je to důležité pro vibe codera:
- Chraňte soubory obsahující tajné údaje před náhodnými úpravami.
- Po každém generování kódu automaticky spusťte prettier/eslint.
- Bez výslovného svolení blokujte
git push --forcedo main. - Vložte aktuální kontext na začátku každé relace.
- Zaznamenávejte akce Claude pro účely auditu.
CLAUDE.md zajišťuje kontext. Háčky zajišťují akce. Jde o dvě různé věci a jejich zaměňování je hlavní začátečnická chyba.
V čem se háčky liší od CLAUDE.md a dovedností?
Hlavní poznatek
CLAUDE.md je text, který model čte na začátku relace a snaží se jím řídit. Háček je shellový příkaz, který proces Claude Code spustí v reakci na událost, nezávisle na modelu. Dovednost je pojmenovaný balíček pokynů, který Claude může vyvolat nástrojem Skill, podobně jako funkci. Každý z těchto tří prvků slouží k jinému typu úloh.
Dokumentace Anthropic výslovně vysvětluje rozdíl mezi CLAUDE.md a háčky:
Obsah CLAUDE.md se předává jako uživatelská zpráva po systémovém promptu, nikoli jako součást systémového promptu. Claude si ho přečte a snaží se jím řídit, ale jeho přísné dodržování není zaručeno.
Jinými slovy, obsah CLAUDE.md se ke Claudovi dostane jako první zpráva od uživatele, nikoli jako systémový pokyn. Model si ho přečte a pokusí se jím řídit. Nic ale není zaručeno, zvlášť ke konci dlouhé relace, kdy kontext narůstá a starší pokyny se vytlačují.
Háček funguje jinak. Je uložený v settings.json, nezávisí na modelu a proces Claude Code ho spustí při konkrétní události: PreToolUse, PostToolUse, SessionStart a dalších. V PreToolUse může příkaz odmítnout odpovídající volání před akcí; PostToolUse běží až po ní a může poskytnout zpětnou vazbu či následnou úpravu, nikoli vrátit původní zápis.
Srovnání:
| Funkce | CLAUDE.md | Háček | Dovednost |
|---|---|---|---|
| Kde se nachází | CLAUDE.md v kořenovém adresáři projektu | .claude/settings.json | Složka .claude/skills/ |
| Kdo jej spouští | Model jej čte jako součást uživatelské zprávy | Proces Claude Code při události | Model prostřednictvím nástroje Skill |
| Záruka spuštění | Ne (podle nejlepšího úsilí) | Nastavený odpovídající command hook vykoná kód; chyby a ukončení závisejí na události | Prostřednictvím volání modelu (s oprávněním, ale ne na úrovni shellu) |
| K čemu slouží | Kontext projektu, tón, styl, směrování | Omezení, formátování, kontroly konkrétních souborů | Složité vícekrokové postupy s parametry |
| Kdy se spouští | Při každé zprávě modelu v relaci | Při události životního cyklu | Když jej model vyvolá |
| Může zablokovat akci? | Ne | U odpovídajícího PreToolUse; PostToolUse již provedenou akci nevrací | Ne |
Celou šablonu CLAUDE.md a 6 pravidel pro živý soubor najdete v průvodci Jak nastavit CLAUDE.md v roce 2026: připravená šablona a 6 pravidel. O dovednostech jako pojmenovaných schopnostech se dozvíte v článku Dovednosti Claude Code: jak si vytvořit vlastní knihovnu.
Háček je nejnižší úroveň: žádný model, žádná interpretace, jen shell.
Háčky jsou jedním z nástrojů inženýrství kontextu, vedle Plan Mode a /compact.
4 typy háčků: Command, HTTP, Prompt, Agent – který zvolit?
Hlavní poznatek
Claude Code má 4 typy obsluhy. Command je shellový skript a nejběžnější typ. HTTP odešle požadavek POST na vaši adresu URL; hodí se pro týmy a integrace. Prompt provede krátké volání Haiku pro sémantickou kontrolu. Agent vytvoří subagenta s přístupem k nástrojům pro hloubkovou validaci. Začátečníkům stačí Command a Prompt; pokryjí 90 % úloh.
| Typ | Co dělá | Kdy jej zvolit | Složitost |
|---|---|---|---|
| Command | Spustí shellový příkaz, přijímá JSON přes stdin a odpovídá návratovým kódem a stdout | 90 % případů: kontrola cest, formátování, grep v obsahu, lsof, operace git | nízká |
| HTTP | Odešle požadavek POST s tělem JSON na vaši adresu URL a přijme odpověď JSON | Když pravidlo patří týmu/CI: centralizovaná validace, sdílený stavový panel, vzdálený audit | střední (vyžaduje server) |
| Prompt | Odešle krátké zadání do Haiku (ve výchozím nastavení) a získá odpověď ano/ne pro sémantické posouzení | Když grep nestačí: „posuď, zda tento text zní korporátně“ | nízká |
| Agent | Vytvoří subagenta s přístupem Read/Grep/Glob pro vícekrokové kontroly | Náročná validace: „najdi všechny změněné soubory a ověř, že k nim existují odpovídající testy“ | vysoká |
Nejčastější chybou je snažit se pomocí Command vyřešit úlohu, pro kterou je potřeba Prompt. Například „nepoužívej dlouhé pomlčky v souborech .md“ je úloha pro grep, takže se hodí Command. Ale „nepiš korporátním tónem“ je sémantická úloha, a proto potřebuje Prompt.
Pokud teprve začínáte, použijte Command. Všech 7 připravených háčků níže je typu Command. HTTP/Prompt/Agent přijdou na řadu později, až budete připraveni.
Kde je settings.json a jaké jsou 4 úrovně konfigurace?
Hlavní poznatek
Claude Code hledá konfiguraci na 4 místech: enterprise (nasazení přes MDM), uživatelská (~/.claude/settings.json), projektová (.claude/settings.json v kořenovém adresáři repozitáře) a místní (.claude/settings.local.json, není v git). Všechny 4 soubory se sloučí při zahájení relace, přičemž přednost má nižší úroveň.
| Úroveň | Cesta | Kdy se uplatní | V git? |
|---|---|---|---|
| Enterprise | /Library/Application Support/ClaudeCode/settings.json (Mac), /etc/claude-code/settings.json (Linux) | Pro celý tým přes MDM | ne |
| Uživatelská | ~/.claude/settings.json | Všechny projekty jednoho uživatele | ne |
| Projektová | .claude/settings.json v kořenovém adresáři repozitáře | Tento projekt, pro celý tým | ano |
| Místní | .claude/settings.local.json | Jen tento projekt, jen tento uživatel | ne (v .gitignore) |
Všech 7 níže popsaných háčků uchovávám v projektovém .claude/settings.json, takže se automaticky zahrnou při naklonování repozitáře a Claude se řídí stejnými pravidly i v novém okně. Osobní experimentální háčky patří do .claude/settings.local.json, aby nepřekážely týmu.
Všechny 4 soubory se sloučí při zahájení relace. Pokud si pravidla odporují, přednost má nižší úroveň (místní před projektovou, projektová před uživatelskou).
Nejrychlejší způsob, jak vytvořit první háček, je interaktivní nabídka /hooks přímo v Claude Code. Vyberte událost ze seznamu, zvolte filtr (například Bash nebo Edit) a vložte příkaz. Claude Code za vás zapíše platný JSON do settings.json.
31 událostí životního cyklu: které potřebují začátečníci?
Hlavní poznatek
Claude Code má aktuálně 31 událostí životního cyklu rozdělených do 3 frekvencí: jednou za relaci (SessionStart/SessionEnd), jednou za tah (UserPromptSubmit/Stop) a při každém volání nástroje (PreToolUse/PostToolUse). Začátečníci potřebují 4 z 31 událostí: PreToolUse pro omezení, PostToolUse pro automatické úpravy, SessionStart pro kontext a Stop pro závěrečné kontroly.
Události nastávají ve třech frekvencích: jednou za relaci (SessionStart, SessionEnd), jednou za tah (UserPromptSubmit, Stop, StopFailure) a při každém volání nástroje v agentní smyčce (PreToolUse, PostToolUse).
Je důležité porozumět těmto třem frekvencím, abyste v nich neměli zmatek:
- Jednou za relaci -
SessionStart,SessionEnd,Setup. Spustí se jednou při otevření a zavření Claude Code. Použijte je k inicializaci kontextu a úklidu dočasných souborů. - Jednou za tah -
UserPromptSubmit,UserPromptExpansion,Stop,StopFailure. Spustí se při každé vaší zprávě a pokaždé, když se model zastaví. Použijte je k zaznamenání konverzace a závěrečné kontrole výsledku. - Při každém volání nástroje -
PreToolUse,PostToolUse,PostToolUseFailure,PermissionRequest,PermissionDenied,PostToolBatch,SubagentStart,SubagentStop. Spustí se při každé úpravě souboru, spuštění Bash, čtení nebo hledání. Jde o nejvytíženější vrstvu, ve které se uplatňují omezení, formátování a validace.
Úplný seznam 31 událostí zahrnuje asynchronní/reaktivní události: TeammateIdle, PreCompact, PostCompact, Elicitation, ElicitationResult, InstructionsLoaded, ConfigChange, CwdChanged, FileChanged, WorktreeCreate, WorktreeRemove, Notification. Ty jsou pro pokročilé případy; zatím je přeskočte.
Test s pěti otázkami: kdy patří pravidlo do háčku a kdy zůstává v CLAUDE.md?
Hlavní poznatek
Pokud se pravidlo týká akce (nikoli kontextu), souvisí s bezpečností/penězi/datovými údaji, lze ho ověřit pomocí grep/regex, je těžké napravit jeho porušení a Claude ho už alespoň jednou porušil, patří do háčku. Pokud jsou méně než tři z těchto pěti odpovědí „ano“, zůstává v CLAUDE.md. Ověřil jsem tak svých 80 řádků a 5 pravidel přesunul do háčků.
Mně to funguje jako zákon, ne jako doporučení. Rozhodování mezi CLAUDE.md a háčkem jsem zjednodušil na test s pěti otázkami. Pokud jsou alespoň tři odpovědi „ano“, pravidlo patří do háčku. Při méně než třech zůstává v textu.
Test „kdy patří pravidlo do háčku?“:
- Týká se toto pravidlo akce, nikoli kontextu? („nespouštěj
rm -rf“ je akce; „mám projekt v TypeScriptu“ je kontext.) - Týká se pravidlo bezpečnosti, peněz nebo dat? („nesahej na
.env“, „nezveřejňuj klíče“.) - Lze ho ověřit pomocí grep, regexu nebo návratového kódu shellového příkazu? („po úpravě
.mdzkontroluj, že v něm není dlouhá pomlčka“.) - Bylo by obtížné napravit následky porušení pravidla? („force-push do main“ se napravuje obtížně; „zapomenutá tečka na konci“ snadno.)
- Viděli jste už alespoň jednou, že Claude toto pravidlo zapomněl?
Příklad: „Nepoužívej dlouhé pomlčky; používej jen spojovníky.“ Akce? Ano. Bezpečnost? Ne. Lze ověřit pomocí grep? Ano. Je náprava obtížná? Ne. Viděli jste porušení? Ano. 3 z 5: vložte to do háčku.
Protipříklad: „Pracuji s vibe codery, ne vývojáři; piš bez slangu.“ Akce? Spíš kontext. Bezpečnost? Ne. Lze ověřit regexem? Příliš obtížně. Je náprava obtížná? Ne. Viděli jste porušení? Ano. 1 z 5: ponechte v CLAUDE.md.
Testem prošlo pět mých pravidel. Přesunul jsem je do háčků. Zbývajících 75 % zůstalo v textovém souboru.
7 háčků ke zkopírování
Hlavní poznatek
Níže je 7 připravených háčků pro .claude/settings.json: blokování úprav .env, automatické spuštění prettier, zabránění force-pushi do main, kontrola dlouhých pomlček, uvolnění portu před npm run dev, automatický commit po úspěšných testech a vložení aktuálního kontextu při zahájení relace. Zkopírujte každý z nich do souboru, restartujte Claude Code a funguje to.
Všech 7 háčků je uložených v jednom souboru .claude/settings.json v kořenovém adresáři projektu. Každá položka obsahuje typ události, filtr nástroje (matcher) a shellový příkaz. Exit code 2 odmítne odpovídající PreToolUse před vykonáním. U PostToolUse již akce proběhla: hook poskytuje zpětnou vazbu a nemůže ji vrátit.
U většiny událostí háčků blokuje akci pouze návratový kód 2. Claude Code považuje návratový kód 1 za neblokující chybu a v akci pokračuje, přestože v Unixu 1 obvykle znamená selhání.
exit 0 znamená úspěch. exit 1 znamená chybu, ale Claude pokračuje (jde o první anti-vzor níže). exit 2 má chování podle události: může blokovat PreToolUse, zatímco PostToolUse jen předává zpětnou vazbu k již provedené akci.
Háček 1. Kontrolujte přímé úpravy .env (PreToolUse, exit 2)
Blokuje pokusy přímo upravit libovolný soubor odpovídající .env, .env.local, .env.production a podobně.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // empty'); [ -z \"$FILE\" ] && exit 0; echo \"$FILE\" | grep -qE '(^|/)\\.env(\\.|$)' && { echo 'Do not edit `.env` directly. Tell me which variable to add, and I’ll open the file myself.' >&2; exit 2; } || exit 0"
}
]
}
]
}
}
Co dělá: Před každou operací Edit/Write/MultiEdit získá cestu k souboru, pomocí grep ověří, zda odpovídá vzoru .env, a pokud ano, vrátí exit 2 se zprávou. Claude uvidí stderr a řekne mi: „Pokusil jsem se upravit .env, ale háček mě zablokoval; řekněte mi, kterou proměnnou mám přidat.“
Háček 2. Po každé úpravě kódu automaticky spusťte prettier (PostToolUse, exit 0)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // empty'); [ -z \"$FILE\" ] && exit 0; echo \"$FILE\" | grep -qE '\\.(ts|tsx|js|jsx|json)$' && npx prettier --write \"$FILE\" 2>/dev/null & exit 0"
}
]
}
]
}
}
Co dělá: Po každé operaci Edit/Write získá cestu a pokud má soubor příponu .ts/.tsx/.js/.jsx/.json, spustí prettier na pozadí pomocí &. Vždy skončí s kódem 0, protože jde o formátování, nikoli omezení. Když prettier selže, nic hrozného se nestane; soubor zůstane tak, jak byl.
Rozdíl oproti háčku 1 je zásadní: PreToolUse + exit 2 je tvrdá blokace před akcí. PostToolUse + exit 0 je měkká úprava po akci. Jde o dva různé režimy pro různé úlohy.
Háček 3. Blokujte git push --force do větve main (PreToolUse, exit 2)
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "CMD=$(jq -r '.tool_input.command // empty'); [ -z \"$CMD\" ] && exit 0; echo \"$CMD\" | grep -qE 'git[[:space:]]+push' && echo \"$CMD\" | grep -qE '(\\-\\-force|\\-\\-force-with-lease|[[:space:]]-f([[:space:]]|$))' && echo \"$CMD\" | grep -qE '([[:space:]/:])main([[:space:]/:]|$)' && { echo 'Force push to main is forbidden. Create a new branch or ask me to do it manually.' >&2; exit 2; } || exit 0"
}
]
}
]
}
}
Co dělá: Při každém spuštění Bash kontroluje, že příkaz obsahuje push, obsahuje --force/--force-with-lease/-f a zmiňuje main. Pokud odpovídají všechny tři podmínky, příkaz zablokuje s jasnou zprávou.
Dříve jsem toto pravidlo měl v CLAUDE.md napsané velkými písmeny. Claude ho přesto porušil asi jednou za dva týdny, když jsem ho požádal o „force-push, abych vrátil svůj špatný commit“. Hook zachytí zobrazené doslovné tvary příkazů, aliasy, skripty, implicitní cílová větev či jiný klient Git ale mohou řetězcovou kontrolu obejít. Na vzdáleném serveru vynucujte ochranu main a omezte přihlašovací údaje agenta.
Háček 4. Blokujte dlouhé pomlčky v textových souborech (PostToolUse, exit 2)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // empty'); [ -z \"$FILE\" ] && exit 0; echo \"$FILE\" | grep -qE '\\.(md|mdx|tsx?)$' && grep -q $'\\xe2\\x80\\x94' \"$FILE\" && { echo \"File $FILE contains an em dash (U+2014). Replace it with a regular hyphen (U+002D).\" >&2; exit 2; } || exit 0"
}
]
}
]
}
}
Co dělá: PostToolUse s exit 2 hlásí Claude selhání následné kontroly po úpravě. Zápis nevrací ani mu nezabrání. Pokud Claude upraví soubor a ponechá v něm dlouhou pomlčku, háček selže, Claude dostane zpětnou vazbu a zkusí to znovu. Po 2–3 relacích Claude přestane tento znak vkládat úplně.
Všimněte si, že grep hledá konkrétně znak dlouhé pomlčky (U+2014) pomocí $'\xe2\x80\x94', což je zápis Bash pro jeho vyjádření v bajtech UTF-8. Pokud jednoduše zadáte grep -q '-', zachytí běžné spojovníky a spustí se u každého souboru. Neviditelný znak by porušil celou logiku.
Háček 5. Uvolněte port 3000 před npm run dev (PreToolUse, exit 0)
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "CMD=$(jq -r '.tool_input.command // empty'); [ -z \"$CMD\" ] && exit 0; echo \"$CMD\" | grep -qE '(npm|pnpm|yarn)[[:space:]]+run[[:space:]]+dev' && { lsof -ti:3000 | xargs -r kill -9 2>/dev/null; echo 'Port 3000 freed before launch' >&2; }; exit 0"
}
]
}
]
}
}
Co dělá: Před každým npm run dev (nebo pnpm/yarn) ukončí proces na portu 3000. Vždy skončí s kódem 0, protože jde o přípravu, nikoli omezení. Chrání před skupinou problémů, kdy Claude vidí „port is in use“, myslí si, že jde o problém s kódem, a začne věci opravovat, přestože starý server jen zůstal spuštěný.
Háček 6. Automatický commit po úspěšných testech (PostToolUse, exit 0)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); CMD=$(printf '%s' \"$INPUT\" | jq -r '.tool_input.command // empty') || exit 1; EXIT=$(printf '%s' \"$INPUT\" | jq -r '.tool_response.exit_code // empty') || exit 1; case \"$CMD\" in 'npm test'|'pnpm test'|'yarn test') ;; *) exit 0 ;; esac; [ \"$EXIT\" = \"0\" ] || exit 0; git diff --cached --quiet || { echo 'Existing staged changes: review manually' >&2; exit 0; }; git add -- src/orders.ts tests/orders.test.ts || exit 1; git diff --cached --quiet && exit 0; git commit -m 'tests: checkpoint after successful run'"
}
]
}
]
}
}
Co dělá: JSON stdin čte jednou a přijímá jen přesné prosté testovací příkazy v ukázce. Pokračuje pouze při výslovně nulovém tool_response.exit_code; pokud pole vaše verze neposkytuje, commit vynechá místo odhadu úspěchu. src/orders.ts a tests/orders.test.ts nahraďte přesnými soubory úkolu. Existující připravené změny recept zastaví, aby nepřidal jinou práci. Selhání add jej ukončí, prázdný diff nevytvoří commit a běžné kontroly commitů zůstávají zapnuté. Před zapnutím offline otestujte úspěšný, neúspěšný i chybějící výsledek.
Anti-vzor: přidávat git commit --no-verify ke každé operaci Edit. Kontroly commitů ponechte zapnuté. Spouští-li kontrola automatizaci rekurzivně, zužte spouštěč či kontrolu přepracujte; ve výchozím stavu ověřování neobcházejte. Před automatickými commity prověřte připravený diff a vlastnictví úkolu.
Háček 7. Vložte aktuální kontext při zahájení relace (SessionStart s additionalContext)
{
"hooks": {
"SessionStart": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || echo 'no-branch'); STATUS=$(git status --short 2>/dev/null | head -10); echo \"{\\\"additionalContext\\\":\\\"Current branch: $BRANCH. Uncommitted changes:\\n$STATUS\\\"}\""
}
]
}
]
}
}
Co dělá: Při zahájení relace získá aktuální větev Git a seznam nepotvrzených změn a vrátí JSON s polem additionalContext. Claude Code vloží tento text do první systémové zprávy, takže Claude hned ví, kde se nachází a co zůstalo z předchozí relace.
Pomocí additionalContext předejte informace, které by Claude měl vědět o aktuálním stavu prostředí nebo právě dokončené operaci: stav prostředí (aktuální větev, cíl nasazení, aktivní příznaky funkcí), podmíněná pravidla projektu (který příkaz pro testy platí pro právě upravený soubor), externí data (otevřené úkoly přiřazené vám, nedávné výsledky CI).
Rozšíření tohoto háčku: získejte poslední commit a jeho popis, stav GitHub Actions, aktivní sprint v Linear/Jira a otevřené úkoly pro aktuální repozitář.
3 úskalí háčků, která potkají každého druhého
Hlavní poznatek
První úskalí: háček s exit 1 projde potichu a Claude chybu ignoruje. Druhé: náročná operace v háčku se po timeoutu 60 sekund ukončí. Třetí: háček vidí jen proměnné prostředí z ~/.zshrc, nikoli z .env projektu. Každé se dá napravit jedním řádkem, ale pokud o těchto úskalích nevíte, může to vypadat, že „háčky nefungují“.
Úskalí 1. Háček s exit 1 projde potichu
To nejnebezpečnější. Týden jsem si myslel, že můj háček chrání .env, ale ukázalo se, že jsem v něm měl jq -r '.tool_input.file_path' bez kontroly na null. Když byl tool_input prázdný, jq skončil s kódem 1. Claude považoval exit 1 za „chybu háčku, pokračuj“, takže akce proběhla. Nechápal jsem, proč se do .env stále sahá. Příčinu jsem odhalil, až když jsem háček ručně spustil v terminálu s prázdným vstupem.
Oprava má jedno pravidlo: každý háček začněte kontrolou null a zakončete || exit 0. Každý neočekávaný návrat pak povede k „bezpečnému“ ukončení, místo aby se chyba potichu přešla.
# Safe start and end template:
FILE=$(jq -r '.tool_input.file_path // empty')
[ -z "$FILE" ] && exit 0
# ... your logic ...
exit 0 # or || exit 0 on one line
Úskalí 2. Pomalé háčky se ukončí po vypršení časového limitu
Měl jsem háček, který po operaci Edit spouštěl eslint --fix na celém souboru. Zpracování velkých souborů (1000+ řádků) trvalo 8–10 sekund. Výchozí timeout háčku v Claude Code je 60 sekund, takže jsem si myslel, že se do limitu vejdu. Jenže když během jedné minuty proběhne několik úprav, háčky se hromadí a řadí do fronty a některé se jednoduše přeskočí. Došlo mi to, až když se v protokolu objevilo „hook timed out“.
Oprava: pokud háček vyžaduje náročnou práci, spusťte ji na pozadí. Použijte eslint --fix "$FILE" & a nečekejte na výsledek. Háček pak za milisekundy skončí s kódem 0, zatímco skutečná práce poběží na pozadí.
# Heavy operation in background:
npx eslint --fix "$FILE" &
exit 0
Úskalí 3. Háček nevidí proměnné prostředí projektu
Myslel jsem si, že process.env bude v háčku dostupné stejně jako v aplikaci Node.js. Není. Háček běží v shellu vytvořeném nadřazeným procesem Claude Code a vidí jen to, co je v ~/.zshrc nebo ~/.bashrc, plus to, co mu Claude Code výslovně předá. Pokud váš háček závisí na OPENAI_API_KEY z .env, budete muset .env načíst ručně.
Oprava: výslovně načtěte .env v příkazu háčku.
# Passing project env into hook:
cd "$PWD" && source .env && curl -H "Authorization: Bearer $OPENAI_API_KEY" ...
# Or with dotenv:
dotenv -e .env -- node my-validator.js
To je obzvlášť nepříjemné v monorepu, kde mají různé balíčky vlastní soubory .env. Vyřešíte to předáním PWD a výslovným spuštěním cd "$PWD" na začátku příkazu.
Jak otestovat háčky před commitem?
Hlavní poznatek
Háček je shellový příkaz. Můžete ho ručně spustit v terminálu s fiktivním stdin, zkontrolovat jeho návratový kód a stderr, a to všechno ještě předtím, než ho spustí Claude Code. Ušetří vám to hodiny ladění a ochrání vás před háčky, které blokují vlastní činnost.
Základní testovací scénář. Zkopírujte příkaz háčku z JSONu, otevřete terminál a předejte mu JSON, který by Claude Code odeslal:
# Test hook 1 (protect .env):
echo '{"tool_input":{"file_path":".env"}}' | bash -c '
FILE=$(jq -r ".tool_input.file_path // empty")
[ -z "$FILE" ] && exit 0
echo "$FILE" | grep -qE "(^|/)\.env(\.|$)" && {
echo "BLOCKED" >&2
exit 2
} || exit 0
'
echo "Exit code: $?"
Ve stderr byste měli vidět BLOCKED a Exit code: 2. Pokud dostanete exit 0, regex nefunguje; opravte grep.
Scénáře k ověření:
- Úspěšná cesta - soubor by měl být zablokován. Pro háček 1
.env, pro háček 3git push --force main. - Negativní cesta - soubor by neměl být zablokován. Pro háček 1
README.md, pro háček 3git push origin feature-branch. - Okrajové případy - prázdný vstup, hodnoty null, neočekávané znaky. Háček by měl buď vrátit exit 0, nebo selhat s jasnou chybou, nikoli chybu potichu ignorovat.
Kam ukládat experimentální háčky. Ne do .claude/settings.json, ale do .claude/settings.local.json (není v git). Přidejte tam nové háčky pod PostToolUse s příkazem echo místo skutečné akce, ověřte, zda se spouštějí, a pak je přesuňte do produkčního settings.json.
// Experiment in settings.local.json - writes to /tmp/hook-debug.log:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit",
"hooks": [
{
"type": "command",
"command": "echo \"[hook fired] $(date) $(jq -r '.tool_input.file_path // \"?\"')\" >> /tmp/hook-debug.log"
}
]
}
]
}
}
Po 5–10 úpravách v Claude Code otevřete /tmp/hook-debug.log a podívejte se, které soubory háček spustily. Pokud je prázdný, matcher neodpovídá; opravte regex.
Co dál?
Hlavní poznatek
Začněte háčky PostToolUse s exit 0; jsou nejbezpečnější a nic neblokují. Po týdnu přidejte první háček PreToolUse s exit 2, který ochrání .env nebo zabrání force-pushi. Po dvou týdnech se CLAUDE.md zkrátí z dvousetřádkové smlouvy na stručný popis kontextu v rozsahu 50–80 řádků s vybranými kontrolami událostí v hookách a tvrdými hranicemi přístupu vynucenými zvlášť oprávněními, sandboxem a ochranou vzdáleného serveru.
5 kroků na příští týden:
- Prohledejte svůj
CLAUDE.mda hledejte slova jako „nikdy“, „zakázáno“, „vždy“ a „musíš“. Každé takové pravidlo je kandidátem na háček. Pokud je pravidlo příkazem, textový soubor ho nevynutí. - Začněte s PostToolUse + exit 0. Jsou nejbezpečnější: provedou změnu, ale nic neblokují. Prettier (háček 2), ukončení vývojového serveru (háček 5), automatický commit po testech (háček 6).
- První PreToolUse + exit 2 přidejte, až si budete jistí. Například chraňte
.env(háček 1) nebo zabraňte force-pushi (háček 3). Jde o tvrdou blokaci a chyba v příkazu grep může zablokovat i vás. - Před commitem háčky ručně otestujte (viz výše uvedenou část). Ušetří vám to hodiny ladění.
- Pro experimenty používejte
settings.local.json. Přidávejte do něj nové háčky s příkazem echo místo skutečné akce.
Jakmile háčky nastavíte, dalším krokem v této sérii je jak vrátit změny v Claude Code, kdyby háček propustil něco nebezpečného. Pokud chcete, aby si Claude pamatoval strukturu projektu mezi relacemi, vytvořte Druhý mozek v Claude Code (složka business/ + propojená znalostní báze). A pokud chcete pojmenovat dovednosti svého projektu, aby se daly znovu používat, podívejte se na Dovednosti Claude Code.
Zdroje
Pokud potřebujete přístup k neuronovým sítím prostřednictvím Ailoot, podívejte se na Ailoot.
Další podrobnosti
Časté otázky
Proč musí hook přečíst svůj vstup JSON pouze jednou?
Stdin je proud: první jq ho spotřebuje a další čtení dostanou konec. Vstup jednou uložte a příkaz i výsledek vytahujte z uložené hodnoty. Chybějící či neznámý výsledek považujte za neověřený a automatický commit vynechte.
Vytvářejí ukázkové regex hooky bezpečnostní hranici?
Ne. Kontrolují konkrétní události a rozpoznané řetězce příkazů. Přesměrování shellu, aliasy, skripty, MCP a jiné zápisy je mohou obejít; tvrdé hranice zajišťujte omezenými přihlašovacími údaji, oprávněními, sandboxem a chráněnými větvemi.