Het Codex-harness en de bouw van de App Server
Door Celia Chen, lid van de technische staf
OpenAI's programmeerassistent Codex is op veel plekken beschikbaar: in de web-app(opent in een nieuw venster), via de CLI(opent in een nieuw venster), als IDE-extensie(opent in een nieuw venster) en in de nieuwe Codex macOS-app. Achter de schermen worden deze allemaal aangedreven door hetzelfde 'Codex-harness': de agent loop en logica die de basis vormen van elke Codex-ervaring. De cruciale schakel hierin is de Codex App Server(opent in een nieuw venster), een clientvriendelijke, bidirectionele JSON-RPC1 API.
In dit artikel introduceren we de Codex App Server. We delen onze ervaringen over hoe je de krachtige functies van Codex het beste in je eigen product integreert om de workflow van gebruikers te optimaliseren. We bespreken de architectuur en het protocol van de App Server, de integratie met verschillende interfaces en geven tips over hoe je Codex inzet als code-reviewer, SRE-agent of programmeerassistent.
Voordat we dieper op de architectuur ingaan, is het goed om de achtergrond van de App Server te kennen. Oorspronkelijk was de App Server een praktische oplossing om het Codex-harness te hergebruiken voor verschillende producten. Gaandeweg is dit uitgegroeid tot ons standaardprotocol.
De Codex CLI begon als een TUI (Terminal User Interface). Toen we de VS Code-extensie bouwden (een meer IDE-gerichte manier om met Codex te werken) wilden we hetzelfde harness gebruiken. We wilden de agent loop vanuit een IDE aansturen zonder deze volledig opnieuw te hoeven bouwen. Dat betekende dat we complexe interactiepatronen moesten ondersteunen die verder gingen dan simpele request/response-acties, zoals het verkennen van de werkruimte, het streamen van de voortgang terwijl de agent redeneert, en het genereren van diffs. Aanvankelijk experimenteerden we met Codex als een MCP-server(opent in een nieuw venster) (Model Context Protocol), maar het bleek lastig om de MCP-structuur logisch aan te laten sluiten op VS Code. In plaats daarvan introduceerden we een JSON-RPC-protocol dat de TUI-loop spiegelde. Dit werd de onofficiële eerste versie(opent in een nieuw venster) van de App Server. Destijds verwachtten we niet dat andere clients afhankelijk zouden worden van de App Server, dus het was niet ontworpen als een stabiele API.
Toen het gebruik van Codex de maanden daarna groeide, wilden zowel interne teams als externe partners het harness in hun eigen producten implementeren. JetBrains en Xcode wilden bijvoorbeeld een agent-ervaring van IDE-kwaliteit, terwijl de Codex-desktop-app meerdere agenten parallel moest kunnen aansturen. Deze vraag stimuleerde ons om een platform-laag te ontwerpen waar zowel onze eigen producten als partner-integraties op lange termijn veilig op konden bouwen. Het moest eenvoudig te integreren zijn en achterwaarts compatibel, zodat we het protocol konden verbeteren zonder bestaande clients te verbreken.
Vervolgens laten we zien hoe we de architectuur en het protocol hebben ontworpen, zodat verschillende clients hetzelfde harness kunnen gebruiken.
Laten we eerst inzoomen op wat er precies in het Codex-harness zit en hoe de Codex App Server deze beschikbaar stelt aan clients. In onze vorige blog beschreven we de kern van de agent loop: de interactie tussen de gebruiker, het model en de tools. Dit is het hart van het Codex-harness, maar een volledige agent-ervaring omvat meer:
1. Levenscyclus en persistentie van threads. Een thread is een Codex-conversatie tussen een gebruiker en een agent. Codex maakt threads aan, hervat ze, forkt ze en archiveert ze. De eventgeschiedenis wordt opgeslagen, zodat clients opnieuw verbinding kunnen maken en een consistente tijdlijn kunnen tonen.
2. Configuratie en authenticatie. Codex laadt configuraties, beheert standaardinstellingen en voert authenticatiestromen uit zoals 'Inloggen met ChatGPT', inclusief de status van inloggegevens.
3. Tooluitvoering en uitbreidingen. Codex voert shell-/file-tools uit in een sandbox en koppelt integraties zoals MCP-servers en skills, zodat deze kunnen deelnemen aan de agent loop binnen een consistent beleidsmodel.
Alle agentlogica die we hier hebben genoemd, inclusief de kern-agent loop, bevindt zich in een deel van de Codex CLI-codebase genaamd 'Codex core(opent in een nieuw venster)'. Codex core is zowel een bibliotheek waarin alle agentcode staat, als een runtime die opgestart kan worden om de agent loop te draaien en de persistentie van één Codex-thread (conversatie) te beheren.
Om nuttig te zijn, moet het Codex-harness toegankelijk zijn voor clients. Hier biedt de App Server uitkomst.
De App Server is zowel het JSON-RPC-protocol tussen de client en de server, als een langlopend proces dat de Codex core threads host. Zoals te zien in het bovenstaande diagram, bestaat een App Server-proces uit vier hoofdcomponenten: de stdio-lezer, de Codex-berichtverwerker, de thread manager en de kern-threads. De thread manager start één core-sessie per thread, waarna de Codex-berichtverwerker direct communiceert met elke core-sessie om client-verzoeken in te dienen en updates te ontvangen.
Eén client-verzoek kan leiden tot vele event-updates; juist deze gedetailleerde events stellen ons in staat om een rijke gebruikersinterface bovenop de App Server te bouwen. Daarnaast fungeren de stdio-lezer en de Codex-berichtverwerker als de vertaallaag tussen de client en de Codex core threads. Ze vertalen JSON-RPC-verzoeken van de client naar operaties voor de Codex-core, luisteren naar de interne eventstroom van de Codex-core en transformeren die low-level events vervolgens naar een kleine set stabiele JSON-RPC-meldingen die geschikt zijn voor de UI.
Het JSON-RPC-protocol tussen de client en de App Server is volledig bidirectioneel. Een typische thread bevat één client-verzoek en vele server-meldingen. Bovendien kan de server zelf verzoeken initiëren wanneer de agent input nodig heeft, zoals een goedkeuring, en vervolgens de turn pauzeren totdat de client reageert.
Hierna ontleden we de bouwstenen voor het gesprek en het App Server-protocol. Het ontwerpen van een API voor een agent loop is complex, omdat de interactie tussen gebruiker en agent geen simpel request/response-verkeer is. Eén verzoek van een gebruiker kan zich ontvouwen in een gestructureerde reeks acties die de client getrouw moet weergeven: de input van de gebruiker, de incrementele voortgang van de agent en artefacten die onderweg worden geproduceerd (bijvoorbeeld diffs). Om die interactiestroom eenvoudig te integreren en robuust te maken voor verschillende UI's, hebben we gekozen voor drie fundamentele bouwstenen met duidelijke grenzen en levenscycli:
1. Item: Een item is de atomaire eenheid van input/output in Codex. Items zijn getypeerd (bijv. gebruikersbericht, agentbericht, tooluitvoering, goedkeuringsverzoek, diff) en hebben elk een expliciete levenscyclus:
item/startedwanneer het item begint- optionele
item/*/delta-events terwijl de inhoud binnenstroomt (voor streamende item-types) item/completedwanneer het item wordt voltooid met de definitieve payload
Dankzij deze levenscyclus kunnen clients direct beginnen met renderen bij started, incrementele updates streamen bij delta, en afronden bij completed.
2. Turn: Een turn is een werkeenheid van de agent, geïnitieerd door input van de gebruiker. Het begint wanneer de client input indient (bijvoorbeeld: 'voer tests uit en vat fouten samen') en eindigt wanneer de agent klaar is met het produceren van output voor die input. Een turn bevat een reeks items die de tussenstappen en de geproduceerde output vertegenwoordigen.
3. Thread: Een thread is de duurzame container voor een lopende Codex-sessie tussen een gebruiker en een agent. Deze bevat meerdere turns. Threads kunnen worden aangemaakt, hervat, geforkt en gearchiveerd. De threadgeschiedenis wordt opgeslagen, zodat clients opnieuw verbinding kunnen maken en een consistente tijdlijn kunnen weergeven.
Laten we nu kijken naar een vereenvoudigd gesprek tussen een client en een agent, weergegeven door deze bouwstenen:
Aan het begin van het gesprek moeten de client en de server de initialize-handshake uitvoeren. De client moet een enkel initialize-verzoek sturen voorafgaand aan enige andere methode, waarop de server bevestigt met een antwoord. Dit geeft de server de kans om zijn mogelijkheden kenbaar te maken en laat beide partijen afspraken maken over protocolversies, functievlaggen en standaardinstellingen voordat het echte werk begint. Hier is een voorbeeldpayload van de VS Code-extensie van OpenAI:
Dit is wat de server terugstuurt:
Wanneer een client een nieuw verzoek doet, maakt deze eerst een thread aan en daarna een turn. De server stuurt voortgangsmeldingen terug (thread/started en turn/started). Ook stuurt de server inputs terug die hij registreert als items, zoals het bericht van de gebruiker.
Toolaanroepen worden ook als items teruggestuurd naar de client. Daarnaast kan de server om goedkeuring van de client vragen voordat deze een actie uitvoert door een serververzoek te sturen. Deze goedkeuring pauzeert de turn totdat de client antwoordt met 'allow' of 'deny'. Zo ziet de goedkeuringsstroom eruit in de VS Code-extensie:

Uiteindelijk stuurt de server een bericht van de agent en beëindigt de turn met turn/completed. De agent message delta-events streamen stukjes van het bericht terug totdat het bericht definitief is met item/completed.
De berichten in het diagram zijn vereenvoudigd voor de leesbaarheid. Als je de JSON voor een volledige turn wilt zien, kun je de testclient draaien vanuit de Codex CLI-repo:
Laten we nu kijken hoe verschillende client-interfaces Codex integreren via de App Server. We behandelen drie patronen: lokale apps en IDE's, de Codex web-runtime en de TUI.
Bij alle drie verloopt het transport via JSON-RPC over stdio (JSONL). JSON-RPC maakt het eenvoudig om client-bindings te bouwen in een taal naar keuze. Codex-interfaces en integraties van partners hebben App Server-clients geïmplementeerd in talen waaronder Go, Python, TypeScript, Swift en Kotlin. Voor TypeScript kun je definities direct vanuit het Rust-protocol genereren door het volgende commando uit te voeren:
Voor andere talen kun je een JSON Schema-bundel genereren en deze invoeren in je favoriete codegenerator via:

Lokale clients bundelen of downloaden doorgaans een platformspecifieke App Server-binary, starten deze als een langlopend subproces en houden een bidirectioneel stdio-kanaal open voor JSON-RPC. In onze VS Code-extensie en Desktop App bevat het geleverde artefact bijvoorbeeld de platformspecifieke Codex-binary. Deze is vastgezet op een geteste versie, zodat de client altijd exact de versie draait die wij hebben gevalideerd.
Niet elke integratie kan frequent client-updates uitrollen. Sommige partners, zoals Xcode, ontkoppelen hun releasecycli door de client stabiel te houden en deze indien nodig naar een nieuwere App Server-binary te laten verwijzen. Op die manier kunnen ze serververbeteringen (zoals betere automatische compressie in Codex core of nieuw ondersteunde config keys) overnemen en bugfixes uitrollen zonder te hoeven wachten op een nieuwe client-release. De JSON-RPC-interface van de App Server is ontworpen om achterwaarts compatibel te zijn, zodat oudere clients veilig met nieuwere servers kunnen communiceren.

Codex Web gebruikt het Codex-harness, maar draait deze in een containeromgeving. Een worker richt een container in met de uitgecheckte werkruimte, start daarin de App Server-binary en onderhoudt een langlopend JSON-RPC over stdio2-kanaal. De web-app (die in het browsertabblad van de gebruiker draait) communiceert met de Codex-backend via HTTP en SSE, waarmee task events van de worker worden gestreamd. Dit houdt de UI in de browser licht, terwijl we toch een consistente runtime-omgeving behouden voor zowel desktop als web.
Websessies zijn vluchtig: tabbladen sluiten en netwerkverbindingen vallen weg. Daarom kan de web-app niet de ultieme bron van waarheid zijn voor langlopende taken. Door state en voortgang op de server bij te houden, gaat het werk door, zelfs als het tabblad verdwijnt. Dankzij het streamingprotocol en opgeslagen threadsessies kan een nieuwe sessie eenvoudig opnieuw verbinden, verdergaan waar deze gebleven was en de achterstand inhalen zonder de state opnieuw op te hoeven bouwen in de client.

Historisch gezien was de TUI een 'native' client die in hetzelfde proces draaide als de agent loop en direct communiceerde met de interne Rust-types, in plaats van via het app-serverprotocol. Dit versnelde de eerste iteraties, maar maakte de TUI tot een uitzondering in de architectuur.
Nu de App Server bestaat, zijn we van plan de TUI te herschrijven(opent in een nieuw venster) zodat deze gebruikmaakt van de App Server, net als elke andere client: een App Server-subproces starten, communiceren via JSON-RPC over stdio, en dezelfde streaming events en goedkeuringen renderen. Dit maakt workflows mogelijk waarbij de TUI verbinding maakt met een Codex-server op een externe machine. Hierdoor blijft de agent dicht bij de rekenkracht en kan het werk doorgaan, zelfs als de laptop in slaapstand gaat of de verbinding verliest, terwijl updates en bediening lokaal live beschikbaar blijven.
De Codex App Server wordt de primaire integratiemethode die we in de toekomst blijven onderhouden, maar er zijn ook andere methodes met beperktere functionaliteit. Standaard raden we clients aan om de Codex App Server te gebruiken voor integratie, maar het is de moeite waard om de alternatieven te bekijken en de voor- en nadelen te begrijpen. Hieronder staan de meest voorkomende manieren om Codex aan te sturen en wanneer deze geschikt zijn.
Voer codex mcp-server(opent in een nieuw venster) uit en maak verbinding vanuit elke MCP-client die stdio-servers ondersteunt (bijv. de OpenAI Agents SDK(opent in een nieuw venster)). Dit is geschikt als je al een MCP-gebaseerde workflow hebt en Codex wilt aanroepen als een tool. Het nadeel is dat je beperkt bent tot wat MCP aanbiedt. Specifieke Codex-interacties die afhankelijk zijn van rijkere sessie-informatie (zoals updates van diffs) laten zich mogelijk niet goed vertalen via MCP-endpoints.
Sommige ecosystemen bieden een overdraagbare interface die meerdere modelaanbieders en runtimes kan aansturen. Dit kan handig zijn als je één abstractielaag zoekt die meerdere agents coördineert. De afweging is dat deze protocollen vaak neerkomen op een gemeenschappelijke subset van mogelijkheden. Dit maakt het lastiger om rijkere interacties weer te geven, vooral wanneer specifieke tools en sessie-semantiek van de aanbieder belangrijk zijn. Dit domein ontwikkelt zich snel en we verwachten dat er meer standaarden zullen ontstaan naarmate we ontdekken wat de beste bouwstenen zijn om echte agentworkflows te representeren (skills(opent in een nieuw venster) zijn hier een goed voorbeeld van).
Kies de App Server wanneer je het volledige Codex-harness wilt ontsluiten als een stabiele, UI-vriendelijke eventstroom. Je krijgt zowel de volledige functionaliteit van de agent loop als ondersteunende functies zoals 'Inloggen met ChatGPT', model-detectie en configuratiebeheer. De grootste inspanning zit in de integratie, aangezien je de JSON-RPC-binding aan de clientzijde in jouw taal moet bouwen. In de praktijk kan Codex echter veel van het zware werk doen als je het voorziet van het JSON-schema en de documentatie. Veel teams waarmee we hebben samengewerkt, konden dankzij Codex snel een werkende integratie realiseren.
Een lichtgewicht, scriptbare CLI-modus voor eenmalige taken en CI-runs. Dit is geschikt voor automatisering en pipelines waarbij je een enkele opdracht zonder interactie wilt uitvoeren, gestructureerde output voor logs wilt streamen, en wilt eindigen met een duidelijk status-signaal (succes of falen).
Een TypeScript-bibliotheek voor het programmatisch aansturen van lokale Codex-agents vanuit je eigen applicatie. Dit werkt het best wanneer je een native library-interface wilt voor server-side tools en workflows, zonder een aparte JSON-RPC-client te hoeven bouwen. Omdat dit eerder werd uitgebracht dan de App Server, ondersteunt het momenteel minder talen en is de functionaliteit beperkter. Bij voldoende interesse van developers voegen we mogelijk extra SDK's toe die het App Server-protocol 'wrappen', zodat teams meer van het harness kunnen gebruiken zonder zelf JSON-RPC-bindings te schrijven.
In deze post hebben we gedeeld hoe we het ontwerpen van een nieuwe standaard voor interactie met agents aanpakken en hoe we het Codex-harness omvormen tot een stabiel, clientvriendelijk protocol. We hebben besproken hoe de App Server de Codex-core ontsluit, clients de volledige agent loop laat aansturen, en de basis vormt voor een breed scala aan toepassingen, waaronder de TUI, lokale IDE-integraties en de web-runtime.
Als dit ideeën heeft opgeroepen voor het integreren van Codex in jouw eigen workflows, is het de moeite waard om de App Server te proberen. Alle broncode bevindt zich in de open-source repo(opent in een nieuw venster) van Codex CLI. Deel gerust je feedback en functieverzoeken. We zijn benieuwd naar je ervaringen en blijven werken om agents toegankelijker te maken voor iedereen.
Auteur
Dankwoord
Speciale dank aan Michael Bolin, Owen Lin, Eric Traut en Rasmus Rygaard voor hun bijdragen aan deze post, en aan het hele Codex-team dat aan de App Server heeft gewerkt.
Voetnoten
- 1
We gebruiken een 'JSON-RPC lite'-variant: deze behoudt de structuur van request/response/notification, maar laat de '
jsonrpc': '2.0'header weg en gebruikt JSONL over stdio in plaats van strikte JSON-RPC 2.0. - 2
'stdio' verwijst naar de stdin/stdout van de app-server binnen de container. In gehoste omgevingen worden deze streams vaak via een persistente netwerkverbinding (bijv. WebSocket-achtig) naar de container-runtime getunneld—zodat het zich gedraagt als stdio, zelfs als het geen letterlijke lokale pipe is.


