ai-machine-learning

Claude Code Hooks: De Complete Developersgids met Productie-Klare Voorbeelden

Geschreven door Mert Batur
Apr 5, 2026
16 leestijd
Claude Code Hooks: De Complete Developersgids met Productie-Klare Voorbeelden

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:

text
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 = fout

De 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:

ScopeBestandGecommit naar Git?Gebruiksscenario
Gebruiker~/.claude/settings.jsonNeePersoonlijke standaarden (meldingen, opmaakvoorkeuren)
Project.claude/settings.jsonJaTeam-gedeelde hooks (bestandsbeveiliging, testrunners, linting)
Lokaal.claude/settings.local.jsonNee (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.

json
{
  "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:

EventWanneer het vuurtKan blokkeren?Veelvoorkomend gebruiksscenario
PreToolUseVoor een tool wordt uitgevoerdJa (exit 2)Gevaarlijke commando's blokkeren, bestanden beveiligen
PostToolUseNadat een tool klaar isNeeAutomatisch opmaken, tests uitvoeren, acties loggen
NotificationWanneer Claude een melding stuurtNeeDesktopmeldingen, Slack-berichten
StopWanneer Claude een reactie afrondtNeeOpruimen, samenvatting genereren
SessionStartBij sessie-initialisatieNeeContext injecteren, omgeving instellen
UserPromptSubmitWanneer gebruiker een prompt indientJa (exit 2)Invoervalidatie, inhoudsfiltering
PreCompactVoor contextcompactieNeeStatus opslaan voor geheugeninkrimping
PostCompactNa contextcompactieNeeKritieke context opnieuw injecteren
ConfigChangeWanneer instellingen wijzigenNeeOmgevingsvariabelen hot-reloaden
FileChangedWanneer een bewaakt bestand wijzigtNeeRebuilds triggeren, caches invalideren
TaskCreatedWanneer een nieuwe taak wordt gespawndNeeTaaktracking, resource-allocatie
PermissionDeniedWanneer een permissiecheck misluktNeeAuditlogging, melden van geblokkeerde acties
WorktreeCreateWanneer een nieuwe Git-worktree wordt aangemaaktNeeWorktree-specifieke instellingen initialiseren
SubagentStartWanneer een subagent spawntNeeSubagent-activiteit monitoren
SubagentStopWanneer een subagent klaar isNeeSubagent-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.

TypeSnelheidComplexiteitHet beste voorVoorbeeld
CommandSnelLaagOpmaak, blokkeren, loggenPrettier uitvoeren na bestandsbewerking
HTTPGemiddeldGemiddeldExterne diensten, webhooksPOST naar Slack bij voltooiing
PromptLangzaamGemiddeldSubjectieve beslissingen"Is deze code veilig om uit te voeren?"
AgentLangzaamstHoogComplexe bestandsbewuste verificatieControleren 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.

json
{
  "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).

json
{
  "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.

json
{
  "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.

json
{
  "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

json
{
  "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

json
{
  "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

json
{
  "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

json
{
  "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

json
{
  "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)

json
{
  "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)

json
{
  "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

MechanismeDeterministisch?Wanneer het looptHet beste voorVoorbeeld
HooksJaAutomatisch bij lifecycle-eventsAfdwinging, automatisering, meldingenAutomatisch opmaken, bestandswrites blokkeren
MCPNee (Claude beslist)Wanneer Claude de MCP-tool aanroeptNieuwe mogelijkheden, externe datatoegangEen database raadplegen, Notion doorzoeken
SkillsNee (gebruiker triggert)Wanneer gebruiker een slash-commando aanroeptHerbruikbare instructiesets/review voor code-review-workflow
CLAUDE.mdNee (richtlijn)Gelezen bij sessiestartProjectcontext, 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

json
{
  "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

StackOpmaakcommandoTestcommandoBewaken Extensies
Node/TypeScriptnpx prettier --writenpx jest --no-coverage.ts, .tsx, .js, .jsx
Pythonblackpytest -x.py
Gogofmt -wgo test ./....go
Rustrustfmtcargo 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:

  1. /hooks-commando -- Typ /hooks in Claude Code om alle geregistreerde hooks, hun matchers en hun status te zien.
  2. Transcriptinspectie -- Nadat een hook vuurt, controleer het sessietranscript. Hook-uitvoeringen verschijnen met hun uitvoer en exitcode.
  3. Snel uitschakelen -- Voeg "disableAllHooks": true toe aan je settings.json om alle hooks tijdelijk uit te schakelen zonder de configuratie te verwijderen. Verwijder het (of zet het op false) 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-eventInteractieve modusHeadless-modus (-p)CI-aanbeveling
PreToolUse (exit 2)Blokkeert, toont berichtPauzeert voor --resumeGebruik voor verplichte menselijke goedkeuringen
PostToolUseLoopt normaalLoopt normaalHoud formatters en loggers
NotificationDesktopmeldingVuurt nog steeds (geen UI)Omleiden naar logbestand of Slack-webhook
StopLoopt opruimenLoopt opruimenGoed voor CI-artefactverzameling
SessionStartInjecteert contextInjecteert contextCI-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:

yaml
- 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 de Write-tool. Controleer exacte toolnamen met /hooks.
  • Verkeerd instellingenbestand -- Hooks in ~/.claude/settings.json verschijnen niet in de /hooks-uitvoer voor de projectscope. Probeer .claude/settings.json in 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 2 om 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.

Tags

claude code hooksclaude codedeveloper toolsAI automatiseringworkflow automatiseringsettings.jsonPreToolUsePostToolUse

Dit artikel delen

Start je project

Klaar om iets buitengewoons te bouwen?

Laten we je idee werkelijkheid maken. Ons team staat klaar om software te bouwen die het verschil maakt.