Zum Hauptinhalt springen
Alle Artikel

Claude Code Hooks: Event-basierte Automatisierung

Von Manuel HedingerAutomatisierung · 9 Min. Lesezeit
Dual-Monitor mit Event-Pipeline PreToolUse, Edit und PostToolUse neben Code-Editor
Inhalt

Hooks sind das Enforcement-Feature in Claude Code. Während CLAUDE.md Empfehlungen gibt, garantieren Hooks, dass bestimmte Aktionen immer passieren - Auto-Formatting, Security-Checks, Tests.

Was sind Hooks?

Ein Hook ist ein Script oder Command, das bei einem bestimmten Event automatisch ausgeführt wird:

[Claude will Datei editieren]
        ↓
[PreToolUse Hook: Security Check]
        ↓
[Check OK → Edit wird ausgeführt]
        ↓
[PostToolUse Hook: Auto-Format]
        ↓
[Formatierte Datei gespeichert]

Der Unterschied zu CLAUDE.md:

CLAUDE.mdHooks
"Bitte formatiere nach dem Edit"Formatierung passiert garantiert
AdvisoryDeterministic
Claude kann vergessenSystem führt aus

Wichtigste Hook-Events

Die folgende Übersicht deckt die gebräuchlichsten Events ab – die vollständige, aktuelle Liste finden Sie in der Claude-Code-Dokumentation.

Session-Events

EventWannTypische Nutzung
SessionStartSession beginntEnv-Setup, Logging
SessionEndSession endetCleanup, Reporting

User-Events

EventWannTypische Nutzung
UserPromptSubmitUser sendet PromptInput-Validierung, Logging

Tool-Events

EventWannTypische Nutzung
PreToolUseVor Tool-AusführungValidierung, Blocking, Modifikation
PostToolUseNach erfolgreicher AusführungFormatting, Testing, Notifications
PostToolUseFailureNach fehlgeschlagener AusführungError-Logging, Alerts
PermissionRequestBei Permission-DialogAuto-Accept/Deny Logik

Agent-Events

EventWannTypische Nutzung
SubagentStartSubagent wird gestartetLogging, Context-Setup
SubagentStopSubagent ist fertigValidierung, Cleanup
StopClaude ist fertigFinale Checks, Notifications

System-Events

EventWannTypische Nutzung
PreCompactVor Context-KomprimierungState-Saving
NotificationClaude sendet NotificationCustom Alerts

Konfiguration

Locations

Hooks können an verschiedenen Stellen konfiguriert werden:

LocationDateiScope
User~/.claude/settings.jsonAlle Projekte
Project.claude/settings.jsonDieses Projekt (committen)
Local.claude/settings.local.jsonPersönlich (nicht committen)

Grundstruktur

{
  "hooks": {
    "EventName": [
      {
        "matcher": "ToolPattern",
        "hooks": [
          {
            "type": "command",
            "command": "your-script.sh",
            "timeout": 60
          }
        ]
      }
    ]
  }
}

Matcher Patterns

PatternBedeutung
"Write"Exakt das Write-Tool
"Edit|Write"Edit ODER Write
"Notebook.*"Alle Notebook-Tools
"*"Alle Tools

Exit-Code Verhalten

Der Exit-Code Ihres Scripts bestimmt, was passiert:

Exit CodeVerhalten
0Erfolg. stdout wird im Verbose-Mode angezeigt. Bei PreToolUse bedeutet Exit 0 nicht automatisch "allow" – die normale Permission-Logik gilt weiter, sofern Sie nicht per JSON permissionDecision setzen
2Blocking Error auf Events, die Blocking unterstützen (z.B. PreToolUse). stderr wird an Claude zurückgegeben
AndereNon-blocking Error. stderr im Verbose-Mode

Exit Code 2 ist der Schlüssel zum Blockieren – aber nur bei Events mit Blocking-Support. So verhindern Sie z.B. Writes auf kritische Dateien:

#!/bin/bash
# .claude/hooks/protect-production.sh
# Hook-Input kommt als JSON über stdin

FILE_PATH=$(jq -r '.tool_input.file_path // empty')

if [[ "$FILE_PATH" == *"production"* ]]; then
    echo "BLOCKED: Production files sind geschützt!" >&2
    exit 2
fi

exit 0

PreToolUse: Aktionen kontrollieren

Einfaches Blocking

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/protect-paths.sh"
          }
        ]
      }
    ]
  }
}

Script .claude/hooks/protect-paths.sh:

#!/bin/bash
# Tool-Input als JSON über stdin lesen

FILE_PATH=$(jq -r '.tool_input.file_path // empty')

PROTECTED_PATHS=(
    ".env"
    "credentials"
    "secrets"
    "production.config"
)

for pattern in "${PROTECTED_PATHS[@]}"; do
    if [[ "$FILE_PATH" == *"$pattern"* ]]; then
        echo "BLOCKED: $FILE_PATH ist geschützt!" >&2
        exit 2
    fi
done

exit 0

JSON-Output für erweiterte Kontrolle

PreToolUse Hooks können JSON zurückgeben für feinere Kontrolle:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow",
    "permissionDecisionReason": "Docs-Datei auto-approved",
    "updatedInput": {
      "file_path": "/corrected/path/file.ts"
    },
    "additionalContext": "Hinweis: Dies ist eine Docs-Datei."
  }
}
FeldWerteBeschreibung
permissionDecisionallow, deny, askAutomatische Entscheidung
permissionDecisionReasonStringGrund für die Entscheidung
updatedInputObjectModifizierte Tool-Parameter
additionalContextStringExtra-Info für Claude

Beispiel: Auto-Approve für Docs

#!/bin/bash
# .claude/hooks/auto-approve-docs.sh

FILE_PATH=$(jq -r '.tool_input.file_path // empty')

if [[ "$FILE_PATH" == *.md ]] || [[ "$FILE_PATH" == *"/docs/"* ]]; then
    cat << EOF
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow",
    "permissionDecisionReason": "Documentation auto-approved"
  }
}
EOF
fi

exit 0

PostToolUse: Nach Aktionen reagieren

Auto-Formatting

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/auto-format.sh"
          }
        ]
      }
    ]
  }
}

Script:

#!/bin/bash
# .claude/hooks/auto-format.sh

FILE_PATH=$(jq -r '.tool_input.file_path // empty')
[ -z "$FILE_PATH" ] && exit 0

case "$FILE_PATH" in
    *.ts|*.tsx|*.js|*.jsx)
        npx prettier --write "$FILE_PATH" 2>/dev/null
        ;;
    *.py)
        black "$FILE_PATH" 2>/dev/null
        ;;
    *.go)
        gofmt -w "$FILE_PATH" 2>/dev/null
        ;;
esac

exit 0

Auto-Testing

#!/bin/bash
# .claude/hooks/auto-test.sh

FILE_PATH=$(jq -r '.tool_input.file_path // empty')
[ -z "$FILE_PATH" ] && exit 0

# Finde zugehörige Test-Datei
TEST_FILE="${FILE_PATH%.ts}.test.ts"

if [[ -f "$TEST_FILE" ]]; then
    npm test -- "$TEST_FILE" --passWithNoTests 2>&1
fi

exit 0

Prompt-based Hooks

Für Stop und SubagentStop Events können Sie LLM-basierte Hooks nutzen:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Prüfe ob alle Aufgaben erledigt sind: $ARGUMENTS",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

Das LLM (Haiku) evaluiert und gibt zurück:

{
  "ok": true,
  "reason": "Alle Tasks wurden erfolgreich abgeschlossen."
}

Oder bei Problemen:

{
  "ok": false,
  "reason": "Tests wurden nicht ausgeführt."
}

Environment Variables und stdin-JSON

Hooks erhalten Session-Kontext über Umgebungsvariablen und Tool-Details als JSON über stdin:

VariableBeschreibung
CLAUDE_PROJECT_DIRAbsoluter Pfad zum Projekt-Root
CLAUDE_CODE_REMOTEtrue wenn Remote/Web-Session
CLAUDE_ENV_FILE(SessionStart) Pfad für persistente Env-Vars

Tool-Input über stdin (nicht als Env-Vars)

FILE_PATH, COMMAND und ähnliche Felder sind keine Umgebungsvariablen. Der Hook liest sie aus dem JSON auf stdin, z.B.:

FILE_PATH=$(jq -r '.tool_input.file_path // empty')
COMMAND=$(jq -r '.tool_input.command // empty')

Typische Felder unter tool_input je nach Tool:

  • Edit/Write: file_path – Pfad zur bearbeiteten Datei
  • Bash: command – ausgeführter Befehl

Praktische Hook-Sammlung

1. Branch Protection

#!/bin/bash
# Verhindere Commits auf main/master

BRANCH=$(git branch --show-current)

if [[ "$BRANCH" == "main" || "$BRANCH" == "master" ]]; then
    echo "BLOCKED: Direkte Commits auf $BRANCH nicht erlaubt!" >&2
    exit 2
fi

exit 0

2. Commit Message Validation

#!/bin/bash
# Prüfe Conventional Commits Format

MESSAGE="$1"
PATTERN="^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .{1,50}"

if ! [[ "$MESSAGE" =~ $PATTERN ]]; then
    echo "BLOCKED: Commit Message muss Conventional Commits Format folgen!" >&2
    echo "Format: type(scope): description" >&2
    exit 2
fi

exit 0

3. Security Scanning

#!/bin/bash
# Scanne auf Secrets

FILE_PATH=$(jq -r '.tool_input.file_path // empty')
[ -z "$FILE_PATH" ] && exit 0

if grep -E "PRIVATE_KEY|API_KEY|SECRET" "$FILE_PATH" 2>/dev/null; then
    echo "WARNING: Mögliche Secrets gefunden in $FILE_PATH" >&2
    # exit 2  # Uncomment um zu blockieren
fi

exit 0

4. Dependency Check

#!/bin/bash
# Prüfe auf bekannte Vulnerabilities nach package.json Änderung

FILE_PATH=$(jq -r '.tool_input.file_path // empty')

if [[ "$FILE_PATH" == *"package.json"* ]]; then
    npm audit --audit-level=high 2>&1
    if [[ $? -ne 0 ]]; then
        echo "WARNING: npm audit hat Vulnerabilities gefunden" >&2
    fi
fi

exit 0

5. Documentation Reminder

#!/bin/bash
# Erinnere an Docs-Updates bei API-Änderungen

FILE_PATH=$(jq -r '.tool_input.file_path // empty')

if [[ "$FILE_PATH" == *"/api/"* ]]; then
    echo "REMINDER: API geändert - bitte auch Docs aktualisieren" >&2
fi

exit 0

Debugging Hooks

Verbose Mode

claude --verbose

Zeigt stdout aller Hooks (auch bei Exit 0).

Logging in Hooks

#!/bin/bash
# Logging zu File

FILE_PATH=$(jq -r '.tool_input.file_path // empty')
LOG_FILE="$CLAUDE_PROJECT_DIR/.claude/hooks.log"
echo "[$(date)] Hook ausgeführt: $0" >> "$LOG_FILE"
echo "  FILE_PATH: $FILE_PATH" >> "$LOG_FILE"

Häufige Fehler

ProblemLösung
Hook wird nicht ausgeführtPfad prüfen, chmod +x
Exit 2 blockiert nichtstderr nutzen; nur Events mit Blocking-Support (z.B. PreToolUse)
Tool-Felder leerJSON von stdin parsen (jq), nicht auf Env-Vars wie $FILE_PATH warten
Timeouttimeout Feld erhöhen

Best Practices

1. Schnelle Hooks

Hooks sollten schnell sein (< 5 Sekunden). Lange Hooks blockieren den Workflow.

2. Fail-Safe

#!/bin/bash
# Nicht blockieren bei eigenem Fehler

FILE_PATH=$(jq -r '.tool_input.file_path // empty')
[ -z "$FILE_PATH" ] && exit 0

if ! command -v prettier &> /dev/null; then
    # Prettier nicht installiert - nicht blockieren
    exit 0
fi

prettier --write "$FILE_PATH"

3. Klare Fehlermeldungen

echo "BLOCKED: .env Dateien dürfen nicht committet werden!" >&2
echo "Hinweis: Nutze .env.example als Template" >&2
exit 2

4. Dokumentation

Dokumentieren Sie Ihre Hooks für das Team:

## Konfigurierte Hooks

| Event | Hook | Zweck |
|-------|------|-------|
| PreToolUse (Edit) | protect-paths.sh | Schützt kritische Dateien |
| PostToolUse (Edit) | auto-format.sh | Formatiert Code |
| Stop | verify-tests.sh | Prüft Test-Coverage |

Fazit

Hooks transformieren "sollte" in "muss". Auto-Formatting, Security-Checks, Test-Execution - was früher Disziplin erforderte, passiert jetzt automatisch.

Starten Sie mit einem einfachen PostToolUse Hook für Formatting. Wenn Sie den Workflow verinnerlicht haben, erweitern Sie auf Security und Testing.


Weiterführende Artikel:

Sie möchten Hooks für Ihr CI/CD-Setup entwickeln? Hedinger-Digital unterstützt bei Konzeption und Implementierung - Prozessautomatisierung bei Hedinger-Digital. Für die übergeordnete Frage, wo KI in Ihren Abläufen ansetzen soll, gibt es die KI-Beratung für KMU.

Häufige Fragen

Was sind Claude Code Hooks?

Hooks sind Scripts oder Commands, die automatisch bei bestimmten Events ausgeführt werden - z.B. vor einer Dateiänderung (PreToolUse) oder nachdem Claude fertig ist (Stop). Sie garantieren, dass bestimmte Aktionen immer passieren.

Was ist der Unterschied zwischen Hooks und CLAUDE.md?

CLAUDE.md enthält Empfehlungen, die Claude befolgen sollte. Hooks sind deterministisch - sie werden garantiert ausgeführt. Nutzen Sie CLAUDE.md für 'sollte', Hooks für 'muss'.

Welche Hook-Events gibt es?

Die wichtigsten: PreToolUse (vor Tool-Nutzung), PostToolUse (nach Tool-Nutzung), Stop (wenn Claude fertig ist), SessionStart/SessionEnd, UserPromptSubmit, SubagentStart/SubagentStop.

Wie blockiere ich gefährliche Aktionen mit Hooks?

Nutzen Sie PreToolUse mit Exit-Code 2 auf Events, die Blocking unterstützen. Das Script beendet mit Code 2 und schreibt die Fehlermeldung nach stderr – Claude erhält sie und die Aktion wird blockiert. Exit 0 bei PreToolUse bedeutet Erfolg, nicht automatisch 'allow'.

Kann ich Hooks nur für bestimmte Tools konfigurieren?

Ja, mit dem 'matcher' Feld. Sie können exakte Tool-Namen ('Write'), Regex-Patterns ('Edit|Write') oder Wildcards ('*') verwenden, um Hooks auf bestimmte Tools zu beschränken.

Weitere Artikel

Alle Artikel

Was lässt sich bei Ihnen vereinfachen?

Im Erstgespräch klären Sie unverbindlich, welche Aufgaben sich eignen und was ein sinnvoller erster Schritt ist.

Ihre Angaben werden nur zur Beantwortung der Anfrage verwendet. Details in der Datenschutzerklärung.