Hooks in Claude Code: hoe je geautomatiseerde acties triggert na elke prompt

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:

HookWanneer triggert hijBelangrijkste use case
PreToolUseVóór elke tool-aanroep door ClaudeActies blokkeren die niet mogen
PostToolUseNa elke tool-aanroep door ClaudeAuto-actie op wat Claude net deed
SessionStartBij start van een sessieContext injecteren (memory laden)
StopBij einde van een sessie of agent-loopCleanup, 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.

Hook-events in Claude Code
Vier hook-events in een sessie: SessionStart bij begin, PreToolUse voor elke actie, PostToolUse na elke actie, Stop aan einde.

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:

bash
#!/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"}'
fi

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

bash
#!/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:

bash
#!/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:

bash
#!/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 caseRules.mdHooks
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.

bash
#!/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.

bash
#!/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:

  1. Test je hook losstaand. echo '{"tool_name": "Bash"}' | bash.claude/hooks/jouw_hook.sh, output moet geldige JSON zijn.
  2. Log alles in dev. Voeg in je hook een echo "$INPUT" >> /tmp/hook_debug.log toe terwijl je experimenteert.
  3. 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:

  1. Maak .claude/hooks/ aan in je actieve project. Schrijf één van de drie aanbevolen hooks hierboven (memory, bash safety, of receipt log). 30 minuten.
  2. Test in een nieuwe sessie. Werkt hij? Krijg je output? Zie je de blokkade triggeren als je een gevaarlijk commando vraagt?
  3. 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

  1. Claude Code documentation, Hooks
  2. Context Rot in Claude Code automatische rotatie, concreet voorbeeld van hooks in productie
  3. VNX hooks-implementatie op GitHub, open-source referentie
  4. Rules.md uitgelegd (vorige post in deze serie)

Vincent van Deth

AI Strategy & Architecture

Vincent van Deth bouwt productiesystemen met AI voor het MKB. Hij is de maker van VNX, een multi-agent LLM orchestrator, en helpt teams betrouwbare AI-automatisering te shippen — zonder bullshit.

Reacties

Je e-mailadres wordt niet gepubliceerd. Reacties worden beoordeeld voor plaatsing.

Reacties laden...