# Claude Code Hooks: praktischer Leitfaden mit Beispielen

URL: https://agentvera.dev/de/blog/claude-code-hooks-guide/ · Veröffentlicht: 2026-10-23

So funktionieren Claude Code Hooks: Events, settings.json, Matcher, Exit-Codes und JSON-Ausgabe, dazu fertige Hooks zum Formatieren, Blockieren und Benachrichtigen.

**Kurz gesagt:**

- Hooks stehen unter dem Schlüssel hooks in settings.json und laufen immer bei ihrem Event, denn Claude Code führt sie aus, nicht das Modell.
- Um einen Tool-Aufruf zu blockieren, beendet sich ein PreToolUse-Hook mit Code 2 oder gibt JSON mit permissionDecision deny zurück; Exit-Code 1 blockiert nichts.
- Ein Deny-Hook blockiert Aufrufe auch unter --dangerously-skip-permissions, aber Hooks sind keine Sandbox und laufen mit den Rechten deines Nutzers.

Claude Code Hooks sind Befehle, die Claude Code an festen Punkten einer Session selbstständig ausführt: vor einem Tool-Aufruf, nach einer Dateiänderung, beim Absenden eines Prompts, wenn Claude stoppt oder deine Aufmerksamkeit braucht. Du definierst sie unter dem Schlüssel `hooks` in `settings.json`. Ein Hook kann Kontext hinzufügen, eine Datei formatieren oder eine Aktion blockieren, indem er mit Code 2 endet oder eine JSON-Entscheidung zurückgibt. Anders als Anweisungen in `CLAUDE.md` läuft ein Hook immer, weil ihn das Harness ausführt, nicht das Modell.

Dieser Leitfaden behandelt die wichtigen Events, das Konfigurationsformat, Matcher, Exit-Codes und JSON-Ausgabe, drei Hooks zum Kopieren und die Sicherheitshinweise, die du vor dem ersten Hook lesen solltest. Die Fakten stammen aus der offiziellen [Hooks-Referenz](https://code.claude.com/docs/en/hooks "Claude Code hooks reference") und dem [Hooks-Guide](https://code.claude.com/docs/en/hooks-guide "Claude Code hooks guide"). Wenn du nur die kurze Definition suchst, schau in den [Glossareintrag zu Claude Code Hooks](/de/glossary/claude-code-hooks/ "Claude Code Hooks").

## Warum Hooks statt Anweisungen

Du kannst „Nach jeder Änderung immer Prettier ausführen“ in `CLAUDE.md` schreiben, und Claude wird es meistens tun. Meistens ist das Problem. Anweisungen sind Hinweise, die das Modell gegen alles andere in seinem Kontext abwägt. Hooks sind Code, der jedes Mal läuft, wenn das Event feuert.

Deshalb sind Hooks das richtige Werkzeug für drei Arten von Regeln:

- **Dinge, die immer passieren müssen**, wie Formatieren, Linten oder Logging.
- **Dinge, die nie passieren dürfen**, wie `.env` ändern oder `rm -rf` im falschen Ordner ausführen.
- **Dinge, von denen du wissen willst**, etwa dass Claude auf eine Berechtigungsantwort wartet, während du in einem anderen Fenster bist.

Lass Stilhinweise und Projektwissen in [CLAUDE.md](/de/blog/claude-md-agents-md/ "CLAUDE.md und AGENTS.md") und lege harte Regeln in Hooks.

## Hook-Events, die du wirklich brauchst

Die Referenz listet mehr als dreißig Events, und die Liste wächst mit neuen Releases. Die meisten echten Setups nutzen eine Handvoll:

| Event | Wann es feuert | Kann es blockieren? |
| --- | --- | --- |
| `PreToolUse` | Bevor ein Tool-Aufruf läuft | Ja, blockiert den Aufruf |
| `PostToolUse` | Nachdem ein Tool-Aufruf erfolgreich war | Nein, das Tool ist schon gelaufen; stderr geht an Claude |
| `UserPromptSubmit` | Wenn du einen Prompt abschickst | Ja, der Prompt erreicht Claude nie |
| `Notification` | Wenn Claude Code eine Benachrichtigung sendet, etwa eine Berechtigungsabfrage oder Leerlauf-Wartezeit | Nein |
| `Stop` | Wenn Claude seine Antwort beendet | Ja, Claude arbeitet weiter |
| `SubagentStart` / `SubagentStop` | Wenn ein Subagent startet oder endet | Nur `SubagentStop` |
| `SessionStart` | Beim Start, beim Fortsetzen, bei `/clear` oder beim Komprimieren | Nein, aber stdout wird zu Kontext |
| `PreCompact` | Bevor der Kontext komprimiert wird | Ja, blockiert das Komprimieren |
| `PermissionRequest` | Kurz bevor ein Berechtigungsdialog erscheint | Nur über JSON, nicht über Exit 2 |
| `SessionEnd` | Wenn die Session endet | Nein |

`PreToolUse` und `PostToolUse` decken die meisten Bedürfnisse ab. `Notification` und `Stop` sind die für „sag mir Bescheid, wenn es fertig ist oder hängt“.

## So konfigurierst du Hooks in settings.json

Hooks liegen in denselben Settings-Dateien wie Berechtigungen:

| Datei | Geltungsbereich | Über Git geteilt? |
| --- | --- | --- |
| `~/.claude/settings.json` | Alle deine Projekte | Nein |
| `.claude/settings.json` | Ein Projekt | Ja |
| `.claude/settings.local.json` | Ein Projekt, nur du | Nein (gitignored) |
| Managed Policy Settings | Ganze Organisation | Von Admins gesetzt |

Plugins können Hooks in `hooks/hooks.json` mitliefern, und Skills und Subagenten können Hooks in ihrem Frontmatter definieren.

Die Struktur hat drei Ebenen: das Event, eine Matcher-Gruppe und eine Liste von Handlern.

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write",
            "timeout": 30
          }
        ]
      }
    ]
  }
}
```

Der `type` eines Handlers kann `command` (ein Shell-Befehl), `http` (ein POST an eine URL), `mcp_tool` (ein Tool eines verbundenen MCP-Servers), `prompt` (eine schnelle Ja/Nein-Prüfung durch ein Modell) oder `agent` (eine experimentelle Subagenten-Prüfung) sein. Das Standard-Timeout beträgt 600 Sekunden für Command-, HTTP- und MCP-Tool-Handler, 30 Sekunden für Prompt-Hooks und 60 für Agent-Hooks.

Jeder Hook bekommt JSON über stdin. Übliche Felder sind `session_id`, `transcript_path`, `cwd`, `permission_mode` und `hook_event_name`. Tool-Events ergänzen `tool_name`, `tool_input` und `tool_use_id`. Dein Skript liest dieses JSON, meist mit `jq`, und entscheidet, was zu tun ist. Die Umgebungsvariable `CLAUDE_PROJECT_DIR` zeigt auf die Projektwurzel, praktisch, um Skripte aus dem Repo zu referenzieren.

Mit `/hooks` in Claude Code stöberst du durch die geladenen Hooks und siehst, aus welcher Datei jeder stammt. Der Browser ist schreibgeschützt, Hooks änderst du also durch Bearbeiten des JSON.

## Matcher: welche Tool-Aufrufe ein Hook sieht

Der `matcher` bestimmt, welche Aufrufe einen Hook auslösen. Bei Tool-Events trifft er auf den Tool-Namen:

| Matcher | Bedeutung |
| --- | --- |
| `"*"`, `""` oder kein Matcher | Jeder Aufruf |
| `"Bash"` | Genau das Bash-Tool |
| `"Edit\|Write"` | Edit oder Write (eine Liste) |
| `"mcp__memory__.*"` | Jedes Tool des MCP-Servers `memory` |
| `"mcp__.*__write.*"` | Jedes MCP-Tool, dessen Name mit `write` beginnt |

Die Regel ist einfach. Besteht der Matcher nur aus Buchstaben, Ziffern, `_`, `-`, Leerzeichen, Kommas oder `|`, ist er ein exakter Name oder eine Namensliste. Jedes andere Zeichen macht ihn zu einem regulären JavaScript-Ausdruck. MCP-Tools heißen `mcp__<server>__<tool>`.

Manche Events ignorieren den Matcher, darunter `UserPromptSubmit` und `Stop`, weil es nichts zu treffen gibt. Andere treffen etwas anderes als einen Tool-Namen. `SessionStart` trifft, wie die Session gestartet wurde (`startup`, `resume`, `clear`, `compact`), und `Notification` trifft den Benachrichtigungstyp, etwa `permission_prompt` oder `idle_prompt`.

Tool-Events akzeptieren auch ein `if`-Feld mit der Syntax von Berechtigungsregeln, sodass ein Bash-Hook zum Beispiel nur für `"Bash(git *)"` läuft. Die Doku beschreibt das als Best-Effort-Filter, halte die eigentliche Prüfung also in deinem Skript.

## Exit-Codes und JSON-Ausgabe

Ein Command-Hook antwortet Claude Code auf zwei Wegen: über den Exit-Code und über optionales JSON auf stdout.

| Exit-Code | Was passiert |
| --- | --- |
| `0` | Erfolg. stdout wird als JSON geparst, wenn es ein einzelnes JSON-Objekt ist. Bei `UserPromptSubmit` und `SessionStart` wird Klartext auf stdout dem Kontext von Claude hinzugefügt. |
| `2` | Blockierender Fehler. stderr ist der Grund. Bei `PreToolUse` wird der Aufruf abgebrochen, bei `UserPromptSubmit` wird der Prompt abgelehnt, bei `Stop` arbeitet Claude weiter. |
| Alles andere, auch `1` | Nicht blockierender Fehler. Claude Code vermerkt ihn und macht weiter. |

Die Falle ist Exit-Code 1. Viele Skripte scheitern standardmäßig mit 1, und das blockiert **nichts**. Wenn du „stopp“ meinst, beende mit 2.

Für feinere Steuerung beende mit 0 und gib JSON aus. Ein `PreToolUse`-Hook kann erlauben, ablehnen oder nachfragen:

```json
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Use rg instead of grep for better performance"
  }
}
```

`permissionDecision` akzeptiert `allow`, `deny`, `ask` oder `defer`. Ein Hook kann den Aufruf auch mit `updatedInput` umschreiben oder Claude mit `additionalContext` zusätzlichen Text mitgeben. Felder, die bei jedem Event funktionieren, sind `continue: false` (Claude ganz stoppen, mit einem `stopReason`) und `systemMessage` (eine Warnung für dich).

Treffen mehrere Hooks zu, laufen sie parallel, und die restriktivste Antwort gewinnt: deny schlägt defer, defer schlägt ask, ask schlägt allow. Ein `allow` von einem Hook überstimmt keine Deny-Regel in deinen Berechtigungen.

## Beispiel 1: Dateien nach jeder Änderung formatieren

Mit diesem Hook starten die meisten. Er führt Prettier auf jeder Datei aus, die Claude schreibt oder ändert:

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}
```

Tausche für andere Sprachen `ruff format`, `gofmt -w` oder `rustfmt` ein. Da der Formatter nach der Änderung läuft, sieht Claude die formatierte Datei beim nächsten Lesen, und du siehst im Review keine reinen Stil-Diffs mehr.

## Beispiel 2: gefährliche Befehle und geschützte Dateien blockieren

Ein `PreToolUse`-Hook ist der Ort für harte Grenzen. Dieses Skript, angelehnt an den offiziellen Guide, blockiert Änderungen an sensiblen Dateien. Speichere es als `.claude/hooks/protect-files.sh`:

```bash
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")

for pattern in "${PROTECTED_PATTERNS[@]}"; do
  if [[ "$FILE_PATH" == *"$pattern"* ]]; then
    echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
    exit 2
  fi
done

exit 0
```

Mach es mit `chmod +x .claude/hooks/protect-files.sh` ausführbar und registriere es dann:

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}
```

Dasselbe Muster funktioniert für Shell-Befehle. Matche `Bash`, lies `.tool_input.command` und beende mit 2, wenn der Befehl etwas enthält, das du nie willst, etwa `rm -rf /`, `git push --force` oder `DROP TABLE`. Bedenke, dass sich ein String-Check leicht umgehen lässt; sieh ihn also als Sicherheitsgurt, nicht als Schloss.

## Beispiel 3: Desktop-Benachrichtigung bekommen

Lange Aufgaben halten öfter an und warten auf dich, als dir lieb ist. Ein `Notification`-Hook sagt dir sofort Bescheid. Unter macOS:

```json
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}
```

Unter Linux nimmst du stattdessen `notify-send 'Claude Code' 'Claude Code needs your attention'`. Setze den Matcher auf `permission_prompt`, wenn dich nur Berechtigungsanfragen interessieren, oder füge einen `Stop`-Hook mit demselben Befehl hinzu, um zu hören, wann Claude fertig ist.

## Weitere nützliche Muster

- **Kontext nach dem Komprimieren neu einspielen.** Ein `SessionStart`-Hook mit dem Matcher `compact` kann per `echo` eine kurze Erinnerung an deine Regeln ausgeben. Seine stdout-Ausgabe wird dem frischen Kontext hinzugefügt.
- **Konfigurationsänderungen protokollieren.** Ein `ConfigChange`-Hook kann jede Settings-Änderung an eine Logdatei anhängen.
- **Qualitätsschranke bei Stop.** Ein `Stop`-Hook kann deine Tests ausführen und mit 2 und den Fehlern enden, sodass Claude weiter repariert. Prüfe das Feld `stop_hook_active` in der Eingabe, um eine Endlosschleife zu vermeiden. Claude Code übersteuert einen Stop-Hook außerdem nach mehreren Blockaden in Folge.
- **Einen sicheren Prompt automatisch freigeben.** Ein `PermissionRequest`-Hook kann einen bestimmten Dialog mit `{"behavior": "allow"}` im Decision-Objekt beantworten. Halte den Matcher eng.

## Sicherheitshinweise, bevor du Hooks hinzufügst

Hooks laufen als Shell-Befehle mit den Rechten deines Nutzers, ohne zu fragen. Das ist der Sinn der Sache, aber auch das Risiko.

- **Lies Hooks, bevor du einem Repo traust.** Die `.claude/settings.json` eines Projekts kann Hooks mitbringen. Prüfe sie so, wie du ein `postinstall`-Skript prüfen würdest.
- **Setze Variablen in Anführungszeichen.** Die Hook-Eingabe stammt vom Modell, und das Modell liest Dateien und Webseiten, die [Prompt Injection](/de/glossary/prompt-injection/ "Prompt Injection") enthalten können. Nutze `"$VAR"`, werte Eingaben nie mit eval aus und bevorzuge `jq` gegenüber selbstgebautem Parsing.
- **Nutze absolute oder projektrelative Pfade** mit `$CLAUDE_PROJECT_DIR`, damit ein Hook nicht vom aktuellen Ordner abhängt.
- **Halte Hooks schnell.** Ein langsamer `PreToolUse`-Hook bremst jeden Tool-Aufruf. Setze ein `timeout`.
- **Hooks sind keine Sandbox.** Ein Deny-Hook blockiert Aufrufe auch unter `--dangerously-skip-permissions`, was nützlich ist, aber ein entschlossener oder verwirrter Agent kann dasselbe Ergebnis auf anderem Weg erreichen. Kombiniere Hooks mit Deny-Regeln und Isolation, wie in [Sicherheit von KI-Coding-Agenten](/de/blog/ai-coding-agent-security/ "Sicherheit von KI-Coding-Agenten") und [Berechtigungen sicher überspringen](/de/blog/claude-code-skip-permissions/ "Claude Code --dangerously-skip-permissions") beschrieben.
- **Kenne die Ausschalter.** `"disableAllHooks": true` schaltet Hooks ab, und Admins können `allowManagedHooksOnly` in den Managed Settings setzen, um Nutzer- und Projekt-Hooks zu blockieren.

Verhält sich ein Hook falsch, starte Claude Code mit `claude --debug` oder schreibe das Log mit `--debug-file /tmp/claude.log` in eine Datei, um Matcher, Exit-Code und Ausgabe jedes Hooks zu sehen.

## So nutzt AgentVera Hooks

AgentVera ist eine Desktop-App, die Claude Code, Codex, Gemini CLI und andere Coding-CLIs nebeneinander ausführt. Hooks sind ein großer Teil davon, wie es mit Claude Code zusammenarbeitet.

- **Deine Hooks bleiben deine.** AgentVera übergibt jedem Claude Code Prozess seine eigenen Hooks über das Flag `--settings`. Claude Code führt sie mit den Hooks in deinen Settings-Dateien zusammen, und deine `settings.json` wird nicht verändert.
- **Der Agent-Status kommt aus Hooks.** Der Status, den jeder Agent in der App zeigt, wird aus den eigenen Hook-Events der CLI gelesen, nicht aus dem Terminaltext geraten.
- **Smart Tools sind Hooks.** Die Funktion [Smart Tools](/de/features/smart-tools/ "Smart Tools") fügt lokalen Claude Code Agenten vier Hooks hinzu: Sie blockiert wiederholtes Lesen derselben Datei, führt nur die Tests aus, die eine Änderung betrifft, prüft direkt nach einer Änderung auf Fehler und teilt Ergebnisse zwischen Agenten. Sie sind standardmäßig an, und du kannst sie unter Settings → „Token saving“ ausschalten.
- **Kein Notify-Skript nötig.** [Benachrichtigungen und Freigaben](/de/features/notifications-and-approvals/ "Benachrichtigungen und Freigaben") sammeln jeden Agenten, der auf eine Freigabe wartet, in einer Warteschlange, senden Desktop-Benachrichtigungen, solange die App im Hintergrund ist, und können dein Handy über Telegram anpingen.

Auch Qwen Code bekommt die Hooks von AgentVera, weil sein Hook-System den Events und dem JSON-Format von Claude Code folgt.

## Fazit

Starte mit einem `PostToolUse`-Formatter und einer `PreToolUse`-Sperre, prüfe sie mit `/hooks` und `--debug` und füge mehr erst hinzu, wenn eine Regel immer wieder gebrochen wird. Mit Exit 2 blockierst du, gib JSON aus, wenn du mehr Kontrolle brauchst, und behandle jeden Hook als Code, der mit deinen Rechten läuft.

Mehr dazu:

- [Claude Code Hooks (Glossar)](/de/glossary/claude-code-hooks/ "Claude Code Hooks")
- [Smart Tools](/de/features/smart-tools/ "Smart Tools")
- [Benachrichtigungen und Freigaben](/de/features/notifications-and-approvals/ "Benachrichtigungen und Freigaben")
- [Claude Code Agent](/de/agents/claude-code/ "Claude Code in AgentVera")

Um AgentVera auszuprobieren, beginne auf der [Startseite](/de/ "AgentVera").

## Häufige Fragen

**Was sind Claude Code Hooks?** Hooks sind Shell-Befehle, HTTP-Aufrufe, MCP-Tools oder Prompts, die Claude Code an festen Punkten einer Session selbstständig ausführt, etwa vor einem Tool-Aufruf, nach einer Dateiänderung oder wenn Claude deine Aufmerksamkeit braucht. Du definierst sie in settings.json.

**Wohin kommen Claude Code Hooks?** In den Schlüssel hooks einer Settings-Datei: ~/.claude/settings.json für alle deine Projekte, .claude/settings.json für ein Projekt, das du über Git teilst, oder .claude/settings.local.json für ein Projekt nur auf deinem Rechner. Auch Plugins, Skills und Subagenten können Hooks definieren.

**Wie blockiert ein Hook einen Tool-Aufruf?** Ein PreToolUse-Hook beendet sich entweder mit Code 2 und schreibt den Grund nach stderr, oder er beendet sich mit 0 und gibt JSON mit permissionDecision deny aus. Claude Code bricht den Aufruf ab und zeigt Claude den Grund. Exit-Code 1 blockiert nicht.

**Laufen Hooks auch mit --dangerously-skip-permissions?** Ja. Ein Hook, der deny zurückgibt, blockiert den Tool-Aufruf auch im Modus bypassPermissions. Damit ist ein PreToolUse-Hook eine nützliche letzte Sicherung für Befehle, die du nie willst, aber keine Sandbox.

**Wie debugge ich einen Claude Code Hook, der nicht feuert?** Öffne /hooks, um zu sehen, welche Hooks geladen sind und woher sie stammen, prüfe, ob der Matcher genau den Tool-Namen trifft, und starte Claude Code mit --debug oder --debug-file, um jeden Hook-Lauf samt Exit-Code und Ausgabe zu sehen.

---

**Über AgentVera.** AgentVera ist eine Desktop-App für macOS, Windows und Linux, entwickelt von Solviera Teknoloji. Sie führt 18 KI-Coding-Agenten (Claude Code, Codex, Gemini CLI, Copilot, Cursor, Antigravity, opencode, Hermes, Qwen Code, Kimi Code, Kiro, Amp, Droid, Goose, Vibe, Crush, Aider, Cline) nebeneinander aus, pro Projekt, in echten Terminals mit den eigenen CLI-Installationen und Logins des Nutzers. Der kostenlose Plan hat unbegrenzt viele Agenten. Download: https://agentvera.dev/de/download/ · Preise: https://agentvera.dev/de/pricing/
