← Blog

Tooling

Agent-code auditen: de checklist voor een productie-herbouw

Drie agency-teams stuurden ons repo's waar elke check groen was en de on-call binnen een maand verdubbelde. Dit is de audit die we nu draaien voor we offreren.

Jacob Molkenboer· Oprichter · A Brand New Company· 8 jun 2026· 9 min
Leren logboek naast een rij messing splitpennen op ivoorpapier, één pen met een lichtgroen lint omwikkeld.

Een founder appte ons op donderdagavond met een repo-URL en één vraag: wat kost het om dit te herbouwen op een stack die we vertrouwen. De CI-badge was groen. Elke deploy in zijn Vercel-dashboard was uitgerold. De repo had acht maanden aan commits, bijna allemaal met dezelfde agent-harness-signatuur. De on-call van zijn team was zes weken stil geweest. Toen ging productie timeouts geven onder load. Toen stopte een webhook stilletjes met retryen. Toen vuurde een cron job dubbel en werden zeshonderd klanten op één ochtend twee keer afgeschreven.

Dit was de derde repo die we in acht maanden zagen met dezelfde vorm: groen aan de voorkant, verrassing aan de achterkant. We zijn na de tweede gestopt met blind offreren voor herbouw. Nu draaien we eerst een audit, en pas dan schrijven we een bedrag op.

Het gat tussen groene CI en rode pager

Een agent-harness, Codex of Claude Code of Cursor of je eigen homebrew, is geoptimaliseerd om de falende test te laten slagen. Dat is niet hetzelfde doel als 'productie overleven'. De agent schrijft de test die hij in gedachten had, schrijft dan de code die de test laat slagen, en CI springt op groen. Niets in die loop dwingt de agent om te vragen: wat als de third-party API ons rate-limit, wat als deze cron job twee keer draait, wat als de database negentig seconden read-only is tijdens een failover.

Je kunt die vragen zelf in de loop weven. De meeste teams doen dat niet, omdat de agent nooit klaagde en de demo's bleven aankomen. Het gat duikt zes maanden later op als on-call-druk die op nalatigheid lijkt, maar eigenlijk een categoriefout is: een testsuite die het happy path kent en bijna niets anders.

Wat we als eerste openen

Voor we ook maar één regel applicatiecode lezen, openen we vier dingen op volgorde: het instructiebestand dat de harness leest (agents.md, CLAUDE.md, .cursorrules, hoe het deze maand ook heet), de harness-sessielogs als die bewaard zijn, de git log in platte tekst, en één productie-errorlog van de afgelopen zeven dagen. Elk van deze vertelt ons meer dan de broncode ooit zal doen.

De agents.md-conventie maakte deze audit sneller. Daarvoor had elke harness zijn eigen dotfile en de helft was niet gedocumenteerd. Een repo zonder enig instructiebestand is niet automatisch een rode vlag, maar het betekent wel dat de agent de hele tijd op training-defaults draaide. Dat correleert vaak met de defaults die pasten op de dag dat het project begon, niet de defaults die nu passen bij het systeem in productie.

Het instructiebestand

De grootste indicator van harness-kwaliteit is het instructiebestand. We checken vier dingen. Wanneer is het voor het laatst aangepast, ten opzichte van de laatste twintig commits. Wie schreef het, de agent of een mens. Of het zichzelf tegenspreekt tussen secties. En of het de agent voorbeelden geeft, niet alleen regels.

Een slecht instructiebestand is vierduizend woorden 'altijd' en 'nooit' zonder een enkele code-referentie. De agent moet raden wat 'gebruik clean architecture' of 'verkies pure functies' in deze codebase betekent, en hij raadt elke sessie anders. Een goed instructiebestand is kort, wijst naar drie echte bestanden in de repo, en zegt 'doe het zoals dit'. De harness geeft twee keer op rij hetzelfde antwoord.

Als het bestand acht weken niet is aangeraakt en de codebase ondertussen twee features uitrolde, is het verouderd, en heeft de agent het zelf zitten verzinnen. Dat is te repareren. Wat niet te repareren is, is het bestand dat in paragraaf twee één ding zegt en in paragraaf negen het tegenovergestelde. We hebben dit vaak genoeg gezien om het te verwachten voor we het bestand openen.

Tool-permissies en shell-bereik

Wat kan de agent eigenlijk draaien? Bash zonder restricties, of alleen een lijstje npm-scripts? Mag hij het filesystem buiten de repo-root aanraken? Heeft hij netwerktoegang tijdens builds? Heeft hij ooit naar main gepusht zonder dat er een mens tussen zat?

Hier begint schaduw-infrastructuur. Een agent met onbeperkte shell zal, gegeven genoeg tijd, een tool installeren waar niemand anders van weet, een script naar /tmp schrijven dat ineens load-bearing wordt, of stilletjes een cron-entry toevoegen. Niets daarvan staat in de repo. Alles daarvan duikt op in de pager. We greppen op shell-out-patronen in de harness-logs en stellen het team één vraag: noem elke binary die de agent de afgelopen drie maanden heeft geïnstalleerd. Kunnen ze dat niet, dan offreren we nog geen herbouw.

Het test-corpus

We kijken niet naar coverage. Coverage is een percentage geraakte regels, geen percentage afgedekte failure-modes, en agents zijn goed in tests schrijven die regels raken zonder gedrag te testen.

We zoeken drie smells. Tests die het system under test mocken, zodat de assertie eigenlijk is 'de mock gaf terug wat de mock werd verteld'. Tests die de bron in de test-setup opnieuw implementeren, zodat elke wijziging in de bron de test om de verkeerde reden laat slagen. Tests zonder asserties, alleen een no-throw-garantie.

// Het patroon dat we het vaakst zien: een assertie op de mock.
test('sends invoice email', async () => {
  const sendEmail = jest.fn().mockResolvedValue({ id: 'msg_1' })
  await sendInvoiceEmail(sendEmail, fakeInvoice)
  expect(sendEmail).toHaveBeenCalled()
  // De echte vragen blijven ongetest: wat als sendEmail throwt?
  // Wat als hij een 5xx teruggeeft? Wat als hij midflight een timeout krijgt?
})

Elk van deze smells is normaal in handgeschreven code op lage volumes. Elk wordt de default op schaal als een agent te horen krijgt 'voeg tests toe voor dit bestand' zonder verdere beperking.

Waarschuwing

Coverage boven 90% met nul tests voor retry, idempotency of timeout-afhandeling is het meest voorkomende patroon in repo's die CI passeren en de on-call-druk verdubbelen.

Git-hygiëne en de vorm van commits

Agent-commits hebben een vorm. Ze raken meestal acht tot vijftien bestanden tegelijk, met een one-line message en een diff van dertig regels. Door mensen gereviewde agent-commits zien er anders uit: kleiner, langere messages, met revert-commits als iets niet uitpakt.

We lezen de laatste vijftig commits snel door: wie ze schreef, hoe groot elke diff was, en hoe vaak de keten 'fix X' dan 'fix X opnieuw' dan 'nu echt fix X' voorkomt. Die fix-de-fix-keten is het duidelijkste signaal dat de agent in een loop zat zonder dat een mens hem stopte. Drie of meer van zulke ketens in vijftig commits en we weten hoe de afgelopen zes maanden eruit zagen.

Observability-haken

We openen één productielog van de afgelopen zeven dagen. We zoeken niet naar de error zelf. We kijken naar de vorm van het loggen. Wordt er iets gevangen en met context opnieuw gegooid, of wordt alles ofwel ingeslikt ofwel uitgecrasht? Zijn er metrics voor request-latency, queue-depth, retry-count? Zijn er traces die de grens tussen de code van de agent en de third-party calls die hij doet overschrijden?

De meeste door agents gebouwde systemen die we auditen hebben hier niets van. De agent kreeg nooit de opdracht observability toe te voegen, omdat er geen test zonder faalde, en de menselijke reviewer dacht er ook niet aan om het te vragen. De twelve-factor-gids over logs als event streams behandelen houdt hier nog steeds stand, twaalf jaar later. Als het antwoord op 'hoe weet je of het systeem gedegradeerd of stuk is' stilte is, dan voegen we een observability-week aan de offerte toe voor we iets anders aanraken.

Het runbook dat niemand schreef

Is er een runbook? Heeft iemand hem gebruikt? Als de database in failover gaat, wat gebeurt er dan? Als de upstream API een uur lang 429 teruggeeft, wat gebeurt er dan? Als de cron-worker midden in een job sterft, wat gebeurt er met de job die liep? Het Google SRE-boek is ouder dan de meeste agent-harnesses, en het hoofdstuk over incidents managen beschrijft het gat nog steeds precies: het team dat het systeem schreef, was nooit het team dat gepaged werd toen het stuk ging.

De afwezigheid van een runbook is zelden de schuld van de agent. De agent stond nooit on-call. Hij weet niet wat jouw team om 3 uur 's nachts nodig heeft, omdat hij er nooit zat. Dit is ook de sectie die het snelste te repareren is, want zodra je de scenario's opsomt, is de agent juist behoorlijk goed in het opstellen van de respons-stappen.

Scoren en wat we ermee doen

We scoren elk van de zeven secties hierboven op vijf en tellen ze op. Onder de vijftien van vijfendertig offreren we geen herbouw zonder eerst een discovery-week, omdat de onbekenden te groot zijn. Tussen vijftien en vijfentwintig offreren we een refactor met een duidelijk migratiepad, meestal minder werk dan de klant verwachtte. Boven vijfentwintig vertellen we het team dat ze iets in handen hebben dat het bewaren waard is, en offreren we een stabilisatie-traject. Ongeveer één op de vijf repo's komt boven de vijfentwintig uit. De andere vier waren de reden dat de founder ons in eerste instantie appte.

De versie van vijf minuten

Lukt het je niet om de volledige audit te draaien, doe dan drie stappen. Lees het instructiebestand hardop voor en vraag of het bruikbaar zou zijn voor een nieuwe collega die gisteren begon. Lees de laatste vijftig commits en tel de fix-de-fix-ketens. Open één productielog van de afgelopen week en vraag of je puur uit dat log kunt opmaken wat het systeem deed toen er iets fout ging. Is een van die drie leeg, ontbrekend of onleesbaar, dan heb je je antwoord over de herbouw al.

Toen we deze lente de agent-stack auditten voor een Rotterdamse logistieke klant, zat de verrassing in het test-corpus: 94% coverage, nul retry-tests, en een cron job die zes weken stilletjes dubbel had gevuurd. We hebben niet herbouwd. We voegden retry-tests toe, een dedupe-key op de cron, en een dunne observability-laag, en ze sloten in de eerste week twee terugkerende incidents. Klinkt dat patroon bekend, dan is dezelfde checklist wat we draaien bij elk AI-agent-traject dat we aannemen.

Het kleinste wat je vandaag kunt doen, voor welke audit dan ook: open het instructiebestand dat je harness leest, en bekijk de datum van de laatste commit die het aanraakte. Is die ouder dan de laatste feature die je uitrolde, dan zit je agent al zo lang te gokken.

Kern

Coverage boven 90% met nul tests voor retry, idempotency of timeout is de meest voorkomende reden dat door agents gebouwde code CI passeert en de on-call-druk verdubbelt.

FAQ

Wat telt als een agent-harness?

De runtime die een code-model omhult en beslist welke tools het mag aanroepen: shell, filesystem, git, netwerk. Codex, Claude Code, Cursor en Aider zijn allemaal harnesses met verschillende defaults.

Hoe lang duurt een volledige audit?

Een eerste lezing kost een senior engineer vier tot zes uur voor een middelgrote repo. Het scoren en de rapportage komen daar een halve dag bovenop. We factureren het tegen een vast bedrag, zodat het resultaat niet onder druk staat.

Wanneer herbouwen, en wanneer refactoren?

Onder 15/35 op de checklist: herbouwen. Tussen 15 en 25: refactoren met een migratiepad. Boven 25: stabiliseren en observability toevoegen. Het test-corpus en het runbook bepalen het antwoord meer dan de taalkeuze.

Verandert agents.md echt de uitkomst?

Ja, als het bestand naar echte voorbeelden in de repo wijst en samen met features wordt bijgewerkt. Nee, als het generieke regels zijn zonder code-referenties, en zo beginnen de meeste.

ai agentstoolingoperationsworkflowarchitectureprocess automation

Iets bouwen?

Start een project