Eerder in deze serie schreef ik over CLAUDE.md en rules.md. Dat zijn beide instructie-mechanismen, Claude leest ze als context en probeert zich eraan te houden. Soms lukt dat, soms vergeet hij iets, soms maakt hij een keuze die je niet zag aankomen.
Hooks zijn anders. Hooks zijn executies, ze draaien als shell-script of Python-script op runtime, niet in de prompt. Ze kunnen acties blokkeren voordat Claude ze uitvoert, of automatisch werk doen na elke prompt zonder dat Claude er iets mee hoeft te doen.
Dit is de stap voorbij rules.md. Voor AI peers en hobbyisten die net voorbij de eerste experimenten zijn, is dit het mechanisme dat het verschil maakt tussen "Claude assist mij" en "Claude is een onderdeel van mijn werkproces, met automatische guards en automatisch werk eromheen".
De vier hook-events
Claude Code definieert vier event-momenten waarop je een hook kunt aanhaken:
| Hook | Wanneer triggert hij | Belangrijkste use case |
|---|---|---|
PreToolUse | Vóór elke tool-aanroep door Claude | Acties blokkeren die niet mogen |
PostToolUse | Na elke tool-aanroep door Claude | Auto-actie op wat Claude net deed |
SessionStart | Bij start van een sessie | Context injecteren (memory laden) |
Stop | Bij einde van een sessie of agent-loop | Cleanup, samenvatting, stat-update |
Iedere hook is een script dat je in .claude/hooks/ plaatst. Claude Code roept het automatisch aan met JSON-input via stdin, en jij geeft een JSON-response terug.

PreToolUse, de blocker
Het krachtigste hook-type. Voordat Claude een tool gebruikt (bv. Bash, Edit, Write), draait je hook. Je hook ontvangt:
- Welke tool wordt aangeroepen
- Met welke parameters
- In welke context
Je kunt dan teruggeven: {"decision": "approve"} (laat Claude doorgaan), of {"decision": "block", "reason": "..."} (blokkeer + zeg waarom).
Concreet voorbeeld uit mijn praktijk, context rotation bij 65% gevuld geheugen:
#!/bin/bash
#.claude/hooks/vnx_context_monitor.sh
INPUT=$(cat)
USED_PCT=$(echo "$INPUT" | jq -r '.context_used_pct // 0')
ROTATION_THRESHOLD=65
if ((USED_PCT >= ROTATION_THRESHOLD)); then
cat <<EOF
{
"decision": "block",
"reason": "VNX CONTEXT ROTATION REQUIRED (${USED_PCT}% used). Schrijf eerst een ROTATION-HANDOVER.md document met je voortgang."
}
EOF
else
echo '{"decision": "approve"}'
fiWat dit doet: zodra Claude probeert iets te doen terwijl het context-window 65% gevuld is, blokkeert de hook de actie en dwingt Claude eerst een handover-document te schrijven. Mijn andere hooks pakken dat document daarna op om automatisch een nieuwe sessie te starten.
Resultaat: zero-touch context rotation. Ik schreef er een blog over die op nummer #1 in Google staat.
PostToolUse, de auto-actor
Na elke tool-aanroep draait deze hook. Je kunt:
- Een receipt schrijven van wat Claude deed
- Iets in de achtergrond starten
- Een test triggeren
- Een notificatie sturen
Concreet voorbeeld, auto-test na elke file-edit:
#!/bin/bash
#.claude/hooks/auto_test_on_edit.sh
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')
# Alleen op.ts en.py files
if [["$TOOL_NAME" == "Edit" || "$TOOL_NAME" == "Write"]]; then
if [["$FILE_PATH" == *.ts || "$FILE_PATH" == *.py]]; then
# Trigger test in achtergrond, Claude wacht niet
nohup npm run test:related -- "$FILE_PATH" > /dev/null 2>&1 &
fi
fi
# Altijd approve, we onderbreken Claude niet
echo '{}'Wat dit doet: elke keer dat Claude een TypeScript- of Python-bestand aanpast, draait een gerelateerde test op de achtergrond. Claude gaat door met zijn werk. Jij ziet in een aparte terminal of de test groen blijft. Geen wachten, geen handmatig triggeren.
SessionStart, de memory loader
Aan het begin van iedere sessie. Hier laad ik persistente context uit een lokale memory-directory.
Concreet voorbeeld, auto-load van je memory directory:
#!/bin/bash
#.claude/hooks/load_memory.sh
MEMORY_DIR=".claude/memory"
if [! -d "$MEMORY_DIR"]; then
echo '{"context": ""}'
exit 0
fi
# Lees alle.md bestanden uit memory directory
CONTEXT=$(cat "$MEMORY_DIR"/*.md 2>/dev/null)
# Geef terug als context die wordt geinjecteerd
jq -n --arg ctx "$CONTEXT" '{"context": $ctx}'Wat dit doet: bij elke nieuwe Claude-sessie wordt automatisch je .claude/memory/ directory ingeladen. Geen handmatig kopiëren van context. Geen "wat deed ik laatste keer?".
Stop, de cleaner-upper
Bij einde van een sessie. Voor wrap-up acties.
Concreet voorbeeld, auto-commit van werknotities:
#!/bin/bash
#.claude/hooks/auto_commit_notes.sh
NOTES_DIR=".claude/work-notes"
# Zijn er nieuwe notities sinds laatste commit?
if [-d "$NOTES_DIR"] && [-n "$(git status --porcelain $NOTES_DIR 2>/dev/null)"]; then
git add "$NOTES_DIR"
git commit -m "chore(notes): auto-commit work notes from session" \
--no-verify > /dev/null 2>&1
fi
echo '{}'Wat dit doet: zodra een Claude-sessie eindigt, wordt automatisch elke wijziging in .claude/work-notes/ gecommit. Werknotities raken nooit meer kwijt, ook niet als jij vergeet om ze handmatig te committen.
Hooks vs. rules: wanneer kies je wat?
Een veelgestelde vraag bij beginners. Het simpele antwoord:
| Use case | Rules.md | Hooks |
|---|---|---|
| Codeerstandaarden ("gebruik async/await") | ||
| Workflow-stappen ("test voor commit") | ||
Hard-blokkeren ("nooit git push --force op main") | ||
| Auto-acties ("test triggeren na file edit") | ||
| Context laden ("memory injecteren") | ||
| Beslis-regels ("wanneer nieuwe component vs aanpassen") |
Vuistregel: rules zijn voor "wat Claude moet weten en proberen". Hooks zijn voor "wat het systeem moet afdwingenofautomatisch doen".
Veel beginners proberen hard-blokkades via rules.md. Dat werkt niet betrouwbaar. Voor security-kritieke regels, geen rm -rf /, geen secrets in commits, geen prod-deploys zonder tests, gebruik je hooks.
De drie hooks die ik aan elke beginner aanraad
Niet allemaal tegelijk. Begin met deze drie, op deze volgorde:
1. SessionStart memory loader
Eerste week. Laadt je actieve project-status uit een memory bestand. Maakt elke nieuwe sessie meteen productief zonder dat je context moet herhalen.
2. PreToolUse Bash safety
Tweede week. Blokkeert gevaarlijke Bash-commands voordat Claude ze uitvoert.
#!/bin/bash
#.claude/hooks/bash_safety.sh
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // ""')
if [["$TOOL_NAME" == "Bash"]]; then
# Block dangerous patterns
if echo "$COMMAND" | grep -qE '(rm -rf /|git push.*--force.*main|sudo rm)'; then
echo '{"decision": "block", "reason": "Dangerous command blocked by hook. Review manually."}'
exit 0
fi
fi
echo '{"decision": "approve"}'3. PostToolUse receipt logger
Derde week. Schrijft een NDJSON-receipt van elke tool-actie naar een lokaal logbestand. Maakt later debugging en kwaliteitsanalyse mogelijk.
#!/bin/bash
#.claude/hooks/receipt_logger.sh
INPUT=$(cat)
LOG_FILE=".claude/receipts/actions.ndjson"
mkdir -p "$(dirname "$LOG_FILE")"
# Voeg timestamp toe en append
echo "$INPUT" | jq --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
'. + {timestamp: $ts}' >> "$LOG_FILE"
echo '{}'Met deze drie heb je 80% van de praktische waarde van hooks. De rest komt later, op basis van wat je eigen workflow nodig heeft.
Hooks debuggen, de sneaky valkuil
Hooks falen vaak stilletjes. Als je hook crasht of slecht JSON teruggeeft, gaat Claude soms gewoon door alsof er niets gebeurde, en jij merkt het pas weken later.
Drie debug-tips:
- Test je hook losstaand.
echo '{"tool_name": "Bash"}' | bash.claude/hooks/jouw_hook.sh, output moet geldige JSON zijn. - Log alles in dev. Voeg in je hook een
echo "$INPUT" >> /tmp/hook_debug.logtoe terwijl je experimenteert. - Test op een safe playground. Voor blocking hooks: probeer eerst commands die je verwacht te blokkeren. Werkt blokkade? Pas dan deployen op productie-projecten.
Wat doe je deze week?
Drie acties:
- Maak
.claude/hooks/aan in je actieve project. Schrijf één van de drie aanbevolen hooks hierboven (memory, bash safety, of receipt log). 30 minuten. - Test in een nieuwe sessie. Werkt hij? Krijg je output? Zie je de blokkade triggeren als je een gevaarlijk commando vraagt?
- Lees de volgende post in deze serie over state management, daar laat ik zien hoe hooks en memory samenwerken om je AI-assistent persistent geheugen te geven.
Veelgestelde vragen
Samenvatting
Hooks zijn de stap voorbij rules.md. Vier event-momenten (PreToolUse, PostToolUse, SessionStart, Stop), telkens een script dat draait op runtime. Voor zachte regels gebruik je rules.md. Voor harde blokkades, auto-acties, en context-laden: hooks.
Begin met drie hooks: memory loader bij SessionStart, Bash safety bij PreToolUse, receipt logger bij PostToolUse. Daarmee heb je 80% van de waarde. Rest volgt naargelang je workflow het nodig heeft.
Volgende week: hoe je dit combineert met een lokale memory-directory voor persistent state management.
Lees ook: De 10 Claude Code features die elke developer in 2026 zou moeten gebruiken, hooks zijn feature #5 in de complete roadmap.
Voor teams die hun complete setup willen professionaliseren: zie AI-architectuur.
Heb je een specifieke hook-uitdaging? Stel je vraag op LinkedIn, ik beantwoord ze graag in een vervolgpost als ze veel voorkomen.
Bronnen & referenties
- Claude Code documentation, Hooks
- Context Rot in Claude Code automatische rotatie, concreet voorbeeld van hooks in productie
- VNX hooks-implementatie op GitHub, open-source referentie
- Rules.md uitgelegd (vorige post in deze serie)