Claude Code Masterkurs – KI-gestuetztes Programmieren lernen mit Anthropics Coding-Agent

Hooks & Automation

Level 3 | 40 Minuten

Automatisiere Workflows mit dem Hook-System von Claude Code

Lernziele

Was sind Hooks?

Hooks sind benutzerdefinierte Shell-Befehle die automatisch ausgeführt werden wenn bestimmte Ereignisse in Claude Code eintreten. Anders als Skills und Prompts die Claude als KI-Anfrage verarbeitet, laufen Hooks AUSSERHALB des Sprachmodells — sie sind rein deterministische Automatisierung. Wenn ein Hook konfiguriert ist, wird er zuverlässig bei jedem passenden Event ausgeführt, ohne dass Claude darüber nachdenkt oder entscheidet. Stell dir Hooks vor wie Reflexe im menschlichen Körper: Wenn du auf eine heiße Herdplatte greifst, zieht dein Arm automatisch zurück — ohne dass dein Gehirn erst darüber nachdenken muss. Genauso reagiert ein Hook sofort auf ein Event, ohne den Umweg über das KI-Modell. Warum ist das wichtig? Weil es Dinge gibt die IMMER passieren müssen, nicht nur manchmal. Code-Formatting nach jeder Dateiänderung sollte nicht davon abhängen ob Claude sich daran erinnert den Formatter aufzurufen. Sicherheits-Checks vor gefährlichen Befehlen sollten nicht davon abhängen ob Claude die Gefahr erkennt. Benachrichtigungen wenn Claude auf Input wartet sollten nicht davon abhängen ob Claude daran denkt dich zu informieren. Hooks lösen genau diese Probleme. Du definierst: Bei welchem Event soll was passieren? Das Event tritt ein → der Befehl wird ausgeführt. Jedes Mal, garantiert, ohne Ausnahme. Das ist eine Ebene der Zuverlässigkeit die kein Prompt erreichen kann. Aktuell gibt es 10+ verschiedene Hook-Events: von SessionStart über UserPromptSubmit, PreToolUse, PostToolUse, PostCompact (neu seit März 2026 — feuert nach Context-Komprimierung), Notification bis Stop. Für jedes Event kannst du einen oder mehrere Shell-Befehle definieren. Die Befehle können alles sein was dein Terminal ausführen kann: Skripte, CLI-Tools, API-Aufrufe, Dateisystem-Operationen. Hooks werden in der Settings-Datei konfiguriert — entweder global (für alle Projekte), pro Projekt (committed ins Repository für das Team), oder lokal (nur für dich). Die Konfiguration ist JSON-basiert und unterstützt optionale Matcher die bestimmen bei welchen spezifischen Tools oder Dateien der Hook auslösen soll.

💡 Warum Hooks? Hooks eliminieren drei Probleme: 1. Repetitive manuelle Schritte — Formatter nach jeder Änderung? PostToolUse Hook erledigt das. 2. Vergessene Standards — Sicherheitschecks passieren JEDES Mal, nicht nur wenn du dran denkst. 3. Fehlender Kontext — SessionStart-Hook füttert Claude mit Git-Status und TODOs automatisch.

Hook Event-Typen

Claude Code bietet 9 verschiedene Lifecycle-Events auf die Hooks reagieren können. Jedes Event repräsentiert einen spezifischen Moment im Ablauf einer Session — vom Start bis zum Ende, von der Nutzereingabe bis zur Tool-Ausführung. Das Verständnis dieser Events ist der Schlüssel zu effektiven Hooks. Das SessionStart-Event feuert wenn eine Claude Code Session beginnt. Ideal um zusätzlichen Kontext zu laden, Team-Updates zu injizieren, oder lokale Entwicklungsumgebungen zu initialisieren. Zum Beispiel: Automatisch den aktuellen Sprint-Status aus Jira laden und als Kontext bereitstellen. Das UserPromptSubmit-Event feuert nachdem du eine Nachricht sendest, aber BEVOR Claude sie verarbeitet. Du kannst die Nachricht modifizieren, zusätzlichen Kontext anhängen oder bestimmte Prompts blockieren. Zum Beispiel: Automatisch Ticket-Nummern in Links umwandeln. PreToolUse feuert BEVOR ein Tool ausgeführt wird. Das ist der kritischste Hook für Sicherheit: Du kannst gefährliche Befehle blockieren bevor sie Schaden anrichten. Der Hook bekommt den Tool-Namen und die Parameter als Input und kann mit einem Exit-Code > 0 die Ausführung verhindern. PostToolUse feuert NACHDEM ein Tool erfolgreich ausgeführt wurde. Der beliebteste Einsatz: Code-Formatting nach Edit oder Write. Der Hook bekommt den Tool-Namen und das Ergebnis als Input und kann Nachbearbeitungen durchführen. Das Notification-Event feuert wenn Claude eine Benachrichtigung sendet — z.B. wenn es auf eine Permission-Bestätigung wartet. Perfekt für Desktop-Notifications damit du nicht ständig das Terminal im Blick haben musst. Das Stop-Event feuert wenn eine Session endet. Ideal für Cleanup-Arbeiten, Log-Archivierung oder automatische Zusammenfassungen der Session. Zum Beispiel: Session-Kosten in eine Tracking-Datei schreiben. Jeder Hook kann optional einen Matcher haben der bestimmt bei WELCHEN spezifischen Tools oder Dateien er auslösen soll. Zum Beispiel: PostToolUse mit Matcher 'Edit|Write' feuert nur bei Dateiänderungen, nicht bei Grep oder Read.

HOOK EVENT LIFECYCLE
━━━━━━━━━━━━━━━━━━━

📍 SessionStart        → Beim Start einer Session
   ↓
📝 UserPromptSubmit    → Wenn du einen Prompt absendest
   ↓
🔒 PreToolUse          → VOR Tool-Ausführung (kann blockieren!)
   ↓
✅ PostToolUse         → NACH erfolgreicher Tool-Ausführung
   ↓
❌ PostToolUseFailure  → NACH fehlgeschlagener Tool-Ausführung
   ↓
🔔 Notification        → Bei System-Benachrichtigungen
   ↓
🤖 SubagentStart/Stop  → Bei Subagent-Lifecycle
   ↓
🛑 Stop                → Wenn Claude fertig ist
   ↓
📦 PreCompact          → Vor Context-Komprimierung
   ↓
🔚 SessionEnd          → Am Ende der Session

EXIT CODES:
  0 = Hook bestanden, weiter
  1 = Warnung/Feedback (nicht blockierend)
  2 = BLOCKIEREN der Aktion

Sicherheits-Hook: Gefährliche Aktionen blockieren

Sicherheits-Hooks sind die zuverlässigste Verteidigung gegen versehentliche oder manipulierte destruktive Befehle. Sie funktionieren auf dem PreToolUse-Event und prüfen JEDEN Shell-Befehl BEVOR er ausgeführt wird. Wenn der Befehl als gefährlich eingestuft wird, wird er blockiert — ohne Ausnahme, ohne Rückfrage, ohne Umgehung. Das Prinzip: Der Hook bekommt den geplanten Bash-Befehl als JSON-Input, analysiert ihn gegen eine Blocklist und gibt einen Exit-Code zurück: 0 für 'erlaubt', 2 für 'blockiert'. Nur bei Exit-Code 0 wird der Befehl tatsächlich ausgeführt. Das geschieht auf Shell-Ebene und kann vom KI-Modell nicht umgangen werden. Welche Befehle solltest du blockieren? Die Klassiker: 'rm -rf' mit kritischen Pfaden (Root, Home), 'DROP TABLE' und 'DROP DATABASE', 'chmod 777' und 'chmod -R 777', 'git push --force' auf main/master, 'curl | bash' (unsichere Remote-Ausführung), 'kill -9' auf Systemprozesse. Diese Befehle haben in einer normalen Claude Code Session selten einen legitimen Grund. Der Hook selbst ist ein Shell-Skript das den JSON-Input parsed und die Befehlszeile gegen Patterns prüft. Du kannst Regex-Patterns für flexible Erkennung nutzen: Nicht nur exakt 'rm -rf /' blockieren, sondern alles was 'rm -rf' mit einem Pfad außerhalb des Projektverzeichnisses enthält. Besonders wertvoll in Team-Umgebungen: Definiere den Hook in .claude/settings.json und committe ihn ins Repository. Jedes Teammitglied hat automatisch den gleichen Schutz. Das ist wichtiger als du denkst: In Monorepos oder bei Prompt-Injection durch manipulierte Dependencies kann ein ungeschützter Agent erheblichen Schaden anrichten. Ein fortgeschrittenes Pattern: Der Hook kann nicht nur blockieren sondern auch WARNEN und LOGGEN. Bei mittleren Risiken gibt er eine Warnung aus und loggt den Befehl, ohne ihn zu blockieren. So hast du Audit-Trail und Awareness ohne den Workflow zu unterbrechen.

// .claude/settings.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/dangerous-actions-blocker.sh"
          }
        ]
      },
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}
#!/bin/bash
# .claude/hooks/protect-files.sh
# Schützt sensible Dateien vor Bearbeitung

INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

# Geschützte Dateien
PROTECTED=(
  ".env"
  ".env.local"
  "credentials.json"
  "docker-compose.prod.yml"
)

for protected in "${PROTECTED[@]}"; do
  if [[ "$FILE_PATH" == *"$protected"* ]]; then
    echo "⛔ BLOCKIERT: $FILE_PATH ist geschützt!"
    exit 2  # Exit Code 2 = Blockieren
  fi
done

exit 0  # Erlauben

Auto-Formatting nach Edits

Automatisches Code-Formatting nach jeder Dateiänderung ist der meistgenutzte Hook in der Claude Code Community — und das aus gutem Grund. Ohne diesen Hook hängt es davon ab ob Claude sich an die Formatierungsregeln erinnert. Mit dem Hook ist der Code IMMER korrekt formatiert, garantiert, bei jeder einzelnen Änderung. Der Hook funktioniert so: Er reagiert auf das PostToolUse-Event mit einem Matcher für 'Edit' und 'Write' — die beiden Tools die Dateien ändern. Nach jeder Dateiänderung wird automatisch dein Formatter (Prettier, ESLint --fix, Black, rustfmt — je nach Sprache) auf der geänderten Datei ausgeführt. Der Vorteil gegenüber einem Prompt wie 'Formatiere immer mit Prettier': Der Hook ist deterministisch. Er vergisst nicht, er interpretiert nicht um, er macht keine Ausnahmen. Egal wie komplex die Aufgabe ist und wie voll das Context Window ist — der Formatter läuft immer. Die Konfiguration ist unkompliziert: Du definierst einen PostToolUse-Hook mit dem Matcher 'Edit|Write', und als Befehl die Formatter-Ausführung. Der Hook bekommt die geänderte Datei als Input und führt den Formatter darauf aus. Ein wichtiger Praxis-Tipp: Konfiguriere den Formatter so dass er nur die geänderte Datei formatiert, nicht das gesamte Projekt. 'prettier --write $FILE' statt 'prettier --write .' — sonst dauert jede Dateiänderung unverhältnismäßig lange. Fortgeschrittene Nutzer kombinieren Formatting mit Linting: Erst formatieren (prettier), dann linten (eslint --fix). So werden nicht nur Formatierung sondern auch einfache Code-Qualitätsprobleme sofort behoben. Für Multi-Sprachen-Projekte kannst du im Hook-Script die Dateiendung prüfen und den passenden Formatter wählen: .ts/.tsx → Prettier, .py → Black, .rs → rustfmt. So hat jede Sprache ihren optimalen Formatter. Dieser eine Hook verbessert die Code-Qualität deines Projekts mehr als die meisten anderen Maßnahmen — mit minimalem Aufwand.

// .claude/settings.json — PostToolUse Hook
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "prettier --write \"$CLAUDE_FILE_PATHS\""
          }
        ]
      }
    ]
  }
}

// Jedes Mal wenn Claude eine Datei bearbeitet oder schreibt,
// wird Prettier automatisch ausgeführt.
// Keine manuellen Formatting-Schritte mehr!

Desktop-Benachrichtigungen

Claude Code Sessions können lang laufen — besonders wenn Claude komplexe Aufgaben bearbeitet oder auf deine Bestätigung für eine Aktion wartet. Ohne Benachrichtigung sitzt du entweder untätig vor dem Terminal und wartest, oder du verpasst den Moment wo Claude dich braucht. Desktop-Notifications lösen dieses Problem elegant. Der Hook nutzt das Notification-Event und das PermissionRequest-Event. Wenn Claude eine Benachrichtigung sendet oder auf eine Permission-Bestätigung wartet, führt der Hook einen System-Befehl aus der eine Desktop-Notification anzeigt. Auf macOS ist das osascript mit einer Notification, auf Linux notify-send, und auf Windows das BurntToast PowerShell-Modul. Der praktische Nutzen: Du startest eine komplexe Aufgabe, wechselst zu einer anderen Anwendung (Browser, E-Mail, Slack), und bekommst eine Desktop-Notification sobald Claude deine Aufmerksamkeit braucht. Das ist effizienter als ständig zwischen Fenstern zu wechseln. Besonders wertvoll wird die Benachrichtigung bei längeren Tasks die mehrere Permission-Anfragen auslösen. Statt 10 Minuten am Terminal zu sitzen und auf die nächste 'Allow?' Frage zu warten, arbeitest du parallel an etwas anderem und reagierst nur auf Notifications. Die Konfiguration ist einfach: Ein Hook auf das Notification- oder PermissionRequest-Event, als Befehl der plattformspezifische Notification-Befehl. Du kannst auch den Inhalt der Notification anpassen — z.B. welches Tool die Permission braucht oder welche Frage Claude hat. Ein fortgeschrittener Tipp: Kombiniere Desktop-Notifications mit Sound-Alerts für kritische Events. Ein leiser Ping bei normalen Notifications, ein auffälliger Sound bei Permission-Anfragen die Schreibzugriff betreffen. So weißt du sofort ob es dringend ist oder warten kann. Dieser Hook ist besonders für Entwickler relevant die mehrere Claude Code Sessions parallel laufen lassen — du bekommst für jede Session eine separate Notification.

// ~/.claude/settings.json (User-Level)
{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude braucht deine Aufmerksamkeit\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

// Linux Alternative:
// "command": "notify-send 'Claude Code' 'Awaiting your input'"

// Windows Alternative:
// "command": "powershell -c [console]::beep()"

SessionStart: Kontext injizieren

Der SessionStart-Hook ist perfekt um bei jedem Session-Beginn automatisch aktuellen Kontext einzuspeisen. Statt jede Session manuell mit den gleichen Informationen zu briefen, lädt der Hook sie automatisch — konsistent, vollständig und ohne dass du daran denken musst. Typische Anwendungsfälle: Den aktuellen Sprint-Status aus dem Issue-Tracker laden, die neuesten Git-Änderungen der letzten 24 Stunden zusammenfassen, Team-Announcements oder Coding-Guidelines die sich kürzlich geändert haben einblenden, oder den aktuellen Build-Status der CI-Pipeline anzeigen. Der Hook wird ausgeführt sobald die Session startet, BEVOR du deine erste Nachricht sendest. Das Ergebnis des Hook-Befehls wird als zusätzlicher Kontext in die Session injiziert. Claude sieht diese Information automatisch und kann sie bei seinen Antworten berücksichtigen. Ein konkretes Beispiel: Dein SessionStart-Hook führt ein Skript aus das die offenen JIRA-Tickets deines Sprints holt, die letzten 5 Commits zusammenfasst und den Status der CI-Pipeline prüft. Claude startet die Session mit dem Wissen: 'Aktueller Sprint: 3 offene Tickets. Letzter Commit vor 2 Stunden von @colleague: Fix payment validation. CI: Grün.' Für Teams ist der SessionStart-Hook besonders wertvoll: Du kannst Team-weite Regeln oder aktuelle Prioritäten automatisch einblenden. Zum Beispiel: 'ACHTUNG: Production-Freeze bis Freitag. Keine Deployments. Nur Bug-Fixes auf dem hotfix-Branch.' Der Hook sollte schnell ausführen — idealerweise unter 2 Sekunden. Komplexe Abfragen die länger dauern (z.B. an externe APIs) solltest du cachen oder asynchron ausführen um den Session-Start nicht zu verzögern. Ein wichtiger Hinweis: Der injizierte Kontext verbraucht Tokens im Context Window. Halte die Informationen knapp und relevant. Ein Absatz mit den wichtigsten Punkten ist besser als ein ganzer Report der nie gelesen wird.

#!/bin/bash
# .claude/hooks/session-context.sh
# Injiziert automatisch Kontext bei jedem Session-Start

echo "📋 Aktueller Projekt-Status:"
echo "Branch: $(git branch --show-current)"
echo "Uncommitted: $(git status --short | wc -l) Dateien"
echo ""
echo "📌 Offene TODOs:"
grep -r "TODO:" src/ --include="*.ts" 2>/dev/null | head -5
echo ""
echo "⚠️ Letzte Fehler:"
tail -5 logs/error.log 2>/dev/null || echo "Keine Fehler"
// Registrierung in settings.json
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/session-context.sh"
          }
        ]
      }
    ]
  }
}

Stop-Hook: Auto-Tests nach Fertigstellung

Der Stop-Hook feuert wenn Claude eine Aufgabe abschließt oder die Session endet. Das ist der perfekte Moment um automatisch Tests auszuführen und sofortiges Feedback zu bekommen ob Claudes Änderungen die bestehende Funktionalität brechen. Das Prinzip: Nach jeder abgeschlossenen Claude-Aufgabe führt der Hook automatisch deine Test-Suite aus. Wenn Tests fehlschlagen, siehst du sofort welche — und kannst Claude direkt bitten sie zu fixen. Das ist schneller und zuverlässiger als manuell daran zu denken Tests auszuführen. Die einfachste Variante: Der Hook führt 'npm test' oder 'pytest' aus und zeigt die Ergebnisse. Die fortgeschrittene Variante: Der Hook führt nur die Tests aus die von den geänderten Dateien betroffen sind (z.B. mit jest --changedSince=HEAD~1), und bei Fehlern wird eine detaillierte Zusammenfassung generiert. Besonders wertvoll ist der Auto-Test Hook bei iterativer Arbeit: Du gibst Claude eine Aufgabe, Claude implementiert sie, der Hook testet sofort, und wenn Tests fehlschlagen, kann Claude sie im nächsten Schritt fixen. Das schafft einen engen Feedback-Loop ohne manuelle Intervention. Ein Wort der Warnung: Der Hook sollte nur schnelle Tests ausführen. Die vollständige E2E-Test-Suite die 5 Minuten dauert ist hier fehl am Platz. Fokussiere auf Unit Tests und schnelle Integration Tests. Für umfassende Tests nutze besser die CI-Pipeline. Du kannst den Hook auch nutzen um andere Qualitäts-Checks durchzuführen: TypeScript-Compilation (npx tsc --noEmit), Lint-Check (eslint --quiet), oder Bundle-Size-Prüfung (npm run build und die Größe prüfen). Die Konfiguration ist einfach: Ein Hook auf das Stop-Event, als Befehl dein Test-Skript. Optional kannst du mit einem Matcher einschränken dass der Hook nur bei bestimmten Session-Typen auslöst — z.B. nur bei 'normal' Sessions, nicht bei 'resume' Sessions.

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/post-stop-checks.sh"
          }
        ]
      }
    ]
  }
}

// post-stop-checks.sh:
// 1. TypeScript Fehler prüfen: npx tsc --noEmit
// 2. Lint-Check: npx eslint src/
// 3. Bei Erfolg: automatischer Commit
// 4. Bei Fehler: Feedback an Claude

Hook-Konfigurationsebenen

Hooks können auf drei verschiedenen Ebenen konfiguriert werden. Jede Ebene hat einen anderen Geltungsbereich und eignet sich für unterschiedliche Szenarien. Das Verständnis dieser Hierarchie hilft dir, Hooks strategisch einzusetzen. Die globale Ebene (~/.claude/settings.json) gilt für ALLE deine Projekte. Hier gehören Hooks hin die du überall nutzen willst: Desktop-Benachrichtigungen, persönliche Code-Formatting-Preferences, oder Kosten-Tracking. Diese Hooks werden bei jeder Claude Code Session geladen, egal in welchem Projekt du arbeitest. Die Projekt-Ebene (.claude/settings.json im Projektstamm) gilt für alle Teammitglieder die an diesem Projekt arbeiten. Hier gehören projektspezifische Hooks hin: Auto-Formatting mit dem Projekt-Formatter, Sicherheits-Hooks die gefährliche Befehle blockieren, SessionStart-Hooks die Projekt-Kontext laden. Diese Datei wird ins Git-Repository committed und automatisch von allen genutzt. Die lokale Ebene (.claude/settings.local.json) gilt nur für dich und wird NICHT committed. Hier gehören persönliche Overrides und Entwicklungs-Hooks hin: Debug-Logging, spezielle Benachrichtigungen, oder temporäre Hooks die du zum Testen nutzt. Die Hierarchie folgt dem Prinzip der Spezifität: Lokale Hooks überschreiben Projekt-Hooks, Projekt-Hooks überschreiben globale Hooks. Wenn auf allen drei Ebenen ein PostToolUse-Hook für Write definiert ist, wird nur der lokale ausgeführt. Eine bewährte Best Practice für Teams: Definiere auf Projekt-Ebene die essentiellen Hooks (Security, Formatting) und lass individuelle Hooks auf lokaler Ebene. So hat jeder Entwickler eine sichere Baseline, kann aber seine eigenen Hooks hinzufügen. Die Konfiguration selbst ist JSON-basiert und folgt einem klaren Schema: Event-Typ, optionaler Matcher (welche Tools/Dateien), Befehlstyp (command, agent, prompt), und der auszuführende Befehl. Mehrere Hooks für das gleiche Event werden sequentiell ausgeführt. Ein Debugging-Tipp: Wenn ein Hook nicht auslöst, prüfe zuerst ob die Event-Konfiguration korrekt ist. Dann ob der Matcher passt. Dann ob der Befehl selbst funktioniert (teste ihn manuell im Terminal).

KONFIGURATIONSEBENEN (Priorität)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

1. Enterprise Policy     → Zentral verwaltet, nicht überschreibbar
2. User Settings         → ~/.claude/settings.json (persönlich)
3. Project Settings      → .claude/settings.json (Team, committed)
4. Project Local         → .claude/settings.local.json (nicht committed)

MATCHERS:
━━━━━━━━
"Bash"           → Nur Bash-Tool
"Edit|Write"     → Edit ODER Write Tool
"Notebook.*"     → Alle Notebook-Tools (Regex)
""               → Kein Matcher = alle Tools
⚠️ Best Practice Hook-Tipps für den Alltag: • Halte Hooks unter 100ms — sie laufen bei JEDER Tool-Ausführung • Hooks kosten keine Tokens — sie laufen lokal auf deinem System • Nutze /hooks im CLI um Hooks interaktiv zu konfigurieren • Teste Hooks mit CLAUDE_CODE_DEBUG=1 claude für Debug-Output • Commit .claude/hooks/ ins Repo für Team-weite Automation

Zusammenfassung