Harness engineering: Codex gebruiken in een agent-first wereld
Door Ryan Lopopolo, lid van de technische staf
De afgelopen vijf maanden heeft ons team een experiment uitgevoerd: het bouwen en opleveren van een interne bètaversie van een softwareproduct zonder een enkele regel handgeschreven code.
Het product heeft dagelijkse interne gebruikers en externe alfatesters. Het wordt uitgebracht, gedeployed, gaat stuk en wordt weer gerepareerd. Wat dit project uniek maakt: Codex schreef elke regel code, van applicatielogica en tests tot documentatie en interne tools. We schatten dat we dit hebben gebouwd in ongeveer een tiende van de tijd die nodig zou zijn geweest om de code met de hand te schrijven.
Mensen geven richting. Agents voeren uit.
We kozen bewust voor deze beperking om onszelf te dwingen enkel datgene te bouwen wat nodig was om de ontwikkelsnelheid exponentieel te verhogen. We hadden slechts weken de tijd om iets op te leveren wat uiteindelijk neerkomt op een miljoen regels code. Om dat te bereiken, moesten we begrijpen wat er verandert als een engineeringteam niet langer primair code schrijft. De focus verschuift naar het ontwerpen van omgevingen, het specificeren van intenties en het bouwen van feedbackloops waarmee Codex-agents betrouwbaar werk kunnen leveren.
Deze post gaat over de lessen die we hebben geleerd tijdens het bouwen van een gloednieuw product met een team van agents: wat er misging, wat elkaar versterkte en hoe we onze enige echt schaarse bron (menselijke tijd en aandacht) konden maximaliseren.
De eerste commit in een lege repository vond plaats eind augustus 2025.
De Codex CLI genereerde de initiële structuur (repository-indeling, CI-configuratie, format-regels, setup van de package manager en het applicatieframework) met behulp van GPT‑5, op basis van een kleine set bestaande templates. Codex schreef zelfs het eerste AGENTS.md-bestand, dat de agents instructies geeft over hoe ze in de repository moeten werken.
Er was geen bestaande, door mensen geschreven code die als fundament voor het systeem kon dienen. Vanaf het begin werd de repository gevormd door de agent.
Vijf maanden later bevat de repository in de orde van grootte van een miljoen regels code, verspreid over applicatielogica, infrastructuur, tooling, documentatie en interne hulpprogramma's. In die periode zijn er ongeveer 1.500 pull requests (PR's) geopend en gemerged, met een klein team van slechts drie engineers die Codex aanstuurden. Dit komt neer op een gemiddelde doorvoer van 3,5 PR's per engineer per dag. Verrassend genoeg nam de productiviteit toe naarmate het team groeide naar de huidige zeven engineers. Belangrijk is dat dit geen productie als doel op zich was: het product wordt intern door honderden mensen gebruikt, waaronder dagelijkse power users.
Gedurende het hele ontwikkelproces hebben mensen nooit direct code bijgedragen. Dit werd een kernfilosofie voor het team: geen handgeschreven code.
Doordat we niet meer handmatig programmeerden, werd het werk van de engineer meer gericht op systemen, structuren en slagkracht.
In het begin ging de voortgang langzamer dan verwacht. Niet omdat Codex onbekwaam was, maar omdat de omgeving onvoldoende gespecificeerd was. De agent miste de tools, abstracties en interne structuur die nodig waren om doelen op hoog abstractieniveau te bereiken. De hoofdtaak van ons team was om te zorgen dat de agents nuttig werk konden doen.
In de praktijk betekende dit depth-first werken: grotere doelen opbreken in kleinere bouwstenen (ontwerp, code, review, test, etc.), de agent instrueren om die blokken te bouwen, en deze vervolgens gebruiken om complexere taken mogelijk te maken. Als er iets mislukte, was de oplossing bijna nooit 'gewoon nog eens proberen'. Aangezien vooruitgang alleen mogelijk was door Codex het werk te laten doen, doken de engineers in de taak en vroegen zich af: 'Welke capaciteit ontbreekt er, en hoe maken we die zowel leesbaar als afdwingbaar voor de agent?'
Mensen communiceren bijna uitsluitend met het systeem via prompts: een engineer beschrijft een taak, start de agent en laat deze een pull request openen. Om een PR af te ronden, instrueren we Codex om zijn eigen wijzigingen lokaal te reviewen, specifieke extra reviews door agents aan te vragen (zowel lokaal als in de cloud), te reageren op feedback en te itereren totdat alle agent-reviewers tevreden zijn (in feite een 'Ralph Wiggum Loop(opent in een nieuw venster)'). Codex gebruikt onze standaard ontwikkeltools direct (gh, lokale scripts en skills ingebed in de repository) om context te verzamelen, zonder dat mensen output hoeven te kopiëren en plakken in de CLI.
Mensen mogen pull requests reviewen, maar zijn het niet verplicht. In de loop der tijd hebben we bijna alle review-inspanningen verschoven naar afhandeling tussen agents onderling.
Toen de code-output toenam, werd menselijke QA-capaciteit de bottleneck. Omdat menselijke tijd en aandacht de vaste beperking vormden, hebben we gewerkt aan het toevoegen van meer mogelijkheden voor de agent door zaken als de UI, logs en app-metrics direct leesbaar te maken voor Codex.
We zorgden dat de app per git worktree gestart kon worden, zodat Codex per wijziging één instantie kon starten en aansturen. Ook hebben we het Chrome DevTools Protocol gekoppeld aan de agent-runtime en skills gecreëerd voor het werken met DOM-snapshots, screenshots en navigatie. Hierdoor kon Codex bugs reproduceren, oplossingen valideren en direct redeneren over UI-gedrag.

Hetzelfde deden we voor observability-tools. Logs, metrics en traces worden via een lokale observability-stack aan Codex aangeboden. Deze stack is vluchtig (ephemeral) en uniek voor elke worktree. Codex werkt op een volledig geïsoleerde versie van die app (inclusief logs en metrics) die wordt afgebroken zodra de taak is voltooid. Agents kunnen logs bevragen met LogQL en metrics met PromQL. Met deze context beschikbaar worden prompts zoals 'zorg ervoor dat de service binnen 800ms opstart' of 'geen enkele span in deze vier kritieke gebruikersscenario's mag langer duren dan twee seconden' behapbaar.
We zien regelmatig dat één enkele Codex-sessie meer dan zes uur aan een taak werkt (vaak terwijl de mensen slapen).
Contextmanagement is een van de grootste uitdagingen om agents effectief te laten zijn bij grote en complexe taken. Een van de eerste lessen die we leerden was simpel: geef Codex een kaart, geen handleiding van 1000 pagina's.
We probeerden de aanpak met één groot AGENTS.md-bestand(opent in een nieuw venster). Dit faalde op voorspelbare wijze:
- Context is schaars . Een enorm instructiebestand verdringt de taak, de code en de relevante documentatie, waardoor de agent belangrijke beperkingen mist of begint te optimaliseren voor de verkeerde zaken.
- Te veel sturing wordt geen sturing. Als alles 'belangrijk' is, is niets dat. Agents vallen terug op lokaal patroonherkennen in plaats van doelbewust te navigeren.
- Het veroudert direct. Een monolithische handleiding verandert in een kerkhof van verouderde regels. Agents kunnen niet onderscheiden wat nog waar is, mensen stoppen met het onderhoud en het bestand wordt stilletjes een bron van verwarring.
- Het is moeilijk te verifiëren. Eén groot, ongestructureerd tekstblok leent zich niet voor mechanische controles (zoals testdekking, actualiteit, eigenaarschap en kruisverwijzingen), waardoor drift onvermijdelijk is.
Daarom behandelen we AGENTS.md niet als de encyclopedie, maar als de inhoudsopgave.
De kennisbank van de repository bevindt zich in een gestructureerde docs/-map, die fungeert als system of record. Een beknopte AGENTS.md (ongeveer 100 regels) wordt in de context geladen en dient voornamelijk als plattegrond, met verwijzingen naar diepere bronnen elders.
De ontwerpdocumentatie is gecatalogiseerd en geïndexeerd, inclusief verificatiestatus en een set kernprincipes die onze agent-first werkwijze definiëren. Architectuurdocumentatie(opent in een nieuw venster) biedt een overzicht op hoog niveau van domeinen en de gelaagdheid van packages. Een kwaliteitsdocument beoordeelt elk productdomein en elke architecturale laag, en houdt hiaten in de loop van de tijd bij.
Plannen worden behandeld als volwaardige artefacten. Vluchtige, lichtgewicht plannen worden gebruikt voor kleine wijzigingen, terwijl complex werk wordt vastgelegd in uitvoeringsplannen(opent in een nieuw venster) met voortgangs- en beslissingslogboeken die in de repository worden gecommit. Actieve plannen, voltooide plannen en bekende technische schuld zijn allemaal geversioneerd en gecentraliseerd, waardoor agents kunnen werken zonder afhankelijk te zijn van externe context.
Dit maakt stapsgewijze informatievoorziening mogelijk: agents beginnen met een klein, stabiel startpunt en leren waar ze vervolgens moeten kijken, in plaats van direct overspoeld te worden met informatie.
We handhaven dit automatisch. Specifieke linters en CI-jobs valideren of de kennisbank up-to-date, onderling gelinkt en correct gestructureerd is. Een terugkerende 'doc-gardening'-agent scant op verouderde documentatie die niet meer overeenkomt met het werkelijke gedrag van de code, en opent pull requests om dit te corrigeren.
Naarmate de codebase groeide, moest ook het kader voor ontwerpbeslissingen van Codex mee-evolueren.
Omdat de repository volledig door agents is gegenereerd, is deze primair geoptimaliseerd voor leesbaarheid door Codex. Net zoals teams de navigeerbaarheid van hun code willen verbeteren voor nieuwe menselijke engineers, was het doel van ons team om het voor een agent mogelijk te maken direct vanuit de repository zelf over het volledige bedrijfsdomein te redeneren.
Vanuit het oogpunt van de agent bestaat alles wat hij tijdens het draaien niet in de context kan benaderen, effectief niet. Kennis die in Google Docs, chatgesprekken of in de hoofden van mensen zit, is niet toegankelijk voor het systeem. Repository-specifieke, geversioneerde artefacten (zoals code, markdown, schema's en uitvoerbare plannen) zijn het enige wat hij kan zien.

We leerden dat we in de loop van de tijd steeds meer context naar de repo moesten verplaatsen. Die Slack-discussie waarin het team overeenstemming bereikte over een architectuurpatroon? Als die niet vindbaar is voor de agent, is die net zo onleesbaar als voor een nieuwe collega die drie maanden later start.
Codex meer context geven betekent de juiste informatie organiseren en beschikbaar maken zodat de agent erover kan redeneren, in plaats van hem te overstelpen met ad-hoc instructies. Net zoals je een nieuwe teamgenoot zou inwerken in productprincipes, engineeringnormen en teamcultuur (inclusief emoji-voorkeuren), leidt het verstrekken van deze informatie aan de agent tot output die beter is afgestemd op de wensen.
Dit perspectief verhelderde veel technische afwegingen. We gaven de voorkeur aan dependencies en abstracties die volledig binnen de repo geïnternaliseerd en begrepen konden worden. Technologieën die vaak als 'saai' worden omschreven, zijn voor agents vaak makkelijker te modelleren vanwege de modulariteit, API-stabiliteit en hun vertegenwoordiging in de trainingsset. In sommige gevallen was het efficiënter om de agent delen van functionaliteit opnieuw te laten implementeren dan om te werken om het ondoorzichtige gedrag van openbare library's heen. In plaats van bijvoorbeeld een generieke 'p-limit'-achtige package te gebruiken, implementeerden we onze eigen map-with-concurrency helper: deze is strak geïntegreerd met onze OpenTelemetry-instrumentatie, heeft 100% testdekking en gedraagt zich precies zoals onze runtime verwacht.
Door een groter deel van het systeem zo in te richten dat de agent het direct kan inspecteren, valideren en aanpassen, wordt de slagkracht groter, niet alleen voor Codex, maar ook voor andere agents (zoals Aardvark) die aan de codebase werken.
Documentatie alleen is niet genoeg om een volledig door agents gegenereerde codebase coherent te houden. Door vaste regels af te dwingen, en niet de implementaties te micromanagen, laten we agents snel leveren zonder het fundament te ondermijnen. We eisen bijvoorbeeld dat Codex datastructuren aan de grenzen parst(opent in een nieuw venster), maar schrijven niet voor hoe dat exact gebeurt (het model lijkt een voorkeur te hebben voor Zod, maar we hebben die specifieke bibliotheek niet verplicht gesteld).
Agents zijn het effectiefst in omgevingen met strikte grenzen en een voorspelbare structuur(opent in een nieuw venster), dus bouwden we de applicatie rond een rigide architectuurmodel. Elk bedrijfsdomein is verdeeld in een vaste set lagen, met strikt gevalideerde afhankelijkheidsrichtingen en een beperkte set toegestane verbindingen. Deze beperkingen worden mechanisch afgedwongen via aangepaste linters (uiteraard gegenereerd door Codex!) en structurele tests.
Het diagram hieronder toont de regel: binnen elk bedrijfsdomein (bijv. App-instellingen) mag code alleen 'voorwaarts' afhangen van een vaste set lagen (Types → Config → Repo → Service → Runtime → UI). Domeinoverschrijdende functionaliteiten (auth, connectoren, telemetrie, feature flags) komen binnen via één expliciete interface: Providers. Al het andere is niet toegestaan en wordt mechanisch geblokkeerd.

Dit is het soort architectuur dat je doorgaans uitstelt tot je honderden engineers in dienst hebt. Met programmerende agents is het echter een vroege vereiste: de beperkingen zijn wat snelheid mogelijk maakt zonder verval of architecturale drift .
In de praktijk dwingen we deze regels af met custom linters en structurele tests, plus een kleine set stijlprincipes. We dwingen bijvoorbeeld statisch zaken af zoals structured logging, naamgevingsconventies voor schema's en types, limieten voor bestandsgrootte en platformspecifieke betrouwbaarheidseisen. Omdat de lints maatwerk zijn, schrijven we de foutmeldingen zo dat ze herstelinstructies direct in de context van de agent injecteren.
In een workflow waarbij de mens centraal staat, zouden deze regels overdreven streng of beperkend kunnen aanvoelen. Bij agents werken ze als vermenigvuldigers: zodra ze gecodeerd zijn, zijn ze overal tegelijk van toepassing.
Tegelijkertijd zijn we expliciet over waar beperkingen ertoe doen en waar niet. Dit lijkt op het leiden van een grote engineering-platformorganisatie: grenzen centraal afdwingen, autonomie lokaal toestaan. Je hecht veel waarde aan grenzen, correctheid en reproduceerbaarheid. Binnen die grenzen geef je teams (of agents) aanzienlijke vrijheid in hoe oplossingen worden vormgegeven.
De resulterende code komt niet altijd overeen met menselijke stilistische voorkeuren, en dat is prima. Zolang de output correct, onderhoudbaar en leesbaar is voor toekomstige agentsessies, voldoet het aan de norm.
Menselijke smaak en inzicht worden continu teruggekoppeld naar het systeem. Review-opmerkingen, refactoring-pull requests en bugs die de gebruiker raken, worden vastgelegd als documentatie-updates of direct in de tooling verwerkt. Wanneer documentatie tekortschiet, zetten we de regel om in harde code.
Naarmate de doorvoersnelheid van Codex toenam, werden veel conventionele engineering-normen contraproductief.
De repository werkt met minimale blokkades bij het mergen. Pull requests hebben een korte levensduur. Instabiele tests worden vaak aangepakt met vervolg-runs in plaats van de voortgang voor onbepaalde tijd te blokkeren. In een systeem waar de output van agents de menselijke aandacht ver overstijgt, zijn correcties goedkoop en is wachten duur.
In een omgeving met lage output zou dit onverantwoord zijn, maar hier is het vaak de juiste keuze.
Wanneer we zeggen dat de codebase wordt gegenereerd door Codex-agents, bedoelen we alles in de codebase.
Agents produceren:
- Productcode en tests
- CI-configuratie en release-tooling
- Interne ontwikkelaarstools
- Documentatie en ontwerpgeschiedenis
- Harnesses voor evaluatie
- Review-opmerkingen en reacties
- Scripts die de repository zelf beheren
- Definitiebestanden voor het productiedashboard
Mensen blijven altijd betrokken, maar werken op een andere abstractielaag dan voorheen. We geven prioriteit aan werk, vertalen gebruikersfeedback naar acceptatiecriteria en valideren uitkomsten. Wanneer de agent vastloopt, zien we dat als een signaal: we identificeren wat er ontbreekt (tools, vangrails, documentatie) en voeren dit terug in de repository, waarbij we Codex altijd zelf de oplossing laten schrijven.
Agents gebruiken onze standaard ontwikkeltools direct. Ze halen reviewfeedback op, reageren inline, pushen updates en squashen en mergen vaak hun eigen pull requests.
Naarmate meer van de ontwikkelcyclus direct in het systeem werd gecodeerd (testen, validatie, reviews, feedbackverwerking en herstel) passeerde de repository onlangs een betekenisvolle drempel waarbij Codex end-to-end een nieuwe feature kan aansturen.
Op basis van één enkele prompt kan de agent nu:
- De huidige staat van de codebase valideren
- Een gerapporteerde bug reproduceren
- Een video opnemen die de fout toont
- Een oplossing implementeren
- De oplossing valideren door de applicatie te testen
- Een tweede video opnemen die de oplossing toont
- Een pull request openen
- Reageren op feedback van agents en mensen
- Buildfouten detecteren en herstellen
- Alleen escaleren naar een mens als er een oordeel nodig is
- De wijziging mergen
Dit gedrag is sterk afhankelijk van de specifieke structuur en tooling van deze repository en er mag niet worden aangenomen dat dit generaliseert zonder vergelijkbare investeringen. Althans, nu nog niet.
Volledige autonomie van agents introduceert ook nieuwe problemen. Codex repliceert patronen die al in de repository bestaan, zelfs onevenwichtige of suboptimale patronen. Na verloop van tijd leidt dit onvermijdelijk tot drift.
Aanvankelijk losten mensen dit handmatig op. Ons team besteedde elke vrijdag (20% van de week) aan het opruimen van 'AI-slop'. Het is dan ook geen verrassing dat dit niet schaalde.
In plaats daarvan begonnen we zogenaamde 'gouden principes' direct in de repository te coderen en bouwden we een terugkerend opruimproces. Dit zijn uitgesproken, mechanische regels die de codebase leesbaar en consistent houden voor toekomstige agent-sessies. Bijvoorbeeld: (1) we verkiezen gedeelde utility packages boven zelfgemaakte helpers om invarianten centraal te houden, en (2) we benaderen data niet 'YOLO-stijl': we valideren grenzen of vertrouwen op getypeerde SDK's zodat de agent niet per ongeluk voortbouwt op gegokte datastructuren. Op regelmatige basis draaien er achtergrondtaken van Codex die scannen op afwijkingen, kwaliteitsscores bijwerken en gerichte pull requests met refactors openen. De meeste hiervan kunnen in minder dan een minuut worden beoordeeld en automatisch gemerged.
Dit werkt als garbage collection. Technische schuld is als een lening met hoge rente: het is bijna altijd beter om continu in kleine stapjes af te lossen dan het te laten oplopen en het in pijnlijke sprints aan te pakken. Menselijk inzicht wordt één keer vastgelegd en vervolgens continu afgedwongen op elke regel code. Dit stelt ons ook in staat om slechte patronen dagelijks te vangen en op te lossen, in plaats van ze dagen of weken te laten woekeren in de codebase.
Deze strategie heeft tot nu toe goed gewerkt tot en met de interne lancering en adoptie bij OpenAI. Het bouwen van een echt product voor echte gebruikers hielp om onze investeringen in de realiteit te verankeren en ons te sturen richting onderhoudbaarheid op de lange termijn.
Wat we nog niet weten, is hoe architecturale coherentie zich over de jaren ontwikkelt in een volledig door agents gegenereerd systeem. We leren nog steeds waar menselijk oordeel de meeste slagkracht biedt en hoe we dat oordeel zo kunnen coderen dat het zichzelf versterkt. We weten ook niet hoe dit systeem zal evolueren naarmate modellen in de loop van de tijd capabeler worden.
Wat duidelijk is geworden: software bouwen vereist nog steeds discipline, maar die discipline uit zich meer in de structuur dan in de code zelf. De tooling, abstracties en feedbackloops die de codebase coherent houden, worden steeds belangrijker.
Onze moeilijkste uitdagingen liggen nu bij het ontwerpen van omgevingen, feedbackloops en controlesystemen die agents helpen ons doel te bereiken: complexe, betrouwbare software bouwen en onderhouden op schaal.
Naarmate agents zoals Codex grotere delen van de softwarelevenscyclus overnemen, zullen deze vragen nog belangrijker worden. We hopen dat het delen van enkele vroege lessen jullie helpt te bepalen waar je je inspanningen in moet investeren, zodat je gewoon dingen kunt bouwen.


