# Hook-System

Hooks ermöglichen es Ihnen, eigene Logik an Schlüsselpunkten im Claude-Code-Lifecycle einzubinden — Code automatisch formatieren, gefährliche Befehle blockieren, Benachrichtigungen senden, Audit-Logs schreiben. Hooks sind einer der leistungsfähigsten Erweiterungsmechanismen von Claude Code.

---

## 1. Grundkonzepte

Jeder Hook besteht aus drei Teilen:

```
Event (When)   →  Matcher (Which)     →  Handler (What)
PreToolUse        matcher: "Bash"        command: "check_safety.sh"
```

- **Event**: wann es ausgelöst wird (z. B. `PreToolUse` — bevor ein Tool ausgeführt wird)
- **Matcher**: ein optionaler Tool-Namen-Filter (nur `Bash`, oder nur `Write`)
- **Handler**: ein Shell-Befehl, eine Prompt-Injektion oder ein Subagent

---

## 2. Vollständige Ereignisliste

### Kern-Ereignisse

| Ereignis | Auslösung | Blockierbar | Typischer Einsatz |
|------|---------|--------|---------|
| **PreToolUse** | Vor der Ausführung eines Tools | Ja (Exit 2) | Sicherheitsabfangen, Argumentvalidierung |
| **PostToolUse** | Nach der Ausführung eines Tools | Nein | Automatische Formatierung, Logging |
| **Notification** | Claude sendet eine Benachrichtigung | Nein | Slack / Feishu / DingTalk-Alarme |
| **Stop** | Claude beendet eine Antwort | Nein | Qualitätsprüfung, automatischer Commit |
| **UserPromptSubmit** | Benutzer reicht einen Prompt ein | Ja | Kontextinjektion, Richtlinienprüfung |
| **SessionStart** | Sitzung startet | Nein | Umgebungseinrichtung, Begrüßungsnachricht |

### Erweiterte Ereignisse (neu in 2026)

| Ereignis | Auslösung | Blockierbar | Typischer Einsatz |
|------|---------|--------|---------|
| **SubagentStop** | Ein Subagent wird beendet | Nein | Subagent-Ergebnisse einsammeln |
| **SubagentToolUse** | Ein Subagent nutzt ein Tool | Ja | Subagent-Berechtigungen einschränken |
| **FileChanged** | Eine Datei wird geändert | Nein | Automatisches Linting, Build auslösen |
| **CwdChanged** | Arbeitsverzeichnis wechselt | Nein | Verzeichnis-spezifische Konfiguration laden |
| **ModelChange** | Modell wird gewechselt | Nein | Modellnutzung nachverfolgen |
| **CompactComplete** | /compact wird beendet | Nein | Nachverarbeitung nach Compaction |
| **ToolError** | Ein Tool wirft einen Fehler | Nein | Fehlererfassung, Retry-Logik |

---

## 3. Handler-Typen

### Typ 1: Command (Shell-Befehl)

Der häufigste Typ — führt einen Shell-Befehl aus:

```json
{
  "type": "command",
  "command": "npx prettier --write $FILEPATH"
}
```

**Umgebungsvariablen**:
| Variable | Bedeutung | Verfügbar in |
|------|------|---------|
| `$FILEPATH` | Pfad der bearbeiteten Datei | PreToolUse/PostToolUse |
| `$TOOL_INPUT` | Tool-Eingabe als JSON | PreToolUse |
| `$TOOL_NAME` | Tool-Name | PreToolUse/PostToolUse |
| `$SESSION_ID` | Sitzungs-ID | Alle |
| `$NOTIFICATION_MESSAGE` | Benachrichtigungstext | Notification |

**stdin-Eingabe**: Ein Hook-Skript empfängt zusätzlich einen JSON-Payload auf **stdin** mit `session_id`, `tool_name` und `tool_input`. Nutzen Sie diesen, wenn Sie strukturierte Daten benötigen — er ist zuverlässiger als das Parsen der Umgebungsvariablen.

**Exit-Codes**:
- `0`: fortsetzen
- `2`: Operation blockieren (nur PreToolUse/UserPromptSubmit)
- jeder andere Wert: wird als Fehler behandelt, blockiert aber nicht

### Typ 2: Prompt (Prompt-Injektion)

Injiziert Text in den Claude-Kontext:

```json
{
  "type": "prompt",
  "prompt": "Remember: every database operation must use a transaction"
}
```

Nützlich für: zusätzliche Projektregeln beim SessionStart injizieren.

### Typ 3: Subagent

Startet einen Subagent zur Verarbeitung des Ereignisses:

```json
{
  "type": "subagent",
  "prompt": "Review the code that was just modified and check for security vulnerabilities"
}
```

Nützlich für: automatische Code-Qualitätsprüfung nach PostToolUse.

---

## 4. Konfiguration

Konfiguration in `.claude/settings.json` (Projekt-Ebene) oder `~/.claude/settings.json` (Benutzer-Ebene):

```json
{
  "hooks": {
    "EventName": [
      {
        "matcher": "tool name (optional, | separates several)",
        "hooks": [
          {
            "type": "command|prompt|subagent",
            "command": "..."
          }
        ]
      }
    ]
  }
}
```

---

## 5. Praxisrezepte

### Rezept 1: Automatische Formatierung nach dem Speichern einer Datei

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write $FILEPATH 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}
```

### Rezept 2: Gefährliche Shell-Befehle blockieren

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo $TOOL_INPUT | grep -qE 'rm -rf /|sudo rm|git push --force|DROP TABLE|DROP DATABASE' && echo 'dangerous command blocked' && exit 2 || exit 0"
          }
        ]
      }
    ]
  }
}
```

### Rezept 3: Sensible Dateien schützen

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Read|Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "echo $TOOL_INPUT | grep -qE '\\.env|\\.env\\.|credentials|secrets?\\.ya?ml|private.key' && echo 'access to a sensitive file blocked' && exit 2 || exit 0"
          }
        ]
      }
    ]
  }
}
```

### Rezept 4: Systembenachrichtigung bei Abschluss einer Aufgabe

**macOS:**
```json
{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"$NOTIFICATION_MESSAGE\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}
```

**Linux:**
```json
{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "notify-send 'Claude Code' \"$NOTIFICATION_MESSAGE\""
          }
        ]
      }
    ]
  }
}
```

### Rezept 5: Slack-Benachrichtigung

```json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "curl -s -X POST https://hooks.slack.com/services/xxx/yyy/zzz -H 'Content-Type: application/json' -d '{\"text\": \"Claude Code task finished\"}'"
          }
        ]
      }
    ]
  }
}
```

### Rezept 6: ESLint-Autokorrektur

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx eslint --fix $FILEPATH 2>/dev/null; npx prettier --write $FILEPATH 2>/dev/null; exit 0"
          }
        ]
      }
    ]
  }
}
```

### Rezept 7: Audit-Log

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo \"$(date -u +%Y-%m-%dT%H:%M:%SZ) | session=$SESSION_ID | tool=$TOOL_NAME | file=$FILEPATH\" >> ~/.claude/audit.log"
          }
        ]
      }
    ]
  }
}
```

### Rezept 8: Tests automatisch ausführen

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "echo $FILEPATH | grep -qE '\\.(ts|tsx|js|jsx)$' && echo $FILEPATH | grep -qvE '\\.test\\.|\\.spec\\.' && npx vitest related $FILEPATH --run 2>/dev/null || exit 0"
          }
        ]
      }
    ]
  }
}
```

### Rezept 9: Migrationsdateien schützen

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "echo $FILEPATH | grep -qE 'migrations/|alembic/versions/' && echo 'editing an existing migration is not allowed, create a new one' && exit 2 || exit 0"
          }
        ]
      }
    ]
  }
}
```

### Rezept 10: Kontext beim Sitzungsstart injizieren

```json
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Important: this project is mid-way through a v3.0 rewrite. All new code must use React Server Components; the pages/ directory is no longer supported."
          }
        ]
      }
    ]
  }
}
```

---
## 6. Enterprise Hooks

### managed-settings.d/-Konfiguration

Enterprise-Administratoren können eine unternehmensweite Sicherheitsrichtlinie über das Verzeichnis `managed-settings.d/` durchsetzen:

```bash
# Create a policy file in the enterprise management directory
mkdir -p /etc/claude-code/managed-settings.d/
```

```json
// /etc/claude-code/managed-settings.d/security.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/opt/claude-policy/check_command.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/opt/claude-policy/audit_log.sh"
          }
        ]
      }
    ]
  }
}
```

Eine Enterprise-Richtlinie **kann nicht durch Benutzer- oder Projektkonfiguration außer Kraft gesetzt werden**.

---

## 7. Debugging

### Ausführlicher Modus

Drücken Sie `Ctrl+O`, um den ausführlichen Modus zu aktivieren. Dieser zeigt:
- wann jeder Hook ausgelöst wird
- stdout/stderr des Hook-Skripts
- den Exit-Code des Hooks

### Häufige Probleme

| Problem | Ursache | Lösung |
|------|------|---------|
| Der Hook wird nie ausgelöst | Tippfehler im Matcher | Groß-/Kleinschreibung des Tool-Namens prüfen: `Bash`, `Write`, `Edit`, `Read` |
| Der Hook blockiert reguläre Arbeit | Die Exit-Code-Logik ist falsch | Sicherstellen, dass der reguläre Pfad `exit 0` ist und nur mit `exit 2` blockiert wird |
| Der Hook ist langsam | Das Skript dauert zu lange | Ein Hook sollte in 1–2 Sekunden abgeschlossen sein; lange Aufgaben im Hintergrund ausführen |
| Eine Umgebungsvariable ist leer | Dieses Ereignis stellt sie nicht bereit | Prüfen Sie die obige Tabelle, welche Variablen das Ereignis bereitstellt |

### Das Hook-Skript testen

Testen Sie es manuell im Terminal, bevor Sie es in die Konfiguration aufnehmen:

```bash
# Simulate the PreToolUse environment variables
FILEPATH="src/main.ts" TOOL_INPUT="rm -rf /" bash -c 'echo $TOOL_INPUT | grep -qE "rm -rf" && echo "blocked" && exit 2 || exit 0'
```

---

## 8. Vergleich mit Codex Hooks

| | Claude Code Hooks | Codex Hooks |
|------|------------------|-------------|
| Anzahl der Ereignisse | 17 | Weniger |
| Konfiguration | settings.json | config.toml |
| Handler-Typen | command/prompt/subagent | command |
| Enterprise-Verwaltung | managed-settings.d/ | Keine |
| Blockierung | Exit-Code 2 | Begrenzt |

---

## Nächste Schritte

- [Skills](/docs/advanced/skills) — ein erweiterter Mechanismus für Erweiterungen
- [MCP-Server](/docs/advanced/mcp) — externe Tools anbinden
- [Automation & CI/CD](/docs/advanced/headless) — den Headless-Modus nutzen
- [CLI-Tipps](/docs/usage/cli-tips) — Techniken für die Befehlszeile