
Claude Code Hooks: De Complete Developersgids met Productie-Klare Voorbeelden
Claude Code is uitstekend in het schrijven van code, maar het blijft een probabilistisch systeem. Je kunt het vragen om Prettier na elke bestandsbewerking uit te voeren. Je kunt die instructie in je CLAUDE.md zetten. En soms... vergeet het dat gewoon. Claude Code hooks lossen dit op door je deterministische, gegarandeerde controle te geven over wat er voor, tijdens en na elke actie van Claude gebeurt.
Ik configureer al maandenlang hooks in tientallen projecten, en ze zijn stilletjes het belangrijkste onderdeel van mijn Claude Code-setup geworden. Deze gids behandelt alles van de basis tot een productie-klare starterkit die je vandaag nog in elk project kunt gebruiken. Als je Claude Code naast tools als Cursor of Copilot gebruikt, weet je al hoe waardevol aanpassing is -- hooks gaan nog een stap verder.
Wat Zijn Claude Code Hooks (en Waarom Zou Je Er Om Geven)?
Claude Code hooks zijn door de gebruiker gedefinieerde shellcommando's, HTTP-endpoints of LLM-prompts die automatisch worden uitgevoerd op specifieke punten in de levenscyclus van Claude Code. Volgens de officiële documentatie van Anthropic worden hooks -- in tegenstelling tot promptinstructies die Claude soms negeert -- deterministisch uitgevoerd telkens wanneer ze worden getriggerd. Zo heb je gegarandeerde controle over opmaak, beveiliging, meldingen en workflow-automatisering.
Het Probabilistische Probleem
Het ding met CLAUDE.md-instructies is dit: het zijn suggesties, geen contracten. Je kunt schrijven "voer altijd npx prettier --write uit na het bewerken van TypeScript-bestanden" in je projectcontext, en Claude zal het de meeste tijd opvolgen. Maar "de meeste tijd" is niet goed genoeg als je code-opmaak afdwingt in een team, pushes naar productie blokkeert, of elk shellcommando logt voor een beveiligingsaudit.
Dit is de kernspanning in elk AI-codeergereedschap. Claude is een taalmodel -- het werkt op kansen. Je context engineering kan gedrag sturen, maar kan het niet garanderen.
Hoe Hooks Dit Oplossen
Hooks omzeilen het LLM volledig. Het zijn shellscripts, HTTP-aanroepen of AI-evaluaties die worden uitgevoerd bij specifieke lifecycle-events -- voor een tool wordt uitgevoerd (PreToolUse), nadat het klaar is (PostToolUse), wanneer een melding verschijnt, wanneer een sessie start, of wanneer Claude stopt. Zie ze als Git hooks, maar dan voor je AI-codeerassistent.
Er bestaan vier hook-types: command (shellscripts), HTTP (webhook-POST-verzoeken), prompt (enkelvoudige Claude ja/nee-evaluaties) en agent (start een subagent met toegang tot tools). We bespreken elk type later -- command-hooks dekken zo'n 90% van alles wat je nodig hebt.
Hoe Claude Code Hooks Werken: De Levenscyclusstroom
Claude Code hooks worden uitgevoerd in een vaste levenscyclus: een event vuurt (bijv. PreToolUse), de matcher controleert of de hook van toepassing is, het hook-script wordt uitgevoerd en ontvangt JSON via stdin, en de exitcode bepaalt wat er daarna gebeurt. Exitcode 0 betekent doorgaan, exitcode 2 betekent de actie blokkeren. Deze stroom is hetzelfde ongeacht welk hook-type je gebruikt.
Event -> Matcher -> Hook -> Exitcode (De 4-Stappenstroom)
Zo werkt elke hook-uitvoering:
1. EVENT VUURT bijv. PreToolUse(Write)
|
2. MATCHER CONTROLEERT Komt "Write" overeen met het matcherpatroon van de hook?
|
3. HOOK WORDT UITGEVOERD Shellscript draait, ontvangt JSON via stdin
|
4. EXITCODE BESLIST 0 = doorgaan | 2 = blokkeren | overig = foutDe JSON die via stdin binnenkomt bevat alles over het event: de tool_name, tool_input (bestandspad, inhoud, commando) en sessiemetadata. Je script leest deze JSON, voert de benodigde logica uit en sluit af met de juiste code.
Voor PreToolUse-hooks is exitcode 2 de krachtige -- die blokkeert de actie volledig en stuurt je stdout-bericht terug naar Claude als feedback. Claude ziet jouw bericht en kan zijn aanpak aanpassen.
Configuratiescopes: Gebruiker, Project en Lokaal
Hooks leven in settings.json op drie niveaus:
| Scope | Bestand | Gecommit naar Git? | Gebruiksscenario |
|---|---|---|---|
| Gebruiker | ~/.claude/settings.json | Nee | Persoonlijke standaarden (meldingen, opmaakvoorkeuren) |
| Project | .claude/settings.json | Ja | Team-gedeelde hooks (bestandsbeveiliging, testrunners, linting) |
| Lokaal | .claude/settings.local.json | Nee (gitignored) | Persoonlijke overrides voor dit project |
Projectinstellingen zijn het nuttigst voor teams. Zet je hooks in .claude/settings.json, commit het, en elke developer in het team krijgt automatisch dezelfde guardrails.
Het if-Veld: Nauwkeurig Filteren
Sinds Claude Code v2.1.85 ondersteunen hooks een if-veld waarmee je kunt filteren op tool-argumenten -- niet alleen op toolnamen. Zoals gedocumenteerd in de Anthropic hooks-referentie kun je hiermee een hook schrijven die alleen triggert op Bash-commando's die overeenkomen met git push, in plaats van bij elke Bash-aanroep.
{
"matcher": "Bash",
"if": "tool_input.command matches 'git push'",
"hooks": [{ "type": "command", "command": "./scripts/check-branch.sh" }]
}Dit was een gamechanger. Vóór if moest je óf te breed matchen (elk Bash-commando) óf het filteren in je script doen (rommelig).
Alle Claude Code Hook-Events: Snelle Referentietabel
Claude Code biedt meer dan 20 hook-events gedurende zijn levenscyclus, zoals gedocumenteerd in de officiële hooks-referentie en de Claude Code changelog. De meest gebruikte zijn PreToolUse, PostToolUse, Notification en Stop -- maar nieuwere events zoals ConfigChange en FileChanged openen geavanceerde automatiseringspatronen.
Hier is de volledige referentie:
| Event | Wanneer het vuurt | Kan blokkeren? | Veelvoorkomend gebruiksscenario |
|---|---|---|---|
| PreToolUse | Voor een tool wordt uitgevoerd | Ja (exit 2) | Gevaarlijke commando's blokkeren, bestanden beveiligen |
| PostToolUse | Nadat een tool klaar is | Nee | Automatisch opmaken, tests uitvoeren, acties loggen |
| Notification | Wanneer Claude een melding stuurt | Nee | Desktopmeldingen, Slack-berichten |
| Stop | Wanneer Claude een reactie afrondt | Nee | Opruimen, samenvatting genereren |
| SessionStart | Bij sessie-initialisatie | Nee | Context injecteren, omgeving instellen |
| UserPromptSubmit | Wanneer gebruiker een prompt indient | Ja (exit 2) | Invoervalidatie, inhoudsfiltering |
| PreCompact | Voor contextcompactie | Nee | Status opslaan voor geheugeninkrimping |
| PostCompact | Na contextcompactie | Nee | Kritieke context opnieuw injecteren |
| ConfigChange | Wanneer instellingen wijzigen | Nee | Omgevingsvariabelen hot-reloaden |
| FileChanged | Wanneer een bewaakt bestand wijzigt | Nee | Rebuilds triggeren, caches invalideren |
| TaskCreated | Wanneer een nieuwe taak wordt gespawnd | Nee | Taaktracking, resource-allocatie |
| PermissionDenied | Wanneer een permissiecheck mislukt | Nee | Auditlogging, melden van geblokkeerde acties |
| WorktreeCreate | Wanneer een nieuwe Git-worktree wordt aangemaakt | Nee | Worktree-specifieke instellingen initialiseren |
| SubagentStart | Wanneer een subagent spawnt | Nee | Subagent-activiteit monitoren |
| SubagentStop | Wanneer een subagent klaar is | Nee | Subagent-output valideren |
Pro tip: Je gebruikt PreToolUse en PostToolUse voor 80% van je hooks. SessionStart is de volgende meest nuttige -- perfect voor het injecteren van projectcontext die Claude aan het begin van elke sessie nodig heeft.
De 4 Claude Code Hook-Types Uitgelegd
Claude Code ondersteunt vier hook-handlertypes: command-hooks draaien shellscripts, HTTP-hooks POST-en naar URL's, prompt-hooks stellen Claude een ja/nee-vraag, en agent-hooks spawnen een subagent met toegang tot tools. In onze ervaring dekken command-hooks 90% van de gebruikssituaties. Gebruik HTTP voor externe integraties, prompt- en agent-hooks voor genuanceerde beslissingen die AI-oordeel vereisen.
| Type | Snelheid | Complexiteit | Het beste voor | Voorbeeld |
|---|---|---|---|---|
| Command | Snel | Laag | Opmaak, blokkeren, loggen | Prettier uitvoeren na bestandsbewerking |
| HTTP | Gemiddeld | Gemiddeld | Externe diensten, webhooks | POST naar Slack bij voltooiing |
| Prompt | Langzaam | Gemiddeld | Subjectieve beslissingen | "Is deze code veilig om uit te voeren?" |
| Agent | Langzaamst | Hoog | Complexe bestandsbewuste verificatie | Controleren of nieuwe code projectpatronen volgt |
Command-Hooks (Het Werkpaard)
Command-hooks draaien een shellcommando en gebruiken de exitcode om het resultaat te bepalen. Ze ontvangen de JSON-data van het event via stdin.
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "jq -r '.tool_input.command' | grep -q 'rm -rf /' && exit 2 || exit 0"
}]
}]
}
}Dit gebruik je voor opmaak, bestandsbeveiliging, meldingen en de meeste automatisering. Snel, eenvoudig en voorspelbaar.
HTTP-Hooks (Externe Integraties)
HTTP-hooks sturen een POST-verzoek naar een URL met de event-JSON als body. De responsstatuscode bepaalt het resultaat (200 = doorgaan, 403 = blokkeren).
{
"hooks": {
"Stop": [{
"matcher": "",
"hooks": [{
"type": "http",
"url": "https://your-api.com/claude-webhook"
}]
}]
}
}Geweldig voor het sturen van events naar Slack, Discord, PagerDuty of een eigen dashboard. Je kunt dit ook gebruiken om een externe beleidsengine te raadplegen voordat een tool-uitvoering wordt toegestaan.
Prompt-Hooks (AI-Gestuurde Beslissingen)
Prompt-hooks sturen de event-data door naar Claude zelf voor een enkelvoudige ja/nee-evaluatie. Claude geeft een JSON-antwoord terug met "decision": "allow" of "decision": "block" plus redenering.
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "prompt",
"prompt": "Is this bash command safe to run in a production environment? Consider: does it modify system files, delete data, or access sensitive credentials?"
}]
}]
}
}Gebruik deze spaarzaam. Ze voegen latentie toe (een volledige LLM-aanroep per hook-uitvoering) en kosten meer. Maar voor echt subjectieve veiligheidschecks -- zoals "ziet deze databasemigratie er destructief uit?" -- zijn ze moeilijk te evenaren. Als je benieuwd bent naar het wisselen van Claude Code-modellen, volgt het model dat wordt gebruikt voor prompt-hooks je huidige sessiemodel.
Agent-Hooks (Tool-Ondersteunde Verificatie)
Agent-hooks spawnen een subagent met toegang tot Read-, Grep- en Glob-tools. De subagent kan bestanden inspecteren voordat hij zijn beslissing neemt.
{
"hooks": {
"PreToolUse": [{
"matcher": "Write",
"hooks": [{
"type": "agent",
"prompt": "Check if the file being written follows the project's naming conventions and import patterns. Read .claude/CONVENTIONS.md for the rules."
}]
}]
}
}Dit is het krachtigste hook-type, maar ook het langzaamste. Reserveer het voor cruciale checks waarbij je bestandscontext nodig hebt om een goede beslissing te nemen.
7 Productie-Klare Claude Code Hook-Voorbeelden (Kant-en-Klaar om te Kopiëren)
De nuttigste Claude Code hooks zijn: automatisch opmaken met Prettier of Black na bestandsbewerkingen, schrijven naar beveiligde bestanden blokkeren, desktopmeldingen sturen bij taakvoltooiing, projectcontext injecteren bij sessiestart, tests uitvoeren na codewijzigingen, branchbeveiliging afdwingen, en alle toolgebruik auditten. Ik draai varianten van deze hooks al drie maanden in elk project.
Elk voorbeeld hieronder is een compleet settings.json-fragment dat je in je .claude/settings.json kunt plaatsen. Gemeenschapsverzamelingen zoals awesome-claude-code hebben nog meer patronen.
1. Automatisch Opmaken bij Opslaan
{
"hooks": {
"PostToolUse": [{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // .tool_input.file' /dev/stdin); case \"$FILE\" in *.ts|*.tsx|*.js|*.jsx) npx prettier --write \"$FILE\" 2>/dev/null;; *.py) black \"$FILE\" 2>/dev/null;; esac; exit 0"
}]
}]
}
}Dit vuurt na elke Write of Edit, haalt het bestandspad op uit de stdin-JSON, en voert de juiste formatter uit. De exit 0 aan het einde zorgt ervoor dat de hook nooit blokkeert -- opmaakfouten mogen Claude niet stoppen.
Pro tip: Voeg *.go toe met gofmt en *.rs met rustfmt als je meerdere talen gebruikt.
2. Schrijven naar Beveiligde Bestanden Blokkeren
{
"hooks": {
"PreToolUse": [{
"matcher": "Write|Edit",
"if": "tool_input.file_path matches '(\\.env|\\.env\\.local|package-lock\\.json|yarn\\.lock|pnpm-lock\\.yaml)'",
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"BLOCKED: This file is protected. Edit it manually.\"}' && exit 2"
}]
}]
}
}Exitcode 2 blokkeert de actie en stuurt het JSON-bericht terug naar Claude. Claude ziet de feedback en past zijn aanpak aan -- meestal vertelt het je dat het het bestand wilde aanpassen en vraagt het je dat handmatig te doen. Het if-veld voorkomt dat dit bij elke Write-aanroep triggert.
3. Desktopmelding bij Voltooiing
{
"hooks": {
"Notification": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "MSG=$(jq -r '.message // \"Claude Code task finished\"' /dev/stdin); if [ \"$(uname)\" = 'Darwin' ]; then osascript -e \"display notification \\\"$MSG\\\" with title \\\"Claude Code\\\"\"; else notify-send 'Claude Code' \"$MSG\"; fi; exit 0"
}]
}]
}
}Werkt op macOS (osascript) en Linux (notify-send). De lege matcher betekent dat het op alle meldingen triggert. Echt handig wanneer je een lange taak start en naar een ander venster wisselt.
4. Context Injecteren bij Sessiestart
{
"hooks": {
"SessionStart": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"Project: '\"$(basename $(pwd))\"' | Branch: '\"$(git branch --show-current 2>/dev/null || echo none)\"' | Last commit: '\"$(git log --oneline -1 2>/dev/null || echo none)\"'\"}'; exit 0"
}]
}]
}
}Dit injecteert de huidige projectnaam, Git-branch en laatste commit in elke sessie. Claude ontvangt deze context automatisch -- je hoeft niet te vertellen op welke branch je zit.
5. Tests Automatisch Uitvoeren na Codewijzigingen
{
"hooks": {
"PostToolUse": [{
"matcher": "Write|Edit",
"if": "tool_input.file_path matches '\\.(ts|tsx|js|jsx|py)$'",
"hooks": [{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path' /dev/stdin); TEST_FILE=$(echo \"$FILE\" | sed 's/\\.[^.]*$/.test&/'); if [ -f \"$TEST_FILE\" ]; then npx jest \"$TEST_FILE\" --no-coverage 2>&1 | tail -5; fi; exit 0",
"timeout": 30000
}]
}]
}
}Als een bijbehorend testbestand bestaat, wordt het automatisch uitgevoerd nadat Claude de broncode bewerkt. De tail -5 houdt de uitvoer beknopt, en de timeout voorkomt vastlopende testsuites. Dit werkt goed samen met een AI-gestuurde code-review-workflow.
6. Branchbescherming Afdwingen (Geavanceerd)
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"if": "tool_input.command matches 'git push.*(main|master|production)'",
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"BLOCKED: Direct push to protected branch. Use a feature branch and open a PR.\"}' && exit 2"
}]
}]
}
}Dit blokkeert elke git push naar de main-, master- of production-branches. Claude krijgt de feedback en stelt voor om een feature branch aan te maken.
7. Beveiligingsauditlogging (Geavanceerd)
{
"hooks": {
"PostToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "INPUT=$(cat /dev/stdin); CMD=$(echo \"$INPUT\" | jq -r '.tool_input.command'); echo \"[$(date -u +%Y-%m-%dT%H:%M:%SZ)] BASH: $CMD\" >> .claude/audit.log; exit 0"
}]
}]
}
}Logt elk Bash-commando dat Claude uitvoert naar een auditbestand met een UTC-tijdstempel. Onmisbaar voor beveiligingsreviews en het begrijpen van wat Claude tijdens een sessie daadwerkelijk heeft gedaan. Houd .claude/audit.log in je .gitignore.
Hooks vs MCP vs Skills vs CLAUDE.md: Wanneer Gebruik je Wat?
Gebruik hooks voor deterministische automatisering die altijd moet plaatsvinden (opmaak, blokkeren, meldingen). Gebruik MCP om Claude toegang te geven tot externe tools en data. Gebruik Skills voor herbruikbare promptpakketten. Gebruik CLAUDE.md voor gedragsrichtlijnen en projectcontext. Hooks zijn gegarandeerd; al het andere is probabilistisch. Dit is het belangrijkste onderscheid, en ik kom er steeds op terug als ik teams adviseer.
De Beslissingsmatrix
| Mechanisme | Deterministisch? | Wanneer het loopt | Het beste voor | Voorbeeld |
|---|---|---|---|---|
| Hooks | Ja | Automatisch bij lifecycle-events | Afdwinging, automatisering, meldingen | Automatisch opmaken, bestandswrites blokkeren |
| MCP | Nee (Claude beslist) | Wanneer Claude de MCP-tool aanroept | Nieuwe mogelijkheden, externe datatoegang | Een database raadplegen, Notion doorzoeken |
| Skills | Nee (gebruiker triggert) | Wanneer gebruiker een slash-commando aanroept | Herbruikbare instructiesets | /review voor code-review-workflow |
| CLAUDE.md | Nee (richtlijn) | Gelezen bij sessiestart | Projectcontext, coderingsnormen | "Gebruik Tailwind, schrijf tests voor alle nieuwe code" |
Voor een diepgaande blik op MCP, zie onze MCP-gids. Als je van Cursor komt, is Cursor's rules-systeem ruwweg vergelijkbaar met CLAUDE.md -- maar Cursor heeft niets dat lijkt op hooks.
Wanneer Ze Overlappen (en Hoe je Kiest)
Dit is het stroomschema dat ik gebruik:
- "Moet dit ELKE keer gebeuren, zonder uitzonderingen?" -- Hook. Code opmaken, beveiligde bestanden blokkeren, meldingen sturen. Nul ambiguïteit.
- "Heeft Claude een nieuwe MOGELIJKHEID nodig die het niet heeft?" -- MCP-server. Een database benaderen, een API aanroepen, externe docs doorzoeken.
- "Wil ik herbruikbare INSTRUCTIES voor een specifieke workflow?" -- Skill (slash-commando). Code-review-templates, deployment-checklists.
- "Wil ik het GEDRAG van Claude in dit project sturen?" -- CLAUDE.md. Coderingsnormen, architectuurbeslissingen, voorkeursbibliotheken.
Praktische voorbeelden die de grens verduidelijken:
- "Altijd opmaken met Prettier" = Hook (moet elke keer)
- "Gebruik Prettier voor opmaak" in CLAUDE.md = Richtlijn (Claude kan het vergeten)
- "Onze bedrijfsdocumentatie doorzoeken" = MCP (nieuwe mogelijkheid)
- "Onze stijlgids volgen bij code-review" = Skill of CLAUDE.md
Zoals beschreven in Anthropic's plugins-aankondiging zijn hooks één onderdeel van een breder plugin-ecosysteem dat ook MCP en Skills omvat. Ze zijn ontworpen om elkaar aan te vullen, niet om te concurreren.
De Starterkit: Een Drop-In Claude Code Hooks-Configuratie voor Elk Project
Een goede startershooks-configuratie voor Claude Code bevat automatisch opmaken bij bestandsbewerking, melding bij taakvoltooiing, bestandsbeveiliging voor gevoelige bestanden, sessiecontextinjectie, en een stop-hook voor opruimen. Dit is de exacte configuratie die ik in elk nieuw project gebruik -- aangepast voor de stack, maar de structuur blijft hetzelfde.
De Configuratie
{
"hooks": {
"SessionStart": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"Project: '\"$(basename $(pwd))\"' | Branch: '\"$(git branch --show-current 2>/dev/null)\"' | Node: '\"$(node -v 2>/dev/null)\"'\"}'; exit 0"
}]
}],
"PreToolUse": [{
"matcher": "Write|Edit",
"if": "tool_input.file_path matches '(\\.env|\\.env\\..+|.*lock\\.json|.*lock\\.yaml)'",
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"Protected file. Edit manually.\"}' && exit 2"
}]
}],
"PostToolUse": [{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // .tool_input.file' /dev/stdin); case \"$FILE\" in *.ts|*.tsx|*.js|*.jsx) npx prettier --write \"$FILE\" 2>/dev/null;; *.py) black \"$FILE\" 2>/dev/null;; *.go) gofmt -w \"$FILE\" 2>/dev/null;; esac; exit 0"
}]
}],
"Notification": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "MSG=$(jq -r '.message // \"Done\"' /dev/stdin); osascript -e \"display notification \\\"$MSG\\\" with title \\\"Claude Code\\\"\" 2>/dev/null || notify-send 'Claude Code' \"$MSG\" 2>/dev/null; exit 0"
}]
}],
"Stop": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "echo '[STOP] '\"$(date +%H:%M:%S)\"'' >> .claude/session.log; exit 0"
}]
}]
}
}Aanpassen voor Jouw Stack
| Stack | Opmaakcommando | Testcommando | Bewaken Extensies |
|---|---|---|---|
| Node/TypeScript | npx prettier --write | npx jest --no-coverage | .ts, .tsx, .js, .jsx |
| Python | black | pytest -x | .py |
| Go | gofmt -w | go test ./... | .go |
| Rust | rustfmt | cargo test | .rs |
Vervang de opmaak- en testcommando's in de bovenstaande configuratie om ze aan te passen aan jouw stack. De structuur blijft identiek.
Controleren of Je Hooks Werken
Drie manieren om te bevestigen dat hooks actief zijn:
/hooks-commando -- Typ/hooksin Claude Code om alle geregistreerde hooks, hun matchers en hun status te zien.- Transcriptinspectie -- Nadat een hook vuurt, controleer het sessietranscript. Hook-uitvoeringen verschijnen met hun uitvoer en exitcode.
- Snel uitschakelen -- Voeg
"disableAllHooks": truetoe aan je settings.json om alle hooks tijdelijk uit te schakelen zonder de configuratie te verwijderen. Verwijder het (of zet het opfalse) om ze opnieuw in te schakelen.
CI/CD-Integratie: Claude Code Hooks in Headless-Modus
Claude Code hooks werken in headless-modus (claude -p) met enkele verschillen: Notification-hooks vuren nog steeds, maar je kunt ze beter omleiden naar logging in plaats van desktopmeldingen. PreToolUse-hooks met exitcode 2 kunnen headless-sessies pauzeren voor menselijke beoordeling. GitHub Actions gebruikt anthropics/claude-code-action@v1 naast hooks voor geautomatiseerde workflows.
Gedrag in Headless-Modus
| Hook-event | Interactieve modus | Headless-modus (-p) | CI-aanbeveling |
|---|---|---|---|
| PreToolUse (exit 2) | Blokkeert, toont bericht | Pauzeert voor --resume | Gebruik voor verplichte menselijke goedkeuringen |
| PostToolUse | Loopt normaal | Loopt normaal | Houd formatters en loggers |
| Notification | Desktopmelding | Vuurt nog steeds (geen UI) | Omleiden naar logbestand of Slack-webhook |
| Stop | Loopt opruimen | Loopt opruimen | Goed voor CI-artefactverzameling |
| SessionStart | Injecteert context | Injecteert context | CI-omgevingsvariabelen injecteren |
De grote verrassing in headless-modus: PreToolUse-hooks die eindigen met exitcode 2 mislukken niet gewoon stilletjes. Ze pauzeren de sessie en laten je hervatten met --resume, wat een human-in-the-loop-patroon geeft voor CI/CD-pipelines.
GitHub Actions-Integratie
Hier is een minimale GitHub Actions-workflow die Claude Code met hooks gebruikt. Zoals gedocumenteerd in de officiële GitHub Actions-gids:
- name: Run Claude Code
uses: anthropics/claude-code-action@v1
with:
prompt: "Review this PR and suggest improvements"
allowed_tools: "Read,Grep,Glob"
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}Je .claude/settings.json-hooks gaan mee met de repository, dus ze vuren in CI precies zoals lokaal. Zorg er alleen voor dat hooks die afhankelijk zijn van desktopspecifieke tools (zoals osascript) terugvalopties of conditionals hebben.
Hookbeheer voor Teams
Een patroon dat goed werkt voor teams:
.claude/settings.json(gecommit) -- Team-gedeelde hooks: bestandsbeveiliging, formatters, branchbeveiliging. Iedereen krijgt deze..claude/settings.local.json(gitignored) -- Persoonlijke hooks: meldingsvoorkeuren, aangepaste logging, experimentele hooks.~/.claude/settings.json(gebruikersglobaal) -- Jouw standaarden in alle projecten: meldingsstijl, persoonlijke opmaakvoorkeuren.
Dit weerspiegelt hoe .editorconfig (gecommit) en lokale IDE-instellingen (persoonlijk) werken. Zoals opgemerkt in Angelo Lima's CI/CD-gids ervaren teams die gedeelde hooks standaardiseren minder "werkt bij mij"-problemen met Claude Code.
Problemen Oplossen met Claude Code Hooks en Veelgemaakte Fouten
Veelvoorkomende Claude Code hooks-problemen zijn: hooks vuren niet (controleer matcherspelling en settings.json-locatie), hooks draaien maar blokkeren niet (verkeerde exitcode -- gebruik 2, niet 1), oneindige lussen (Stop-hook triggert zichzelf), en trage opstart (te veel synchrone hooks). De meest gemaakte fout is exitcodeverwarring -- developers gebruiken exit 1 terwijl ze exit 2 bedoelen.
Hook Vuurt Niet
Symptomen: Je hebt een hook toegevoegd maar er gebeurt niets wanneer het event plaatsvindt.
Oplossingen:
- Matchertypefout -- Matchers zijn hoofdlettergevoelig.
"write"komt niet overeen met deWrite-tool. Controleer exacte toolnamen met/hooks. - Verkeerd instellingenbestand -- Hooks in
~/.claude/settings.jsonverschijnen niet in de/hooks-uitvoer voor de projectscope. Probeer.claude/settings.jsonin de projectroot. - JSON-syntaxfout -- Een losstaande komma of ontbrekend accolade schakelt de volledige hooks-configuratie stilletjes uit. Valideer je settings.json met
jq .. disableAllHooks: true-- Controleer of iemand (of een vorige debugsessie) deze vlag heeft laten staan.
Hook Draait Maar Blokkeert Niet
Symptomen: Je PreToolUse-hook wordt uitgevoerd, maar de actie gaat toch door.
Oplossingen:
- Verkeerde exitcode -- Exitcode 1 betekent "fout" (hook mislukt), niet "blokkeer." Gebruik
exit 2om een actie te blokkeren. Dit struikelt bijna iedereen, zoals opgemerkt in de officiële documentatie. - Ontbrekende stdout-JSON -- Voor blokkeringshooks: stuur een JSON-bericht zodat Claude weet waarom de actie is geblokkeerd:
echo '{"message": "Geblokkeerd: reden"}'
Oneindige Lussen
Symptomen: Claude blijft dezelfde actie herhalen, of je machine warmt verdacht op.
Oplossingen:
- Stop-hook triggert acties -- Als je Stop-hook een bestand schrijft of een commando uitvoert waardoor Claude reageert, heb je een lus gecreëerd. Stop-hooks mogen alleen passieve dingen doen: loggen, melden, opruimen.
- PostToolUse-hook veroorzaakt bewerkingen -- Een PostToolUse-hook die een bestand aanpast triggert een nieuw PostToolUse-event. Bescherm jezelf hiertegen met specifieke matchers of het
if-veld.
Prestatieproblemen
Symptomen: Claude duurt merkbaar langer om te starten of tools uit te voeren.
Oplossingen:
- Te veel SessionStart-hooks -- Elke wordt synchroon uitgevoerd bij het opstarten. Houd ze licht (onder 1 seconde elk).
- Zware scripts in drukke paden -- Hooks op PreToolUse en PostToolUse vuren vaak. Als je script netwerkverzoeken of zware berekeningen doet, voeg een
timeout-veld toe (milliseconden) en overweeg of het een HTTP-hook moet zijn. - Geen caching -- Als je steeds hetzelfde controleert (zoals "is dit een beveiligde branch?"), sla het resultaat op in een tijdelijk bestand in plaats van bij elke hook-aanroep Git-commando's uit te voeren.
Veelgestelde Vragen
Wat zijn Claude Code hooks en hoe werken ze?
Claude Code hooks zijn door de gebruiker gedefinieerde automatiseringsscripts die worden uitgevoerd bij specifieke lifecycle-events tijdens een Claude Code-sessie. Je configureert ze in settings.json met een matcherpatroon en een handler (shellcommando, HTTP-endpoint, prompt of agent). Wanneer het overeenkomende event vuurt, wordt de hook automatisch uitgevoerd en gebruikt exitcodes om het resultaat te bepalen.
Hoe configureer ik hooks in Claude Code settings.json?
Voeg een "hooks"-object toe aan een van de drie configuratielocaties: ~/.claude/settings.json (gebruikersglobaal), .claude/settings.json (projectgedeeld) of .claude/settings.local.json (projectpersoonlijk). Elk event-type is gekoppeld aan een array van hook-definities met matcher, optioneel if-veld, en een hooks-array met handlerobjecten met type en command of url.
Wat is het verschil tussen PreToolUse- en PostToolUse-hooks?
PreToolUse vuurt voor een tool wordt uitgevoerd, waardoor je de kracht hebt om het te blokkeren met exitcode 2. PostToolUse vuurt nadat de uitvoering is voltooid, handig voor opmaak, testen of loggen. PreToolUse is voor preventie en filtering. PostToolUse is voor validatie en opruimen. Beide ontvangen de toolnaam en invoer als JSON via stdin.
Kunnen Claude Code hooks gevaarlijke commando's blokkeren?
Ja. PreToolUse-hooks met exitcode 2 blokkeren elke tool-uitvoering. Je kunt gevoelige bestanden beveiligen tegen schrijven, shellcommando's blokkeren die overeenkomen met gevaarlijke patronen zoals rm -rf of git push main, en toegang tot productiedatabases voorkomen. Het blokkeringsbericht wordt teruggestuurd naar Claude als feedback, zodat het zijn aanpak kan aanpassen.
Welke hook-events zijn beschikbaar in Claude Code?
Claude Code biedt 15+ events: PreToolUse en PostToolUse voor tool-uitvoering, Notification voor meldingen, Stop voor sessie-einde, SessionStart voor initialisatie, UserPromptSubmit voor invoerfiltering, PreCompact en PostCompact voor contextbeheer, en nieuwere events zoals ConfigChange, FileChanged, TaskCreated en PermissionDenied. Zie de volledige referentietabel in de hook-events-sectie hierboven.
Hoe verschillen hooks van MCP-tools en Skills?
Hooks zijn deterministisch -- ze vuren altijd bij overeenkomende events, ongeacht wat Claude beslist. MCP-tools breiden de mogelijkheden van Claude uit (databasetoegang, API-aanroepen) maar Claude kiest wanneer ze worden gebruikt. Skills zijn herbruikbare instructiepakketten die worden aangeroepen met slash-commando's. CLAUDE.md biedt gedragsrichtlijnen. Gebruik hooks wanneer iets altijd moet gebeuren, MCP wanneer Claude nieuwe mogelijkheden nodig heeft.
Werken Claude Code hooks in headless-modus?
Ja, met kanttekeningen. Hooks vuren normaal in headless-modus (claude -p), maar desktopspecifieke hooks zoals macOS-meldingen hebben terugvalopties nodig. Belangrijk: PreToolUse-hooks die eindigen met exitcode 2 kunnen headless-sessies pauzeren voor menselijke goedkeuring via --resume. Dit maakt human-in-the-loop CI/CD-pipelines mogelijk waarbij bepaalde acties handmatige goedkeuring vereisen.
Hoeveel hooks zijn te veel? Vertragen hooks Claude Code?
Er is geen harde limiet, maar elke synchrone hook voegt latentie toe. SessionStart-hooks draaien bij opstarten, dus houd ze snel (onder 1 seconde elk). PreToolUse- en PostToolUse-hooks vuren bij elke overeenkomende tool-aanroep -- zware scripts hier tellen snel op. Ik raad aan het totale aantal hooks onder de 10-15 te houden, het if-veld te gebruiken om de scope te beperken, en timeout-waarden toe te voegen om vastlopende scripts te voorkomen.
Kan ik hooks gebruiken om code automatisch op te maken met Prettier of Black?
Ja -- het is de meest populaire hook-use case. Maak een PostToolUse-hook die overeenkomt met Write|Edit, haal het bestandspad op uit de stdin-JSON, en voer de juiste formatter uit op basis van de bestandsextensie. Zie voorbeeld één in de productievoorbeeldensectie voor een complete, kant-en-klare configuratie die TypeScript-, JavaScript- en Python-bestanden ondersteunt.
Zijn Claude Code hooks veilig? Wat zijn de beveiligingsrisico's?
Hooks draaien met je volledige gebruikersrechten -- er is geen sandbox. Een kwaadaardige hook kan je SSH-sleutels lezen, bestanden verwijderen of data exfiltreren. Gebruik alleen hooks van vertrouwde bronnen, bekijk elke gedeelde .claude/settings.json voordat je die in je project accepteert, en gebruik .claude/settings.local.json voor persoonlijke hooks die niet gedeeld mogen worden. Voor bredere AI-veiligheidspatronen, zie onze LLM guardrails-gids.