Feedback-stegen
Om en agents första signal är en röd CI-körning tjugo minuter efter pushen — eller en mänsklig granskning nästa dag — kostar varje misstag en hel tur-och-retur. Samma misstag blir billigare ju tidigare det upptäcks. Claude Codes egna best practices sätter det först på listan: "Ge Claude en kontroll den kan köra: tester, en build, en skärmdump att jämföra med. Det är skillnaden mellan en session du bevakar och en du kan gå ifrån." [1]
Det här är inget nytt. Continuous integration har alltid handlat om snabb feedback — Martin Fowler kallar en tiominutersbuild "fullt rimligt" [9] och DORA beskriver CI som att få feedback inom några minuter. [10] Agenter gör bara tur-och-retur-resorna tätare. Ordna kontrollerna som en stege:
Vid varje ändring — agent-hooks
Formatera och lint:a den ändrade filen i samma stund den skrivs: Cursors afterFileEdit-hook, Claude Codes PostToolUse-hook.
När agenten tror att den är klar — en stop-hook
Kör kontrollerna; om de misslyckas, skicka tillbaka agenten till arbetet. Cursors stop-hook kan returnera ett followup_message; Claude Codes Stop-hook kan blockera avslutet.
Vid commit — en git pre-commit-hook
Build, typkontroll, formatkontroll, komplexitetskontroll. Misslyckas snabbt och blockerar commiten.
Vid push / pull request — CI
Fulla tester med täckningströsklar, workflow-linting.
Före merge — den dyra delen
End-to-end-sviter, automatiserad granskning, sedan en människa.
Både Cursor och Claude Code dokumenterar dessa hooks. [3] [2] GitButlers genomgång är en bra rundtur i hur Cursors hooks triggar i praktiken. [4]
Instruktioner är råd, hooks är garantier
En regel i AGENTS.md, CLAUDE.md eller Cursor-regler är något agenten bör göra. En hook som blockerar commiten är något den inte kan undvika. Claude Codes dokumentation säger det rakt ut:
"Till skillnad från CLAUDE.md-instruktioner, som är rådgivande, är hooks deterministiska och garanterar att åtgärden sker." [1]
Lägg därför "alltid"-regler i hooks. Behåll instruktionsfilen för sådant som kräver omdöme — hur du namnger saker, vilka mönster som föredras — och låt koden sköta resten. Och säg i dina agentinstruktioner att --no-verify aldrig är tillåtet, med CI som sista skydd för allt som ändå slinker igenom.
Skriv felmeddelanden för agenten
En kontroll som misslyckas bör säga vad som ska göras, inte bara vad som är fel. "Formatering misslyckades" skickar agenten på jakt; "Kör npm run format och staga ändringarna" blir åtgärdat i ett steg.
Ett exempel från våra egna repon: vår komplexitetskontroll använder FTA, Fast TypeScript Analyzer, med en tröskel på 60. FTA:s egen skala märker poäng med "OK", "Kan bli bättre" och "Behöver förbättras" — deras dokumentation visar 64.17 som "Behöver förbättras". [8] När en fil går över gränsen misslyckas kontrollen inte bara — den skriver ut en körklar refaktoreringsbrief som pekar ut den värsta filen:
✖ 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 typecheckAgenten läser det och fixar problemet i samma körning. Meddelandet är den billigaste prompten du någonsin skriver, eftersom den dyker upp precis när den behövs.
Håll commit-hooken snabb
Sekunder, inte minuter. En långsam hook lär agenter — och människor — att kringgå den. Lint:a och formatera bara filerna som committas: det är precis vad lint-staged är till för, att köra uppgifter mot enbart stagade filer. [7] Hook-hanterare som Husky gör hooken till en del av repot så att den installeras med projektet. [6]
Flytta allt långsamt högre upp i stegen. I CI, avbryt körningar som en nyare push har gjort överflödiga med cancel-in-progress: true [11] och tvinga fram täckning med trösklar — sätt en radtröskel till 90 och körningen misslyckas under 90 %. [12]
Säkerställ att hookarna faktiskt körs i agentens miljö
Git letar efter hooks i .git/hooks som standard, men core.hooksPath kan peka den någon annanstans. [5] Vi fick lära oss det den hårda vägen: i våra Cursor Cloud Agent-miljöer pekade core.hooksPath mot agentens egen hook-katalog, som sedan kedjade vidare till .git/hooks. Husky förlitar sig också på core.hooksPath — så vår pre-commit-grind slutade köra helt tyst.
Vår lösning var ett litet skript som skriver .git/hooks/pre-commit så att den kedjar till Husky-hooken, körs vid installation och igen varje gång miljön startar. Cursor kör numera även projekthooks i cloud agents: "Cloud agents run command-based hooks from your repository" via .cursor/hooks.json. [3]
Oavsett vilken väg du väljer, verifiera den: gör en commit i agentmiljön som borde misslyckas, och kontrollera att den gör det.
Exempel: en gate-zero-uppsättning
Så här ser det ut i varje repo vi kör. En pre-commit-grind med build → typkontroll → formatkontroll → komplexitetskontroll, som misslyckas vid första felet med en enradig fixhint. CI kör sedan lint, tester med täckningströsklar (95 % statements, lines och functions) och workflow-linting. End-to-end-tester körs bara på pull requests märkta redo att mergas.
{
"version": 1,
"hooks": {
"afterFileEdit": [{ "command": "./scripts/hooks/format-changed.sh" }],
"stop": [{ "command": "./scripts/hooks/gate.sh", "loop_limit": 3 }]
}
}En stop-hook skickar tillbaka agenten genom att skriva ut ett followup_message, inte genom att misslyckas; loop_limit sätter en övre gräns för hur många gånger den kan göra det (Cursors standard är 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 tar emot den redigerade filens sökväg som JSON på stdin (file_path), så format-changed.sh bör läsa den därifrån — till exempel med 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 > 60Vår grind kör en build och typkontroll för hela projektet eftersom båda är snabba i våra repon. Om dina tar mer än några sekunder, flytta dem till stop-hooken eller CI och håll pre-commit till stagade filer.
Se skripten som en startpunkt, inte en färdig lösning. Mönstret betyder mer än verktygen: samma kontroller, på varje steg, som blir långsammare och mer grundliga ju högre upp du kommer.
Var Aerunit kommer in
Snabba kontroller avgör hur många tur-och-retur-resor en pull request tar, och tur-och-retur-resor avgör hur många agenter du kan hålla sysselsatta. Aerunits stories bär definitionen av klart — inklusive vilka kontroller som måste klara sig — så agenten känner till ribban innan den börjar. När agenten öppnar en PR granskar Aerunit den automatiskt och kan skicka tillbaka fynden till agentens session: det sista automatiserade steget innan en människa tittar.
Teamkonventioner — som "använd aldrig --no-verify" eller "kör komplexitetskontrollen innan commit" — lever på ett ställe i Aerunits delade kontext och skills och matas in i varje story och körning. Mer om det sista steget i vår guide om att granska agenters pull requests.
Klart, definierat
Stories anger vilka kontroller som måste klara sig innan agenten börjar.
Automatisk granskning
Varje agent-PR granskas, fynden skickas tillbaka till samma session.
Delade konventioner
Regler som "använd aldrig --no-verify" skrivna en gång och inmatade i varje story och körning.
Vanliga frågor
Blir inte agenten långsammare av pre-commit-hooks?
Bara om de är långsamma. Håll commit-hooken till sekunder: kontrollera enbart stagade filer och lämna den fulla testsviten till CI. En snabb hook sparar tid, eftersom agenten fixar problemet i samma körning istället för att vänta på en röd CI-build och pusha igen. [7]
Pre-commit-hook eller agent-hook — vilken ska man välja?
Båda, för olika jobb. Agent-hooks (Cursors afterFileEdit och stop, Claude Codes PostToolUse och Stop) ger feedback under körningen. En git pre-commit-hook skyddar commiten för alla som committar, människa eller agent. CI är sista skyddet för allt som slinker förbi båda. [3] [2]
Vad ska aldrig vara med i en pre-commit-hook?
Allt som är långsamt, flaky eller nätverksberoende: end-to-end-sviter, fulla builds av orelaterade paket, anrop till externa tjänster. Det hör hemma längre upp i stegen — i CI, eller först när en pull request markeras redo att mergas.
Hur får jag samma kontroller att fungera för både människor och agenter?
Lägg kontrollerna i repot, inte i något enskilt verktyg: package-script, en git-hook som installeras vid setup, och CI som kör samma kommandon. Då anropar både agent-hooks och mänskliga commits samma script, och ingen har en egen privat version av reglerna.
Källor
- [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