Mark Emelianov
NL

Medium · AI-engineering, softwareontwikkeling · Concept

Het vierlussenpatroon: autonome codeeragenten laten werken zonder afdrijven

Hoe u AI-engineering gedisciplineerd houdt wanneer de agents sneller werken dan u kunt nakijken — ook wanneer de bedenker van de discipline er zelf van afdwaalt.

Voor het eerst gepubliceerd op Medium op 12 mei 2026; laatst bewerkt op 13 mei 2026. Lees het op Medium. 17 minuten leestijd.

Hoe u AI-engineering gedisciplineerd houdt wanneer de agents sneller werken dan u kunt nakijken — ook wanneer de bedenker van de discipline er zelf van afdwaalt.

Dit is een verkennend artikel, geen voorschrift. De waarde ervan ligt niet in het feit dat het vierlussenpatroon al bewezen zou zijn, maar in de taal die het geeft aan een reëel faalpatroon: autonome agents kunnen druk bezig zijn, lokaal correct zijn en het product toch niet vooruit helpen.

Wie langer dan een week codeeragents op een echte codebase heeft laten draaien, is waarschijnlijk tegen dezelfde muur gelopen als ik. De agents zijn productief: ze leveren commits af, ze halen CI, ze werken documentatie bij. De repo groeit. Er komen tests bij. Er worden nieuwe mechanismen gebouwd.

Vier robots in blauw, paars, oranje en groen zweven rond een lus in de vorm van een oneindigheidsteken, elk met een ander hulpmiddel: kubus, vergrootglas, tablet, grafiek.

En dan stap je achteruit, kijk je naar je product en besef je: er is niets beter geworden.

De agents zijn druk bezig. De output is echt. Maar wat de gebruiker ervaart, is ongeveer wat het een maand geleden was. De codebase is groter, de doctrine dikker, de meta-architectuur eleganter — en de functie die je wilde opleveren werkt nog altijd niet van begin tot einde.

Dit artikel beschrijft het patroon waar ik uiteindelijk bij ben uitgekomen om autonome codeeragents zo te laten werken dat het product echt vooruitgaat. Het is geen wondermiddel. Het is een discipline. En — belangrijk — het is een discipline die ik tijdens dezelfde sessie waaruit dit artikel is voortgekomen meermaals zelf heb overtreden. Ook dat staat hier: de faalpatronen die blijven bestaan nadat je de regels hebt opgeschreven.

Het faalpatroon

De pathologie heeft een naam: driftend-neutrale runs. Een “run” is één uitvoering van een agentlus. Een driftend-neutrale run is een run waarin de agent werk verricht, commits oplevert, CI haalt en niets verandert wat de gebruiker kan zien of meten.

Veelvoorkomende varianten:

Elk van deze patronen voelt productief omdat de agent wél commits oplevert. De run is “geslaagd” in de triviale zin: hij crashte niet, CI was groen, de diff werd gemerged. Maar de meetbare toestand van het platform veranderde niet. Vermenigvuldig dat met 50 runs per week en je hebt een dure loopband.

“Het faalpatroon: driftend-neutrale runs”: doctrine-inflatie, stub-wildgroei, mechanisme zonder meting, plan-slingering; het tegengif is convergentie.

De discipline hieronder bestaat om dit faalpatroon onmogelijk te verbergen.

De vierlussenarchitectuur

Weiger het patroon van “één grote agent”. Eén enkele lus die alles probeert te doen (implementatie, review, monitoring, gebruikerstests) drijft af, omdat de prioriteiten met elkaar wedijveren en er geen scheiding van verantwoordelijkheden is die dat afdwingt.

Vier lussen, elk met een afgebakende verantwoordelijkheid:

Elke lus draait in een eigen sessie. Ze communiceren via het bestandssysteem (git voor gedeelde toestand; per lus een richtlijnbestand voor overdrachten). Ze roepen elkaar niet rechtstreeks aan.

De orthogonaliteit is belangrijk. De implementatielus kan zichzelf niet goedkeuren; de reviewlus kan niet zelf implementeren; de analyselus kan de wijzigingen die hij voorstelt niet doorvoeren; de testlus kan niet herstellen wat hij beoordeelt. Elke lus is gedwongen de output van de andere lussen te gebruiken.

Vierlussenarchitectuur: implementatie (60 min), review (30), analyse (90), gebruikersgerichte test (4 u), elk met een lijst van wat niet mag, en met toestand gedeeld via bestanden.

Dit is dezelfde scheiding die een gezond menselijk engineeringteam kent — developer, reviewer, QA, ops — maar dan vastgelegd voor agents. De lussen zijn niet “flexibeler” dan mensen. Ze zijn rigider. Dat is net de bedoeling.

De convergentiewet

Parallellisme zonder voortgang is erger dan helemaal geen agents. Om voortgang te krijgen, geldt een harde regel:

Elke run eindigt in een van drie toestanden: CONVERGENT (leverde een meetbare verbetering van het platform op, met bewijs van voor en na), EXPLICIET NEUTRAAL (deed bewust niets, met vermelding van de reden), of REGRESSIEF (maakte iets slechter — vereist een onmiddellijke revert plus een schriftelijke les). Een run die liep en dingen deed maar geen meetbare verandering opleverde, is DRIFTEND-NEUTRAAL en is een faalpatroon dat de reviewlus als schending van de discipline aanmerkt.

“Meetbaar” is hier dragend. Het vraagt een canonieke toestandsmatrix die elke lus bij een koude start leest: functiegebiedscores, slaagpercentages, wachtrijdieptes, deploy-vertraging — welke de primaire assen van uw product ook zijn. Een run is convergent als een cel in die matrix verbeterde ÉN geen enkele cel verslechterde. De verbetering moet worden onderbouwd met bewijs van voor en na in de tekst van de PR.

Drie robots op paden: groen convergent met een stijgende grafiek, amber expliciet neutraal met een notitieboekje, rood regressief met een waarschuwing; ervoor een toestandsmatrix.

In de praktijk:

De reviewlus dwingt dit af bij elke PR. PR’s die in geen van de drie toestanden passen, krijgen REQUEST_CHANGES. De auteur moet ofwel de meetbare verbetering aanwijzen, de PR met reden als neutraal herclassificeren, of terugdraaien.

Deze ene regel vangt grofweg 80% van het driftprobleem op. De rest vraagt meer.

De aflossingsregel

Regels stapelen zich op. Elke nieuwe regel die een toekomstige agent moet lezen, is een belasting op het contextbudget van elke toekomstige run. Dus:

Een nieuw doctrinedocument, een nieuwe agentdefinitie, een nieuw backlogitem of een nieuwe processtap toevoegen VEREIST dat minstens één bestaand exemplaar wordt afgeschaft (verwijderen, in een ander opnemen of archiveren). De netto complexiteit mag niet groeien zonder uitdrukkelijke goedkeuring van de operator. Uitzondering: als het nieuwe item via convergentie meerdere oude vervangt, is dat netto negatief en aanvaardbaar.

Dit is de regel die ik zelf het vaakst overtreed. Het is moeilijk om dingen te schrappen die je zelf hebt geschreven. Maar het alternatief is een doctrinedocument waar je 30 minuten over doet aan het begin van elke sessie — waardoor agents het vluchtig doorlezen, waardoor ze het niet volgen, waardoor ze afdrijven.

Een weegschaal met het opschrift “Netto complexiteit mag niet groeien”, tussen een bak Toevoegen met nieuwe doctrine en backlog en een bak Afschaffen; een reviewchecklist eindigt in Goedkeuren.

De reviewlus controleert elke PR: zijn er nieuwe doctrinebestanden of backlogitems toegevoegd? Zo ja, is er ook iets van gelijkwaardig gewicht afgeschaft? Zo niet, REQUEST_CHANGES met: “convergence-discipline: deze PR voegt N nieuwe doctrine-items toe maar schaft er 0 af. Schaf er één af of documenteer waarom de netto toevoeging gerechtvaardigd is door een meetbare verbetering die in deze PR landt.”

De regel tegen het opleveren van stubs

Convergentiediscipline vangt drift per run op. Ze vangt geen drift per artefact op. Eén run kan 10 artefacten opleveren waarvan er 3 werken en 7 stubs zijn, in totaal als “convergent” tellen en het aantal stubs van het platform ongemerkt laten groeien.

De regel per artefact:

Elk artefact dat u oplevert — eindpunt, scherm, widget, capaciteit, agentdefinitie, handboeksectie, alles — MOET zich in een van drie toestanden bevinden: WERKEND(van begin tot einde geverifieerd met een test, smoke-output of screenshot in de tekst van de PR), STARTKLAAR(de lacune uitdrukkelijk benoemd, met een afrondend item ingepland in dezelfde PR), of STUB-MET-WACHTRIJ(een expliciete status:stub-markering plus een aangehaald afrondend item plus een voor de operator leesbare uitleg wanneer men erop stuit). STUB-ZONDER-WACHTRIJis een schending van de discipline.

De klassieke overtreding: een scherm opleveren met een widget “Wachtrij niet beschikbaar — Opnieuw proberen”. De vorm van de widget is in orde; de data erachter bestaat niet; er is geen afrondend item ingepland. De gebruiker loopt tegen een muur zonder uitleg en zonder vervolgpad.

Robots op een lopende band sorteren artefacten in Werkend, Startklaar, Stub-met-wachtrij en een bak voor Stub-zonder-wachtrij, die is bestempeld als schending van de discipline.

Een subtielere overtreding: een documentatiebestand opleveren met markdownlinks naar zusterbestanden die niet bestaan. Het linkdoel zou een stub-met-wachtrij-bestand moeten zijn, maar is zelfs dat niet — het is een leegte. De linkchecker van de reviewer laat CI falen; de deploypoort weigert; het platform loopt vast. Precies dit faalpatroon heb ik opgeleverd in de sessie waaruit dit artikel voortkwam — en de analyselus ving het binnen enkele uren op. Daarover verderop meer.

Het universele koudestartprotocol

Elke lus voert aan het begin van elke run dezelfde zes controles uit, voordat enig werk begint:

Plus een zevende in de monitoringlus:

  1. Controleer de resterende ruimte binnen de limieten. Hoeveel van het huidige factureringsvenster is verbruikt? Wat is het verbruikstempo?

Na de controles past elke lus zijn reactieregels toe in een prioriteitsvolgorde met onderbouwing: bereikbaarheid vóór correctheid, deploypoort vóór inhoud, CI van de hoofdbranch vóór backlog, backlog vóór nieuw werk, platformmetriek vóór doctrine.

Koudestartprotocol vóór enig werk: zeven controles, van synchroniseren met de trunk tot de resterende ruimte binnen de limieten, plus een prioriteitsvolgorde van vijf stappen voor de reactie.

Dit klinkt bureaucratisch. Het is het tegenovergestelde — het neemt de agent de vrijheid om slecht te kiezen. Een lus die wordt geconfronteerd met “deploypoort geweigerd, vier PR’s niet gereviewd, CI rood, backlog groeit, laagst gescoorde functiegebied op F” hoeft niet meer na te denken over prioriteit. Het protocol beslist: eerst de deploypoort.

Dertien robuustheidsinvarianten

Protocollen die de toestand onderzoeken, zijn van nature broos. Controles lopen vast, bestanden ontbreken, netwerken vallen uit. Dus:

Raster “13 robuustheidsinvarianten”: harde timeouts, terugvalmodi, concurrentie via leases, auditlog, verificatie na de actie, kostenplafond, worktree-isolatie.

I-13 is degene die ik na deze sessie heb toegevoegd. De andere twaalf had ik goed. Het botsingspatroon dat I-13 voorkomt, wordt beschreven in de sectie “Wat dit patroon nog steeds breekt” hieronder.

De matrix van model en denkmodus

Moderne platformen voor codeeragents laten u zowel de modelgrootte kiezen ALS de denkmodus (normaal versus uitgebreid denken met een expliciet redeneerbudget). Het kostenverschil tussen goedkoopst en duurst bedraagt ruwweg 60×. Als elke activiteit standaard “het slimste model met het diepste denken” gebruikt, verbrandt u geld aan routinewerk dat niets aan diepgang heeft.

De koppeling van activiteit aan model:

Matrix van model en denkmodus: negen activiteiten gekoppeld aan modelgrootte, denkmodus, redeneerbudget en kosten; de standaard is klein met normaal denken.

Standaard: kleiner model + normaal denken. Schaal op wanneer diepgang echt helpt. Kies nooit “het grootste + het diepste voor alle zekerheid” als standaard — de grootste kostenpost in elk agentsysteem zijn subagents die het model van hun ouder overnemen terwijl ze een goedkoper model zouden moeten kiezen.

De grens tussen agent en operator

De belangrijkste regel: agents schuiven werk niet stilzwijgend door naar de menselijke operator.

Wanneer een autonoom codeersysteem iets niet kan — domeinexpertise, marktpositionering, tests met echte gebruikers, beslissingen over het businessmodel — is er de verleiding om “de operator moet…” in de documentatie te schrijven. Dat is niet eerlijk. Zo worden de moeilijke delen afgeschoven op het moment dat de operator er het minst klaar voor is (vroeg in het leven van het product, wanneer er nog geen MVP is).

Wat agents WEL opleveren: functiescores optillen van kapot naar werkend; ontwerppolish; concurrentieanalyses op basis van openbare bronnen; integratiediepte; UX-tests vóór de eerste klant (via de gebruikersgerichte testlus); onboardingflows; rapportagefuncties.

Wat alleen de operator kan beslissen: strategische prioriteit (welke functie het zwaarst weegt voor de markt die hij kent); businessmodel; de uiteindelijke esthetische voorkeur tussen twee conforme ontwerpen; expliciete toestemming om te omzeilen (wanneer een agent zegt “deze test is flaky, mag ik omzeilen”); herclassificatie van prioriteitsniveaus.

Tests met echte klanten worden UITGESTELD, niet doorgeschoven. Echte gebruikers binnenhalen vóór de MVP verbrandt goodwill op een kapot product. De gebruikersgerichte testlus neemt die rol over tot de MVP-drempel is bereikt. Daarna komen echte gebruikers erbij om te vinden wat de gesimuleerde tester heeft gemist.

Grens tussen agent en operator: agents leveren herstelwerk, polish, analyses en UX-tests; alleen de operator beslist over strategie, businessmodel en omzeilingen.

Dit is de grens die operators het hardst moeten afdwingen. Zonder die grens wordt het agentsysteem iets dat aandacht van de operator opeist in plaats van iets dat werk verzet.

Het ene canonieke toestandsbestand

Alle vier de lussen, alle disciplineregels, alle protocollen — ze zijn nutteloos als er geen gedeelde definitie is van “wat is de toestand van het platform op dit moment”.

Eén bestand. Een trendtabel waaraan alleen wordt toegevoegd. Elke rij is een momentopname. De kolommen zijn de metrieken waar het product om draait: functiescores per gebied, slaagpercentages, aantallen blokkades, wachtrijdieptes.

Elke lus leest dit bestand bij een koude start. Convergente runs werken het bij. Driftend-neutrale runs niet. Na een week of twee IS de trend in dit bestand het antwoord op “leveren de agents convergentie op”.

Eén canoniek state.md als trendtabel waaraan alleen wordt toegevoegd, gelezen en geschreven door alle vier de lussen, met de uitkomsten convergent, driftend-neutraal en convergentie-gestokt.

Als 7 opeenvolgende momentopnames geen beweging tonen, meldt de reviewlus: “convergentie gestokt — lussen pauzeren, metagesprek nodig.” Het bestand is het veiligheidsventiel dat het geval opvangt waarin elke afzonderlijke run beweert productief te zijn, maar het geheel dat niet is.

Wat dit patroon nog steeds breekt

Dit is de sectie die het oorspronkelijke concept van dit artikel niet had. Het kostte me een sessie vol drift om haar toe te voegen.

Auteursdrift

De persoon (of agent) die een regel schrijft, overtreedt haar routinematig voordat de inkt droog is. Ik leverde een discipline per artefact op die zei “elk artefact wordt WERKEND, STARTKLAAR of STUB-MET-WACHTRIJ opgeleverd” — en in dezelfde sessie leverde ik een documentatieboom op met 16 hangende markdownlinks die in geen van die toestanden pasten. De analyselus ving het binnen enkele uren op. Ik was de auteur van de regel die mijn eigen overtreding aanwees.

De les: zelfhandhaving van discipline werkt niet. De review- en analyselussen zijn geen luxe; ze zijn het enige dat auteursdrift opvangt. Bouw ze eerst. De regels die u zelf schrijft, zullen u niet binden zonder externe handhaving.

Botsingen in een gedeelde werkboom

Als u alle vier de lussen vanuit dezelfde fysieke map laat draaien, botsen ze bij elke git-bewerking. De ene lus doet git checkout <branch> en de git status van de andere lus meldt plotseling een andere werkelijkheid. Half gemergede commits worden aan de verkeerde sessie toegeschreven. Ongevolgde bestanden verschijnen en verdwijnen, afhankelijk van welke branch de laatste lus uitcheckte.

De oplossing is invariant I-13 hierboven: elke lus werkt in zijn eigen git worktree. Aparte werkmap, gedeelde .git-database. Het commando git worktree add is één regel en lost de hele klasse van fouten definitief op.

Ik leerde dit door herhaaldelijk te botsen met mijn eigen analyselus, terwijl ik in dezelfde map een hoofdsessie rechtstreeks als operator draaide.

Valkuilen bij het starten

Drie vallen waar u in trapt nog voordat de lussen beginnen te draaien.

Alle drie raakte ik in één sessie. Geen enkele is exotisch — ze zijn dragend voor elke opzet op een Windows-host. Geen enkele staat in de README’s van agentplatformen. Reken een dag om ze te vinden.

De kloof tussen kosten en waarde

De sessie waaruit dit artikel voortkwam, kostte grofweg $157 aan rekenkracht tegen API-tarief (het eigenlijke abonnement is vast; het dollarbedrag is wat hetzelfde werk zou kosten bij betalen per gebruik). De sessie leverde negen gemergede pull requests op met doctrine, infrastructuur en proces. Ze leverde nul voor de gebruiker zichtbare productverbeteringen op. De productfix die ik vroeg in de sessie committe, haalde de productie nooit omdat de deploypoort weigerde — wegens 15 falende tests plus de 16 hangende markdownlinks die ik zelf had opgeleverd.

Dit is de kloof tussen kosten en waarde, rechtuit benoemd. De discipline die ik in dit artikel beschrijf, is precies in die sessie opgebouwd. De meetbare toestand van het platform verbeterde niet. De infrastructuur waarmee toekomstige sessies hem wel verbeteren, bestaat nu — en u moet eerlijk zijn tegenover uzelf (en uw operator) wanneer dat de afweging is die u hebt gemaakt.

“Wat dit patroon nog steeds breekt”: auteursdrift, botsingen in de werkboom, valkuilen bij het starten en een sessie van ~$157 die 9 PR’s mergede zonder enige productverbetering.

De convergentieregel, met terugwerkende kracht toegepast, zou de hele sessie als DRIFTEND-NEUTRAAL hebben aangemerkt. Dat is de regel die doet wat hij moet doen. Hij zegt u ook iets ongemakkelijks: een sessie die is opgezet om een artikel over discipline te produceren, kan moeilijk ook productvoortgang produceren, want elke minuut die naar doctrine gaat, is een minuut die niet naar de functie gaat. Plan dienovereenkomstig.

Wat dit NIET zal doen

Eerlijke grenzen aan wat de discipline wel en niet kan opleveren:

“Wat dit niet zal doen”: de discipline tilt functies van kapot naar werkend, maar kan de topscore niet bereiken, geen strategie bepalen, geen echte klantenpijn vinden en de markt niet winnen.

Benoemen wat niet zal gebeuren, maakt deel uit van de discipline. Zonder dat verwachten operators meer dan het systeem kan leveren en verliezen ze vertrouwen wanneer het tekortschiet.

Wat het kost

Een vierlussensessie die 8 uur per dag draait met een tempo dat de matrix respecteert, kost per maand grofweg het equivalent van het tooling-budget van één engineer van gemiddeld niveau. Het eigenlijke abonnement is vast; de beperking zijn de limieten per factureringsvenster, niet de dollars.

Alles standaard op het grootste model met het diepste denken zetten? Grofweg 5 tot 7 keer dat bedrag. De discipline van de matrix is het verschil tussen houdbaar autonoom engineeren en een op hol geslagen factuur.

Wat het per sessie kost, is veranderlijker. Een sessie die enkel doctrine oplevert — zoals die waaruit dit artikel voortkwam — verbrandt budget zonder productverbetering. Dat is geen verspilling als de doctrine zich in de komende sessies terugbetaalt in convergentie, maar het IS verspilling als de doctrine onafgedwongen blijft liggen.

Infographic “Wat het kost”: basiskost van een vierlussensessie, afgestemd model versus standaard het grootste tegen 5-7×, kosten per categorie en vuistregels.

De reviewlus zorgt ervoor dat doctrine zich terugbetaalt. Zonder die lus stapelt doctrine zich op als dood gewicht.

De les die ik steeds opnieuw leer

Elke keer dat ik een nieuwe regel, agent of werkwijze aan dit systeem toevoeg, zet ik last op de toekomst. De convergentiediscipline is de enige regel die netto de last verlaagt — ze dwingt elke andere toevoeging om zich terug te betalen in meetbare verbetering.

De pathologie die ik aan het begin van dit artikel beschreef — “de agents zijn productief maar het product beweegt niet” — is een falen van discipline, geen falen van tooling. De agents doen precies wat u zegt: commits opleveren, CI halen, documentatie bijwerken. Ze kregen alleen niet te horen dat de commits een meetbare as moesten doen bewegen.

Zodra u hun dat zegt, met expliciete regels per run en per artefact, met één canoniek toestandsbestand, met scheiding van verantwoordelijkheden over vier lussen, met de eerlijke grens rond wat alleen mensen kunnen en met worktree-isolatie zodat ze niet botsen — worden de agents bruikbaar.

Niet magisch. Bruikbaar. Soms.

Dat “soms” is het deel dat het oorspronkelijke concept van dit artikel miste. De discipline is het doel. Ook als ze is opgeschreven, ook als de regels expliciet zijn, ook als de reviewlus draait, zult u (en uw agents) afdrijven. De drift wordt opgevangen — daar is de analyselus voor — maar niet voorkomen. Het mechanisme corrigeert zichzelf, maar het voorkomt zichzelf niet.

Dat onderscheid doet ertoe. De literatuur over AI-engineeringtools staat vol “magische” beweringen. De werkelijkheid is: een kleine set gedisciplineerde patronen, streng afgedwongen door andere agents (niet door zelfdiscipline), die autonome agents de meeste tijd echt werk laten doen, met opgevangen en gecorrigeerde drift de rest van de tijd. Al de rest is toneel.

Een robot houdt een checklist op een tablet vast (backlogitem kiezen, code schrijven, tests toevoegen, documentatie bijwerken, PR openen, convergente run) en steekt een duim omhoog.

Als u codeeragents op een echte codebase laat draaien en de faalpatronen ziet die ik heb beschreven, kunnen de patronen hierboven helpen. Ze zijn niet nieuw; de meeste zijn een codificatie van wat goede engineeringteams al doen. Het nieuwe is dat ze dragend worden gemaakt voor autonome lussen waar geen mens in de directe omgeving is om ze impliciet af te dwingen — en dat de faalpatronen worden benoemd die de discipline toch overleven.

Addendum. Spiekbriefje

Poster van het vierlussenpatroon: vier lussen met verantwoordelijkheden, gedeelde toestandsmappen, drie uitkomsten van een run, een voorbeeld van een toestandsmatrix en de convergentiewet.

Deze pagina is een volledige kopie van het verhaal zoals het op Medium is verschenen. Lees het op Medium. Illustraties gegenereerd met AI.