Claude Code Hooks sind benutzerdefinierte Shell-Befehle, die an verschiedenen Punkten im Lebenszyklus von Claude Code ausgeführt werden. Hooks bieten deterministische Kontrolle über das Verhalten von Claude Code und stellen sicher, dass bestimmte Aktionen immer ausgeführt werden, anstatt sich darauf zu verlassen, dass das LLM sie ausführt.

Für Referenzdokumentation zu Hooks siehe Hooks-Referenz.

Beispiele für Anwendungsfälle von Hooks sind:

  • Benachrichtigungen: Passen Sie an, wie Sie benachrichtigt werden, wenn Claude Code auf Ihre Eingabe oder Berechtigung wartet, etwas auszuführen.
  • Automatische Formatierung: Führen Sie prettier auf .ts-Dateien, gofmt auf .go-Dateien usw. nach jeder Dateibearbeitung aus.
  • Protokollierung: Verfolgen und zählen Sie alle ausgeführten Befehle für Compliance oder Debugging.
  • Feedback: Bieten Sie automatisiertes Feedback, wenn Claude Code Code produziert, der nicht Ihren Codebase-Konventionen folgt.
  • Benutzerdefinierte Berechtigungen: Blockieren Sie Änderungen an Produktionsdateien oder sensiblen Verzeichnissen.

Indem Sie diese Regeln als Hooks anstatt als Prompt-Anweisungen kodieren, verwandeln Sie Vorschläge in App-Level-Code, der jedes Mal ausgeführt wird, wenn er ausgeführt werden soll.

Sie müssen die Sicherheitsimplikationen von Hooks berücksichtigen, wenn Sie sie hinzufügen, da Hooks automatisch während der Agent-Schleife mit den Anmeldeinformationen Ihrer aktuellen Umgebung ausgeführt werden. Zum Beispiel kann bösartiger Hook-Code Ihre Daten exfiltrieren. Überprüfen Sie immer Ihre Hook-Implementierung, bevor Sie sie registrieren.

Für vollständige Sicherheits-Best-Practices siehe Sicherheitsüberlegungen in der Hooks-Referenzdokumentation.

Hook-Events-Übersicht

Claude Code bietet mehrere Hook-Events, die an verschiedenen Punkten im Workflow ausgeführt werden:

  • PreToolUse: Läuft vor Tool-Aufrufen (kann sie blockieren)
  • PostToolUse: Läuft nach Abschluss der Tool-Aufrufe
  • UserPromptSubmit: Läuft, wenn der Benutzer einen Prompt einreicht, bevor Claude ihn verarbeitet
  • Notification: Läuft, wenn Claude Code Benachrichtigungen sendet
  • Stop: Läuft, wenn Claude Code die Antwort beendet
  • SubagentStop: Läuft, wenn Subagent-Aufgaben abgeschlossen sind
  • PreCompact: Läuft, bevor Claude Code eine Kompaktierungsoperation ausführt
  • SessionStart: Läuft, wenn Claude Code eine neue Sitzung startet oder eine bestehende Sitzung fortsetzt
  • SessionEnd: Läuft, wenn die Claude Code-Sitzung endet

Jedes Event erhält unterschiedliche Daten und kann Claudes Verhalten auf verschiedene Weise steuern.

Schnellstart

In diesem Schnellstart fügen Sie einen Hook hinzu, der die Shell-Befehle protokolliert, die Claude Code ausführt.

Voraussetzungen

Installieren Sie jq für JSON-Verarbeitung in der Befehlszeile.

Schritt 1: Hooks-Konfiguration öffnen

Führen Sie den /hooks Slash-Befehl aus und wählen Sie das PreToolUse Hook-Event.

PreToolUse Hooks laufen vor Tool-Aufrufen und können sie blockieren, während sie Claude Feedback darüber geben, was anders zu tun ist.

Schritt 2: Einen Matcher hinzufügen

Wählen Sie + Add new matcher…, um Ihren Hook nur bei Bash-Tool-Aufrufen auszuführen.

Geben Sie Bash für den Matcher ein.

Sie können * verwenden, um alle Tools zu matchen.

Schritt 3: Den Hook hinzufügen

Wählen Sie + Add new hook… und geben Sie diesen Befehl ein:

jq -r '"\(.tool_input.command) - \(.tool_input.description // "No description")"' >> ~/.claude/bash-command-log.txt

Schritt 4: Ihre Konfiguration speichern

Für den Speicherort wählen Sie User settings, da Sie in Ihr Home- Verzeichnis protokollieren. Dieser Hook wird dann auf alle Projekte angewendet, nicht nur auf Ihr aktuelles Projekt.

Drücken Sie dann Esc, bis Sie zum REPL zurückkehren. Ihr Hook ist jetzt registriert!

Schritt 5: Ihren Hook verifizieren

Führen Sie /hooks erneut aus oder überprüfen Sie ~/.claude/settings.json, um Ihre Konfiguration zu sehen:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '\"\\(.tool_input.command) - \\(.tool_input.description // \"No description\")\"' >> ~/.claude/bash-command-log.txt"
          }
        ]
      }
    ]
  }
}

Schritt 6: Ihren Hook testen

Bitten Sie Claude, einen einfachen Befehl wie ls auszuführen und überprüfen Sie Ihre Log-Datei:

cat ~/.claude/bash-command-log.txt

Sie sollten Einträge wie diese sehen:

ls - Lists files and directories

Weitere Beispiele

Für eine vollständige Beispielimplementierung siehe das bash command validator example in unserer öffentlichen Codebasis.

Code-Formatierungs-Hook

Automatische Formatierung von TypeScript-Dateien nach der Bearbeitung:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | { read file_path; if echo \"$file_path\" | grep -q '\\.ts$'; then npx prettier --write \"$file_path\"; fi; }"
          }
        ]
      }
    ]
  }
}

Markdown-Formatierungs-Hook

Automatische Behebung fehlender Sprach-Tags und Formatierungsprobleme in Markdown-Dateien:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/markdown_formatter.py"
          }
        ]
      }
    ]
  }
}

Erstellen Sie .claude/hooks/markdown_formatter.py mit diesem Inhalt:

#!/usr/bin/env python3
"""
Markdown formatter for Claude Code output.
Fixes missing language tags and spacing issues while preserving code content.
"""
import json
import sys
import re
import os

def detect_language(code):
    """Best-effort language detection from code content."""
    s = code.strip()
    
    # JSON detection
    if re.search(r'^\s*[{\[]', s):
        try:
            json.loads(s)
            return 'json'
        except:
            pass
    
    # Python detection
    if re.search(r'^\s*def\s+\w+\s*\(', s, re.M) or \
       re.search(r'^\s*(import|from)\s+\w+', s, re.M):
        return 'python'
    
    # JavaScript detection  
    if re.search(r'\b(function\s+\w+\s*\(|const\s+\w+\s*=)', s) or \
       re.search(r'=>|console\.(log|error)', s):
        return 'javascript'
    
    # Bash detection
    if re.search(r'^#!.*\b(bash|sh)\b', s, re.M) or \
       re.search(r'\b(if|then|fi|for|in|do|done)\b', s):
        return 'bash'
    
    # SQL detection
    if re.search(r'\b(SELECT|INSERT|UPDATE|DELETE|CREATE)\s+', s, re.I):
        return 'sql'
        
    return 'text'

def format_markdown(content):
    """Format markdown content with language detection."""
    # Fix unlabeled code fences
    def add_lang_to_fence(match):
        indent, info, body, closing = match.groups()
        if not info.strip():
            lang = detect_language(body)
            return f"{indent}```{lang}\n{body}{closing}\n"
        return match.group(0)
    
    fence_pattern = r'(?ms)^([ \t]{0,3})```([^\n]*)\n(.*?)(\n\1```)\s*$'
    content = re.sub(fence_pattern, add_lang_to_fence, content)
    
    # Fix excessive blank lines (only outside code fences)
    content = re.sub(r'\n{3,}', '\n\n', content)
    
    return content.rstrip() + '\n'

# Main execution
try:
    input_data = json.load(sys.stdin)
    file_path = input_data.get('tool_input', {}).get('file_path', '')
    
    if not file_path.endswith(('.md', '.mdx')):
        sys.exit(0)  # Not a markdown file
    
    if os.path.exists(file_path):
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        formatted = format_markdown(content)
        
        if formatted != content:
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(formatted)
            print(f"✓ Fixed markdown formatting in {file_path}")
    
except Exception as e:
    print(f"Error formatting markdown: {e}", file=sys.stderr)
    sys.exit(1)

Machen Sie das Skript ausführbar:

chmod +x .claude/hooks/markdown_formatter.py

Dieser Hook automatisch:

  • Erkennt Programmiersprachen in unbeschrifteten Code-Blöcken
  • Fügt entsprechende Sprach-Tags für Syntax-Highlighting hinzu
  • Behebt übermäßige Leerzeilen, während Code-Inhalt erhalten bleibt
  • Verarbeitet nur Markdown-Dateien (.md, .mdx)

Benutzerdefinierter Benachrichtigungs-Hook

Erhalten Sie Desktop-Benachrichtigungen, wenn Claude Eingaben benötigt:

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "notify-send 'Claude Code' 'Awaiting your input'"
          }
        ]
      }
    ]
  }
}

Dateischutz-Hook

Blockieren Sie Bearbeitungen an sensiblen Dateien:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "python3 -c \"import json, sys; data=json.load(sys.stdin); path=data.get('tool_input',{}).get('file_path',''); sys.exit(2 if any(p in path for p in ['.env', 'package-lock.json', '.git/']) else 0)\""
          }
        ]
      }
    ]
  }
}

Mehr erfahren

  • Für Referenzdokumentation zu Hooks siehe Hooks-Referenz.
  • Für umfassende Sicherheits-Best-Practices und Sicherheitsrichtlinien siehe Sicherheitsüberlegungen in der Hooks-Referenzdokumentation.
  • Für Fehlerbehebungsschritte und Debugging-Techniken siehe Debugging in der Hooks-Referenz- dokumentation.