Die Feedback-Leiter
Wenn das erste Signal für einen Agenten ein roter CI-Lauf zwanzig Minuten nach dem Push ist — oder ein menschliches Review am nächsten Tag — kostet jeder Fehler einen vollen Umweg. Derselbe Fehler wird billiger, je früher er auffällt. Claude Codes eigene Best Practices setzen das an erste Stelle: "Gib Claude einen Check, den es ausführen kann: Tests, einen Build, einen Screenshot zum Vergleich. Das ist der Unterschied zwischen einer Session, die du beobachtest, und einer, bei der du weggehen kannst." [1]
Das ist nichts Neues. Continuous Integration ging schon immer um schnelles Feedback — Martin Fowler nennt einen Zehn-Minuten-Build "durchaus vertretbar" [9] und DORA beschreibt CI als Feedback innerhalb weniger Minuten. [10] Agenten machen den Umweg nur häufiger. Ordne die Checks wie eine Leiter an:
Bei jeder Änderung — Agent-Hooks
Formatiere und linte die geänderte Datei in dem Moment, in dem sie geschrieben wird: Cursors afterFileEdit-Hook, Claude Codes PostToolUse-Hook.
Wenn der Agent denkt, er sei fertig — ein Stop-Hook
Führe die Checks aus; schlagen sie fehl, schicke den Agenten zurück an die Arbeit. Cursors Stop-Hook kann eine followup_message zurückgeben; Claude Codes Stop-Hook kann das Beenden blockieren.
Beim Commit — ein Git-Pre-Commit-Hook
Build, Typprüfung, Formatprüfung, Komplexitätsprüfung. Schnell fehlschlagen und den Commit blockieren.
Beim Push / Pull Request — CI
Vollständige Tests mit Abdeckungsgrenzen, Workflow-Linting.
Vor dem Merge — der teure Teil
End-to-End-Suites, automatisiertes Review, dann ein Mensch.
Sowohl Cursor als auch Claude Code dokumentieren diese Hooks. [3] [2] GitButlers Walkthrough gibt einen guten Überblick darüber, wie Cursors Hooks in der Praxis auslösen. [4]
Anweisungen sind Ratschläge, Hooks sind Garantien
Eine Regel in AGENTS.md, CLAUDE.md oder Cursor-Regeln ist etwas, das der Agent tun sollte. Ein Hook, der den Commit blockiert, ist etwas, dem er nicht ausweichen kann. Claude Codes Dokumentation sagt es unverblümt:
"Im Gegensatz zu CLAUDE.md-Anweisungen, die beratend sind, sind Hooks deterministisch und garantieren, dass die Aktion stattfindet." [1]
Lege also "Immer"-Regeln in Hooks ab. Behalte die Anweisungsdatei für Dinge, die Urteilsvermögen erfordern — wie du Dinge benennst, welche Muster bevorzugt werden — und lass den Code den Rest durchsetzen. Und sag in deinen Agentenanweisungen, dass --no-verify niemals erlaubt ist, wobei CI das Sicherheitsnetz für alles ist, was trotzdem durchrutscht.
Fehlermeldungen für den Agenten schreiben
Ein fehlgeschlagener Check sollte sagen, was zu tun ist, nicht nur, was falsch ist. "Formatierung fehlgeschlagen" schickt den Agenten auf die Suche; "Führe npm run format aus und stage die Änderungen" ist in einem Schritt behoben.
Ein Beispiel aus unseren eigenen Repositories: Unsere Komplexitätsprüfung nutzt FTA, den Fast TypeScript Analyzer, mit einem Schwellenwert von 60. FTAs eigene Skala kennzeichnet Werte mit "OK", "Könnte besser sein" und "Verbesserung nötig" — die Doku zeigt 64.17 als "Verbesserung nötig". [8] Überschreitet eine Datei den Wert, schlägt der Check nicht nur fehl — er druckt ein sofort nutzbares Refactoring-Briefing mit der schlechtesten Datei aus:
✖ FTA score 71.4 > 60 in src/billing/invoice.ts
Refactor brief:
1. Plan first: list the responsibilities in this file.
2. Separate routing, business logic and data access.
3. Keep behavior unchanged — no new features.
4. Re-run: npm run complexity
5. Then: npm run format && npm run typecheckDer Agent liest das und behebt das Problem im selben Durchlauf. Die Meldung ist der billigste Prompt, den du je schreiben wirst, weil sie genau dann ankommt, wenn sie gebraucht wird.
Den Commit-Hook schnell halten
Sekunden, nicht Minuten. Ein langsamer Hook bringt Agenten — und Menschen — bei, ihn zu umgehen. Linte und formatiere nur die committeten Dateien: genau dafür ist lint-staged da, es führt Aufgaben nur gegen gestagte Dateien aus. [7] Hook-Manager wie Husky machen den Hook zu einem Teil des Repositories, sodass er mit dem Projekt installiert wird. [6]
Schiebe alles Langsame weiter nach oben auf der Leiter. In der CI Läufe abbrechen, die ein neuerer Push überflüssig gemacht hat, mit cancel-in-progress: true [11] und Abdeckung mit Schwellenwerten erzwingen — setze einen Zeilen-Schwellenwert auf 90, und der Lauf schlägt unter 90 % fehl. [12]
Sicherstellen, dass die Hooks in der Umgebung des Agenten wirklich laufen
Git sucht standardmäßig nach Hooks in .git/hooks, aber core.hooksPath kann woanders hinzeigen. [5] Das haben wir auf die harte Tour gelernt: In unseren Cursor Cloud Agent-Umgebungen zeigte core.hooksPath auf das eigene Hook-Verzeichnis des Agenten, das wiederum zu .git/hooks weiterleitete. Husky verlässt sich ebenfalls auf core.hooksPath — unser Pre-Commit-Gate lief also still und leise nicht mehr.
Unsere Lösung war ein kleines Skript, das .git/hooks/pre-commit schreibt, um zum Husky-Hook weiterzuleiten, ausgeführt bei der Installation und erneut bei jedem Start der Umgebung. Cursor führt mittlerweile auch Projekt-Hooks in Cloud-Agents aus: "Cloud agents run command-based hooks from your repository" über .cursor/hooks.json. [3]
Egal welchen Weg du wählst, verifiziere ihn: Mache innerhalb der Agentenumgebung einen Commit, der fehlschlagen sollte, und prüfe, dass er das tut.
Beispiel: ein Gate-Zero-Setup
So sieht es bei uns in jedem Repository aus. Ein Pre-Commit-Gate aus Build → Typprüfung → Formatprüfung → Komplexitätsprüfung, das beim ersten Fehler mit einem einzeiligen Fix-Hinweis abbricht. Die CI führt dann Lint, Tests mit Abdeckungsgrenzen (95 % Statements, Lines und Functions) und Workflow-Linting aus. End-to-End-Tests laufen nur bei Pull Requests, die als mergebereit markiert sind.
{
"version": 1,
"hooks": {
"afterFileEdit": [{ "command": "./scripts/hooks/format-changed.sh" }],
"stop": [{ "command": "./scripts/hooks/gate.sh", "loop_limit": 3 }]
}
}Ein Stop-Hook schickt den Agenten zurück, indem er eine followup_message ausgibt, nicht indem er fehlschlägt; loop_limit begrenzt, wie oft das passieren kann (Cursors Standard ist 5). [3]
#!/bin/sh
# Cursor stop hook: run the checks; if they fail, send the agent back with the output.
if ! out=$(npm run --silent check 2>&1); then
msg=$(printf 'Checks failed. Fix these before finishing:\n%s' "$out")
jq -n --arg msg "$msg" '{followup_message: $msg}'
fiafterFileEdit erhält den Pfad der geänderten Datei als JSON auf stdin (file_path), daher sollte format-changed.sh ihn von dort lesen — zum Beispiel mit jq -r .file_path.
npm run build || { echo "Build failed. Fix the errors above."; exit 1; }
npm run typecheck || { echo "Type errors. Fix them before committing."; exit 1; }
npm run format:check || { echo "Run \"npm run format\" then stage the changes."; exit 1; }
npm run complexity # prints a refactor brief when a file scores > 60Unser Gate führt einen Build und eine Typprüfung für das gesamte Projekt aus, weil beides in unseren Repositories schnell ist. Wenn deine mehr als ein paar Sekunden brauchen, verschiebe sie in den Stop-Hook oder die CI und beschränke Pre-Commit auf gestagte Dateien.
Betrachte die Skripte als Ausgangspunkt, nicht als fertige Lösung. Das Muster zählt mehr als die Werkzeuge: dieselben Checks auf jeder Sprosse, langsamer und gründlicher, je höher du steigst.
Wo Aerunit ansetzt
Schnelle Checks entscheiden, wie viele Runden ein Pull Request braucht, und Runden entscheiden, wie viele Agenten du gleichzeitig beschäftigen kannst. Aerunits Stories tragen die Definition von "erledigt" — einschließlich der Checks, die bestehen müssen — sodass der Agent die Messlatte kennt, bevor er beginnt. Öffnet der Agent einen PR, überprüft Aerunit ihn automatisch und kann die Befunde zurück in die Session des Agenten schicken: die letzte automatisierte Sprosse, bevor ein Mensch hinschaut.
Team-Konventionen — wie "--no-verify niemals verwenden" oder "die Komplexitätsprüfung vor dem Commit ausführen" — leben einmalig in Aerunits geteiltem Kontext und Skills und fließen in jede Story und jeden Lauf ein. Mehr zu dieser letzten Sprosse in unserem Guide zum Reviewen von Agent-Pull-Requests.
Erledigt, definiert
Stories legen fest, welche Checks bestehen müssen, bevor der Agent startet.
Automatisches Review
Jeder Agent-PR wird geprüft, Befunde gehen zurück an dieselbe Session.
Geteilte Konventionen
Regeln wie "--no-verify niemals verwenden" einmal geschrieben und in jede Story und jeden Lauf eingespeist.
Häufige Fragen
Bremsen Pre-Commit-Hooks den Agenten nicht aus?
Nur wenn sie langsam sind. Halte den Commit-Hook auf Sekunden: prüfe nur gestagte Dateien und überlasse die volle Testsuite der CI. Ein schneller Hook spart Zeit, weil der Agent das Problem im selben Durchlauf behebt, statt auf einen roten CI-Build zu warten und erneut zu pushen. [7]
Pre-Commit-Hook oder Agent-Hook — welcher davon?
Beide, für unterschiedliche Aufgaben. Agent-Hooks (Cursors afterFileEdit und stop, Claude Codes PostToolUse und Stop) liefern Feedback während des Laufs. Ein Git-Pre-Commit-Hook schützt den Commit für jeden Autor, ob Mensch oder Agent. CI ist das Sicherheitsnetz für alles, was beide umgeht. [3] [2]
Was darf niemals in einem Pre-Commit-Hook stehen?
Alles Langsame, Flaky oder Netzwerkabhängige: End-to-End-Suites, vollständige Builds unbeteiligter Pakete, Aufrufe externer Dienste. Das gehört weiter oben auf der Leiter — in die CI, oder erst wenn ein Pull Request als mergebereit markiert ist.
Wie sorge ich dafür, dass dieselben Checks für Menschen und Agenten funktionieren?
Lege die Checks im Repository ab, nicht in einem einzelnen Tool: Package-Skripte, ein bei der Einrichtung installierter Git-Hook und eine CI, die dieselben Befehle ausführt. Dann rufen Agent-Hooks und menschliche Commits dieselben Skripte auf, und niemand hat eine eigene private Version der Regeln.
Quellen
- [1]Claude Code Docs — Best practices
- [2]Claude Code Docs — Hooks guide
- [3]Cursor Docs — Hooks
- [4]GitButler (vendor blog) — Cursor hooks deep dive
- [5]Git — githooks documentation
- [6]Husky — Git hooks made easy
- [7]lint-staged — Run tasks against staged files
- [8]FTA — Fast TypeScript Analyzer
- [9]Martin Fowler — Continuous Integration
- [10]DORA — Continuous integration capability
- [11]GitHub Docs — Control workflow concurrency
- [12]Vitest — Coverage configuration