Ich baute 11 Claude Code Hooks. Sechs waren binnen 24 Stunden tot.

7 min read

Ein Hook für Claude Code. Einer. Ein TypeScript-Checker, der npx tsc in einem Bun-Projekt ausführte und die Ausgabe durch head -20 leitete. Bei 12 Fehlern sah ich drei. Geniales System.

Währenddessen konnte mein Agent force-push auf main machen, meine API-Keys leaken und das Repo mit rm -rf löschen, ohne dass ihn etwas aufhielt. Den Vogel abgeschossen hat er, als er auf Prod deployed hat. In der SaaS. Ich hatte ihm explizit gesagt, er soll es nicht tun. Hat er trotzdem gemacht.

Ich schreibe über Claude Code Best Practices. Mein eigenes Setup hatte keine einzige.

Also tat ich, was jeder Entwickler tut, wenn er merkt, dass sein Sicherheitsnetz aus Pappe ist: Ich baute elf Hooks auf einmal. Drei Tage später waren sechs deaktiviert. Die anderen fünf hatte ich vergessen. Genau so sollte es funktionieren, wenn man coden will (ohne den eigenen Code zu lesen) und nachts schlafen möchte. Fast.

TLDR: Die Hooks, die überleben, sind die, die man vergisst (Security, Secrets, destruktive Operationen). Die Hooks, die sterben, sind die, die einen bei jeder Änderung nerven. Ich habe meine drei Tage lang auditiert, 6 von 11 gekillt, und die 5 Überlebenden haben bereits 2 Fast-Leaks und einen Force-Push abgefangen. Auditiert eure heute Abend. Dauert 20 Minuten.

Comic-Strip zeigt überforderten Entwickler am chaotischen Schreibtisch mit Alarmboxen, dann selbstbewussten Helden mit sauberem Monitor und Sicherheitsschildern, satirischer 1970er-Jahre-Stil
Integrationen bauen wie ein Startup-Gründer: 11 Hooks, 6 Verluste, null Überlebende.

Der Eine Hook, Der Mich Retten Sollte

Vor dem Audit bestand mein gesamtes Hook-Setup aus einem PostToolUse-Trigger auf Edit- und Write-Operationen. Er führte npx tsc aus, um TypeScript-Fehler nach jeder Dateiänderung zu prüfen. Zwei Probleme damit.

Erstens läuft das Projekt auf Bun. npx in einem Bun-Projekt auszuführen ist, als würde man seinen französischen Nachbarn bitten, die japanischen Hausaufgaben Korrektur zu lesen. Funktioniert irgendwie. Manchmal. Wenn die Sterne richtig stehen. Zweitens leitete ich durch head -20, was die Ausgabe abschneidet. TypeScript schreit wegen 12 kaputten Types, ich sehe die ersten 3, Claude sieht die ersten 3, und wir nicken beide und machen weiter. Mein Type-Checker checkte keine Types.

Aber das ist der witzige Teil. Dieser kaputte Hook war das einzige, was zwischen meinem Agent und vollem Zugriff auf alles stand. Kein Schutz vor git push --force. Keine Blockade für rm -rf. Kein Secret-Scanning. Kein Deploy-Schutz. Der Agent hätte das Repo nuken, auf main pushen und jeden API-Key im Projekt leaken können. Das einzige, was er nicht tun konnte (theoretisch), war TypeScript zu schreiben, das nicht kompiliert. Und selbst das machte er falsch.

Ich hatte meine CLAUDE.md wie eine echte Config-Datei strukturiert, mit Regeln, mit Grenzen, mit vier Zeilen Integritätsprinzipien. Aber CLAUDE.md ist ein Vorschlag. Der Agent liest sie, denkt darüber nach und entscheidet manchmal, dass er es besser weiß. Ein Hook ist eine Mauer. Exit Code 2, Tool-Call blockiert, keine Verhandlung.

Die Mauer existierte. Sie war nur kaputt.

Mein Sicherheitsnetz war ein Type-Checker, der keine Types checken konnte.

5.000 Likes für Keine Leitplanken

Am 31. März veröffentlichte jemand einen Fork von Claude Code. Der Quellcode war ein paar Tage zuvor durch das npm-Package geleakt (Fortune und CNBC berichteten darüber, ist öffentlich dokumentiert). Der Fork entfernte die Sicherheitsleitplanken aus den Prompts, löschte Telemetrie, entsperrte experimentelle Features und wurde auf IPFS hochgeladen. Er bekam ungefähr fünfmal so viel Aufmerksamkeit wie ein solider Lehrthread über Hooks, den ein Entwickler namens Akshay in derselben Woche postete.

Dieses Verhältnis sagt etwas aus, und es ist nicht, dass Entwickler Sicherheit hassen.

Entwickler hassen Lärm.

Denkt mal drüber nach. Ihr installiert einen Lint-Hook, der bei jeder Dateibearbeitung feuert. Ihr installiert einen Test-Runner, der 4 bis 8 Sekunden pro Speicherung während eines 15-Dateien-Refactorings hinzufügt. Ihr installiert eine Context-Warnung, die alle 20 Minuten aufpoppt und euch sagt, dass die Unterhaltung zu lang wird (ja, ich weiß, ich führe sie). Nach einem Tag davon fangt ihr an, alle Hook-Ausgaben zu ignorieren. Jede Benachrichtigung. Jede Warnung. Auch die echten.

Das Küchen-Rauchmelder-Problem. Das Ding piept jedes Mal, wenn ihr Toast macht. Also reißt ihr die Batterie raus. Und in der einen Nacht, wo wirklich Feuer ist, kein Melder.

Darum geht es bei der Aufmerksamkeitslücke. Nicht "wir wollen keine Leitplanken." Eher "wir wollen nicht eure Leitplanken, die uns 47 Mal am Tag unterbrechen, um nichts Nützliches zu sagen."

Die Schlussfolgerung des Free-Code-Projekts ist aber falsch. Null Leitplanken ist nicht die Antwort. Die Antwort ist, die sechs zu killen, die Lärm machen, und die fünf zu behalten, die einen retten.

Ich habe free-code selbst nicht benutzt. Ich lese diese Zahlen als Marktsignal, nicht als Empfehlung. Aber das Signal ist klar: Wenn man Entwickler zwischen lärmender Sicherheit und Stille wählen lässt, wählen sie jedes Mal die Stille.

3 Tage, 11 Hooks, 6 Leichen

Ich erspare euch den Hook-für-Hook-Durchgang. (Gern geschehen.) Was zählt, ist das Muster, und es war bis Tag zwei offensichtlich: Die Hooks, die überlebten, sind unsichtbar, die Hooks, die starben, waren laut.

Die fünf, die lebten:

Der TypeScript-Checker war ein 30-Sekunden-Fix. npx gegen bunx tauschen, head -20 gegen tail -5 (man will die letzten Fehler, nicht die ersten, weil die ersten meist kaskadierender Lärm von einem echten Break sind). Fing sofort einen Type-Error ab, den Claude drei Edits zuvor eingebaut hatte.

Der Git-Guard war der, den ich zuerst hätte bauen sollen. PreToolUse auf Bash, Pattern-Matching gegen push --force, push.*-f und reset --hard. Tag eins, blockierte einen echten Force-Push. Claude versuchte, einen Merge-Konflikt zu lösen, indem er das Remote mit Gewalt überschrieb. Wäre es durchgegangen, hätte es einen Commit gelöscht, den ich tatsächlich brauchte. Ich mergte die Dangerous-Ops-Pattern in denselben Hook (rm -rf, chmod 777, curl | bash). Ein Hook, eine Regex-Liste, jede Operation, wo "ups" permanent ist.

Der Secret-Scanner läuft PreToolUse auf Edit und Write. Regex für API-Key-Pattern, Bearer-Token, base64-kodierte Credentials. In drei Tagen schlug er zweimal an: ein Bearer-Token hardcoded in einer Test-Datei und ein console.log, das einen kompletten Auth-Header dumpte. Beide wären ohne Ton committed worden. Das sind dieselben Arten von Secrets, die ich ein paar Wochen zuvor in Klartext in .claude/settings.local.json gefunden hatte. Der Scanner fängt sie ab, bevor sie ins Repo gelangen.

Der Deploy-Guard und der MCP-Call-Logger runden die fünf ab. Deploy-Guard: null Trigger in drei Tagen, was genau der Punkt ist (man beurteilt einen Sicherheitsgurt nicht daran, wie oft er auslöst). MCP-Logger: enthüllte, dass Claude dieselbe Ressource viermal pro Unterhaltung fetchte. Kein Safety-Tool, eine Context-Window-Diagnose. Beide bleiben, weil sie null Reibung kosten.

Die sechs, die starben:

Lärm. Drei davon. Der Test-Runner fügte 4 bis 8 Sekunden pro Dateispeicherung hinzu. Während eines Refactorings mit 15 Dateien sind das zwei Minuten Starren aufs Terminal. Nach einem halben Tag deaktiviert. Der Lint-Hook war redundant mit dem TypeScript-Checker (dieselben Fehler, anderes Format, doppelte Unterbrechungen). Die Context-Window-Warnung feuerte alle 20 Minuten. Nach dem zehnten Mal war ich darauf trainiert, jede Hook-Ausgabe zu ignorieren. Das letzte ist das Gefährlichste, was ein Hook tun kann.

Nutzlosigkeit. Zwei davon. Der Bundle-Size-Checker maß das falsche Verzeichnis für das falsche Build-Tool. Der Commit-Message-Enforcer lehnte "generische" Nachrichten ab, aber Claude schreibt standardmäßig bereits anständige Commit-Messages. Ein Problem lösen, das nicht mehr existiert.

Redundanz. Einer. Ein separater Dangerous-Commands-Hook, der dieselben Pattern wie der Git-Guard matchte. Dieselbe Regex, derselbe Exit-Code, zwei Hooks für einen Job. Gemergt und gelöscht.

Sechs down. Fünf stehen.

Ein Guter Hook Ist Einer, Den Man Vergisst

Hier ist, was die Überlebenden von den Toten trennt: Die Überlebenden brachten mich nie dazu, über sie nachzudenken. Sie laufen bei jedem Tool-Call, checken was sie checken, bleiben still, wenn alles in Ordnung ist. Ich bemerke sie nur, wenn sie etwas blockieren. Und wenn sie etwas blockieren, ist es immer etwas, worüber ich froh bin, dass es blockiert wurde.

Die toten Hooks machten das Gegenteil. Sie unterbrachen, verlangsamten, nervten. Und nach genug davon deaktivierte ich sie. Da fängt das echte Problem an.

Ein deaktivierter Hook ist schlimmer als kein Hook. Weil man immer noch denkt, man sei geschützt. Der Secret-Scanner läuft doch, oder? Nun ja, nein, ihr habt ihn letzten Dienstag ausgeschaltet, als ihr den Lint-Lärm satt hattet, und ihr habt vergessen, dass der Scanner in derselben Config war.

Das ist der Failure-Mode, über den niemand spricht. Schlechte Hooks versagen nicht nur. Sie vergiften die guten. Ein lärmender Hook trainiert einen darauf, alle Hook-Ausgaben zu ignorieren, und das schließt den ein, der gerade eure Produktionsdatenbank-Credentials in einem console.log abgefangen hat.

Das hat eine Dimension. Die vier Integritätszeilen in meiner CLAUDE.md ("Never lie, Never hide, Never conceal, Never fail silently") veränderten, wie sich der Agent verhält, aber sie bleiben Vorschläge, die ein Agent unter Druck umgehen kann. Wenn der Agent auf "erledigt" optimiert, behandelt er CLAUDE.md-Regeln als beratend. Ein Hook verhandelt nicht. Exit Code 2, Operation blockiert. Punkt.

Aber Hooks ersetzen CLAUDE.md nicht. Sie decken die Operationen ab, wo Versagen irreversibel ist: ein geleaktes Secret, ein Force-Push, ein versehentliches Deployment. Für alles andere (Code-Style, Architekturentscheidungen, Namenskonventionen) ist CLAUDE.md das richtige Tool. Man baut keine Backsteinmauer, um Variablenbenennung durchzusetzen.

Die Dinge, die eine Mauer brauchen, brauchen aber wirklich eine Mauer.

Die Lücke

Vor dem Audit: ein Hook. Kaputt. Null Sicherheit. Der Agent konnte deployen, löschen und leaken, ohne einen Ton zu machen.

Danach: fünf Hooks. Funktionierend. Decken die drei Dinge ab, die wirklich wichtig sind (Type-Safety, Secrets, destruktive Operationen). Still, wenn alles in Ordnung ist. Laut, wenn nicht.

Die Lücke zwischen "Ich schreibe über Claude Code Best Practices" und "Ich befolge Claude Code Best Practices" war genau vier Hooks breit.

Wie sehen eure aus?

Wenn ihr eure eigenen Hooks nach dem Lesen auditiert, will ich wissen, was ihr findet. Die schlimmsten Entdeckungen machen die besten Geschichten 😅

Quellen

Akshays Thread über Claude Code Hooks Lifecycle und Konfiguration (März 2025, X/Twitter).

(*) Das Cover ist AI-generiert. Die Hooks im Bild sehen sauber aus, weil sie nie eine echte Codebase gesehen haben.