
Claude Code hooks: Den komplette guide (2026)
En skill kan blive ignoreret. Det er ikke en fejl i skills, det er hele designet: Claude læser beskrivelsen, beslutter om den aktuelle opgave matcher, og indlæser kun teksten, hvis den tror det gør. Det meste af tiden er den vurdering rigtig. Nogle gange er den ikke, og opgaven hvor det betyder mest, code review'et lige før en merge, log-indgangen der skal eksistere uanset hvad, er præcis opgaven, hvor "sandsynligvis" ikke er godt nok.
Hooks er den anden halvdel af Claude Code. En hook er en shell-kommando, harnesset kører, når en specifik hændelse udløses, uanset om nogen skill ville have tænkt på det. Ingen model-vurdering sidder mellem hændelsen og kommandoen. Den kører, hver gang, i rækkefølge, og dens exit-kode kan endda stoppe Claude helt. Har du nogensinde ønsket at sige "formater altid denne fil efter en redigering" eller "lad aldrig Claude røre denne mappe," er en hook værktøjet bygget til den sætning.
Denne guide dækker, hvad hooks er, settings.json-skemaet bag dem, seks opskrifter du kan indsætte i dag, hvordan hooks og skills arbejder sammen, og de fejltilstande, der æder en eftermiddag, hvis du ikke ved, du skal kigge efter dem.
Hvad en hook faktisk er
Claude Code udløser navngivne hændelser under en session: før et værktøj kører, efter et værktøj kører, når Claude er færdig med at svare, når en notifikation ville vise sig. En hook binder en shell-kommando til en af disse hændelser, valgfrit filtreret til specifikke værktøjer. Harnesset kører din kommando, sender den kontekst som JSON på stdin, og læser derefter exit-koden for at beslutte, hvad der sker næste.
De hændelser, du vil bruge mest:
- PreToolUse — udløses før et værktøjskald udføres. En hook her kan blokere kaldet helt.
- PostToolUse — udløses efter et værktøjskald er færdigt. Godt til formatering, testning eller logning af hvad der lige skete.
- Stop — udløses når Claude er færdig med sin tur og er ved at give kontrollen tilbage til dig.
- Notification — udløses når Claude Code ville vise dig en systemnotifikation (tilladelsesanmodninger, idle-prompts).
- UserPromptSubmit — udløses når du indsender en besked, før Claude ser den.
Det er mekanismen. Grunden til at det betyder noget, er den garanti, det giver dig, som en skill strukturelt ikke kan.
Den mentale model: deterministisk vs. skønsmæssig
Dette er den ene idé, det er værd at huske, hvis du ikke husker andet fra denne guide.
En skill er skønsmæssig. Claude læser dens beskrivelse ved starten af en session og beslutter senere, baseret på din anmodning, om den skal indlæse og følge den. Gode skills trigger pålideligt, men "pålideligt" er stadig en sandsynlighed, ikke en garanti. Claude kan fejllæse en tvetydig prompt, eller to skills kan have overlappende beskrivelser, der forvirrer matchet, en fejltilstand vi dækker mere i dybden i vores guide til hvorfor skills ikke trigger.
En hook er deterministisk. Den spørger ikke Claude, om den skal køre. Den læser ikke en beskrivelse og vurderer relevans. Harnesset ser hændelsen, og kommandoen kører, punktum. Er hændelsen PostToolUse på Edit-værktøjet, kører din formatter efter hver redigering, inklusive den, Claude lavede mens den tænkte på noget helt andet.
Den forskel kortlægger direkte til, hvornår man skal gribe fat i hvilken:
| Skill | Hook | |
|---|---|---|
| Kører når | Claude vurderer den relevant | Hver gang hændelsen udløses |
| Kan springes over | Ja, af et dårligt match eller travl kontekst | Nej |
| Bedst til | Vurdering, struktur, "hvordan man gør X godt" | Håndhævelse, "X skal altid ske" |
| Fejltilstand | Stille non-trigger | Stille dårlig exit-kode, eller blokerer alt |
Starter sætningen, du håndhæver, med "Claude skal altid..." eller "Claude må aldrig...", vil du have en hook. Starter den med "når Claude gør X, skal den gribe det an som..." vil du have en skill. At formatere kode efter hver redigering er en hook; at skrive idiomatisk Python er en skill. At blokere commits til main er en hook; at strukturere en god commit-besked er en skill.
Anatomien af en hook i settings.json
Hooks bor under hooks-nøglen i .claude/settings.json (projekt-niveau) eller ~/.claude/settings.json (bruger-niveau), en anden fil end CLAUDE.md og værd ikke at forveksle: CLAUDE.md er prosa, Claude læser, settings.json er konfiguration, harnesset udfører. Har du ikke sat nogen af delene op endnu, dækker vores CLAUDE.md-guide og vores fulde opsætningsgennemgang resten af den stak, denne fil bor inden i. Her er et minimalt, men komplet hooks-eksempel, annoteret:
{
"hooks": {
// Hændelsesnavnet — PreToolUse, PostToolUse, Stop, Notification, osv.
"PostToolUse": [
{
// matcher filtrerer, hvilke værktøjskald der udløser denne hook.
// Udelad den (eller brug "*") for at matche hvert værktøj.
"matcher": "Edit|Write",
"hooks": [
{
// "command" er i øjeblikket den eneste hook-type.
"type": "command",
// Shell-kommandoen der skal køres. Modtager hændelses-JSON på stdin.
"command": "npx prettier --write \"$(echo $CLAUDE_TOOL_INPUT | jq -r .file_path)\"",
// Valgfrit: dræb kommandoen, hvis den hænger.
"timeout": 15
}
]
}
]
}
}
Et par ting værd at fremhæve, fordi de snubler folk:
matcher-feltet opererer på værktøjsnavnet, ikke på filstier eller indhold. "Edit|Write" matcher Edit- og Write-værktøjerne; "Bash" matcher shell-kald. Har du brug for at filtrere efter filsti eller kommandoindhold, gør det inde i dit script ved at læse JSON-payloaden, ikke i matcheren.
Hver hændelsesnøgle holder et array af matcher-blokke, og hver matcher-blok holder et array af hook-kommandoer, så du kan knytte flere kommandoer til én matcher, eller én kommando til flere matchere, uden at duplikere config.
Kommandoen modtager hændelses-payloaden som JSON på stdin: værktøjsnavn, værktøjs-input, og for PostToolUse, værktøjets resultat. En hook der handler på den specifikke fil, der bliver redigeret, læser den JSON frem for at antage, at shellens arbejdsmappe fortæller hele historien.
Exit-koder bærer betydning. Exit 0 betyder "fint, fortsæt." En ikke-nul exit på en PreToolUse-hook blokerer værktøjskaldet og fodrer stderr tilbage til Claude som en grund. En ikke-nul exit på PostToolUse bliver bare logget; værktøjet kørte allerede, så der er intet tilbage at blokere.
Seks opskrifter, du kan bruge i dag
Disse er bevidst smalle. Kopiér blokken, justér kommandoen, og bekræft at den gør, hvad du forventer, på en engangsfil, før du stoler på den til rigtigt arbejde.
1. Auto-formatér efter hver redigering
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "cd \"$CLAUDE_PROJECT_DIR\" && npx prettier --write . --ignore-unknown"
}
]
}
]
}
}
Kører Prettier efter enhver redigering eller skrivning. På store repos, byt det brede . ud med en sti afledt af hookens JSON-input, så du kun formaterer den berørte fil.
2. Blokér redigeringer af beskyttede stier
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/guard_paths.py"
}
]
}
]
}
}
guard_paths.py læser filstien fra stdin-JSON, tjekker den mod en denylist (migrations/, .env, infra/prod/), og afslutter med 1 og en besked på stderr, hvis den matcher. Det er det tætteste, Claude Code kommer på en hård tilladelsesgrænse.
3. Kør tests efter kildeændringer
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "cd \"$CLAUDE_PROJECT_DIR\" && npm test -- --onlyChanged --silent"
}
]
}
]
}
}
Giver Claude et øjeblikkeligt signal, når en redigering ødelægger en test, i stedet for at vente på, at du bemærker det ved review. Hold testkommandoen smal (--onlyChanged, en hurtig delmængde), ellers bliver dette opskrift seks i "hvornår ikke"-afsnittet nedenfor.
4. Skrivebordsnotifikation når Claude er færdig
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude finished\" with title \"Claude Code\"'"
}
]
}
]
}
}
macOS-specifik (byt til notify-send på Linux). Nyttig når du begynder at køre længere autonome ture og stopper med at holde øje med terminalen hele tiden.
5. Log hver bash-kommando
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.command' >> \"$CLAUDE_PROJECT_DIR/.claude/bash-history.log\""
}
]
}
]
}
}
Et revisionsspor, der ikke afhænger af, at du husker at tjekke transskriptionen. På en delt maskine eller et repo med et compliance-krav er dette tæt på obligatorisk.
6. Lint-gate før commit
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/block_bad_commit.sh"
}
]
}
]
}
}
block_bad_commit.sh læser stdin, tjekker om kommandoen er en git commit, og hvis den er, kører den din linter først, og afslutter med ikke-nul, hvis den fejler. Det gør "vær venlig at linte før commit" fra en anmodning, Claude måske glemmer, til en regel, den ikke kan komme udenom.
GRATIS STARTERPAKKE
Sætter du hooks op ved siden af dine første skills? Vi sender vores 3 højest scorede skills plus den installationstjekliste, vi kører før hver SkillProof-test. Gratis.
Få den gratis starterpakkeHooks og skills sammen
De er ikke konkurrerende værktøjer; de bedste opsætninger bruger begge til det, hver er god til. Et gennemarbejdet eksempel: et team, vi testede, ville have hver commit skrevet i deres husstil, bydende form, et afgrænset præfiks, en krop der forklarer hvorfor, og de ville også have commits blokeret, hvis diffen rørte en databasemigrering uden en matchende rollback-fil.
Stildelen er vurdering. Hvad der tæller som et godt "hvorfor" varierer efter ændring, og der er ingen shell-script, der pålideligt skriver god prosa. Det er en skills job: noget som Git Workflow Coach indlæst, hver gang Claude er ved at committe, der lærer strukturen og giver eksempler på gode versus dovne commit-beskeder. Claude læser den, anvender vurdering og skriver en besked, der passer til mønsteret uden at være en skabelon-udfyldning. Kører teamet også streng red-green-refactor, er Test-Driven Development den samme slags vurdering-ikke-lov-tilføjelse: den former, hvordan Claude griber arbejdet an, en hook kan ikke gøre den del.
Migreringsreglen er ikke vurdering, det er lov: enten eksisterer rollback-filen, eller den gør ikke, og teamet ville ikke have "Claude besluttede, at denne ikke havde brug for det" som en mulighed. Det er PreToolUse-hooken fra opskrift seks, tilpasset til at tjekke for den parrede fil frem for at køre en linter, og blokere selve git commit-kaldet, hvis den mangler.
Kør dem sammen, og du får en god commit-besked, der også er garanteret at bestå migreringstjekket, fordi skillen håndterer den del, der har brug for en hjerne, og hooken håndterer den del, der har brug for en mur. Ingen erstatter den anden. Skillen kan ikke garantere overholdelse, og en hook der skriver "fix: forskellige ændringer" på hver commit ville være ubrugelig. Vores bedste kodningsskills-side rangerer vurderingssiden af denne parring efter testet score, hvis du vælger en første skill til at køre ved siden af dine hooks.
Debugging af hooks
Hooks fejler oftere stille end højlydt. Hvad der som regel går i stykker:
Citering. Hook-kommandoer er shell-strenge inde i JSON-strenge, så et ", der ikke er escaped, ødelægger JSON-parsingen, før din kommando nogensinde kører. Er du i tvivl, put den reelle logik i en scriptfil og lad hook-kommandoen bare kalde den (bash .claude/hooks/my-hook.sh) frem for at inline en kompleks one-liner.
Exit-koder der ikke betyder, hvad du tror. Et hook-script, der rammer en urelateret fejl (manglende afhængighed, adgang nægtet), afslutter med ikke-nul på samme måde som et hook, der bevidst vil blokere. Begynder en PreToolUse-hook at blokere hvert værktøjskald, og du ikke skrev den til at være så streng, tjek om scriptet faktisk fejler frem for at vurdere.
PATH-antagelser. Hooks kører i et shell-miljø, der måske ikke matcher din interaktive terminal. En kommando, der virker fint, når du skriver den selv, kan fejle inde i en hook, fordi nvm, et virtualenv, eller et værktøj installeret via et shell-plugin ikke er på PATH i den kontekst. Brug absolutte stier til binærfiler, eller kild det rigtige miljø øverst i scriptet.
Stille stdin-antagelser. Forventer dit script JSON på stdin og får det ikke, fordi du testede det ved at køre det direkte frem for at pipe en eksempel-payload ind, opfører det sig anderledes under harnesset, end det gjorde i din terminal.
Timeouts. En hook uden timeout, der hænger, vil hænge hele turen. Sæt en eksplicit timeout på alt, der rører netværket eller en langsom subprocess.
Hvornår man ikke skal bruge hooks
Hooks er billige at skrive og lette at overbruge. Fejltilstanden er ikke en hook, der gør det forkerte, det er en hook, der gør det rigtige for ofte. En PostToolUse-hook der kører din fulde testsuite efter hver eneste redigering, gør en fem-sekunders ændring til en to-minutters ventetid, gentaget for hver redigering i en session, der laver tyve af dem.
Tommelfingerreglen: tager en hooks kommando mere end et sekund eller to, indsnævr matcheren, indsnævr hvad den tjekker, eller flyt den til en mindre hyppig hændelse. Test-ved-hver-redigering bliver test-ved-fil-skrivning bliver test-før-commit, efterhånden som tjekket bliver dyrere. Match hookens omkostning til, hvor ofte dens hændelse udløses, og overvej om en skill, der kun indlæser kontekst og ikke kører en proces, er et bedre match til alt, der ikke strengt er håndhævelse.
Det er også værd ikke at gribe fat i en hook for at fixe en skills triggerproblem. Trigger en skill ikke, når den burde, er fixet en bedre beskrivelse, ikke en hook, siden hooks kører shell-kommandoer og ikke kan indlæse skill-indhold. For den fejltilstand, se hvorfor skills ikke trigger.
SKILLPROOF-PAKKE
At parre hooks med de rigtige skills er det meste af en god Claude Code-opsætning. Developer Toolkit bundter vores højest scorede kodningsskills, som er en del af skill-halvdelen af denne parring, allerede gjort for dig.
Få Developer Toolkit — $10FAQ
Sænker hooks hver eneste Claude Code-session?
Kun de hændelser, du knytter dem til, og kun med den tid, din kommando tager. En hook på PostToolUse for Edit kører én gang per redigering; en hurtig formatter er umærkelig, en fuld testsuite mærkes ved hver redigering, hvilket er tilfældet dækket ovenfor under hvornår man ikke skal bruge hooks.
Kan en hook stoppe Claude fra at gøre noget helt?
Ja, det er hvad PreToolUse-hooks er til. Afslut med ikke-nul, og værktøjskaldet bliver blokeret, før det kører, med stderr typisk vist tilbage til Claude som grunden. Det er mekanismen bag opskrift to (beskyttede stier) og opskrift seks (lint-gate).
Hvor sætter jeg min hooks-config, projekt- eller brugerindstillinger?
Projekt-niveau (.claude/settings.json, committed) hvis det skal gælde for alle på den kodebase: formatering, beskyttede stier, migreringstjek. Bruger-niveau (~/.claude/settings.json) til en personlig præference, som skrivebordsnotifikationen i opskrift fire.
Hvad er forskellen på en hook og en skill, der siger "formater altid kode"?
Hooken kører faktisk altid. En skill der fortæller Claude altid at formatere kode, er stadig en instruktion, Claude læser og beslutter at følge; det er et stærkt puf, ikke en garanti, og den konkurrerer med andet om opmærksomhed i konteksten på enhver given tur. Er "altid" et krav frem for en præference, brug en hook.
Min hook kører slet ikke. Hvad er det første, jeg skal tjekke?
Bekræft at settings-filen er gyldig JSON (et efterhængende komma eller et ikke-escaped anførselstegn kan stille deaktivere hele hooks-blokken), og at hændelsesnavnet og matcheren er stavet præcis som forventet; begge er versalfølsomme. Efter det, tjek om du redigerede projektindstillinger, mens sessionen læser brugerindstillinger, eller omvendt.
★ 9.6/10 × 3
Den gratis startpakke
De 3 skills med vores højeste testscorer plus installations-tjeklisten — det setup, vi selv ville lægge på en frisk maskine. Gratis, på mail.