Découvrir le Codex harness : la conception de notre App Server
Par Celia Chen, membre du service technique
L'agent de codage Codex d'OpenAI est disponible sur de nombreuses plateformes : l'application web(ouverture dans une nouvelle fenêtre), le CLI(ouverture dans une nouvelle fenêtre), l'extension IDE(ouverture dans une nouvelle fenêtre) et la nouvelle application Codex pour macOS. Tous ces services sont alimentés par le même Codex harness : la boucle d'agent et la logique qui sous-tendent toutes les expériences Codex. Le lien essentiel entre eux ? Le Codex App Server(ouverture dans une nouvelle fenêtre), une API JSON-RPC[[fn :1]] bidirectionnelle intuitive pour les clients.
Dans cet article, nous vous présenterons le Codex App Server et partagerons nos connaissances acquises jusqu'à présent sur les meilleures façons d'intégrer les fonctionnalités de Codex à votre produit afin d'aider vos utilisateurs à optimiser leurs flux de travail. Nous aborderons l'architecture et le protocole de l'App Server, son intégration avec différentes interfaces Codex, ainsi que des conseils pour tirer parti de Codex, que vous souhaitiez le transformer en un outil de révision de code, un agent SRE ou un assistant de codage.
Avant d'aborder l'architecture, il est utile de savoir comment le App Server a été conçu. À l'origine, ce dernier était un moyen pratique de réutiliser le Codex harness dans différents produits, qui a progressivement évolué pour devenir notre protocole standard.
Codex CLI a été initialement conçu comme une interface utilisateur de terminal (TUI), ce qui signifie que Codex est accessible via le terminal. Lorsque nous avons développé l'extension VS Code (une manière plus conviviale d'interagir avec les agents Codex), nous avons dû trouver un moyen d'utiliser le même harness afin de piloter la même boucle d'agent à partir d'une interface utilisateur IDE sans avoir à la réimplémenter. Cela impliquait de prendre en charge des modèles d'interaction complexes allant au-delà des requêtes/réponses, tels que l'exploration de l'espace de travail, la diffusion en continu de la progression de l'agent et l'émission de diffs. Nous avons d'abord expérimenté l'exposition de Codex en tant que serveur MCP(ouverture dans une nouvelle fenêtre), mais il s'est avéré difficile de maintenir la sémantique MCP d'une manière qui soit cohérente avec VS Code. Nous avons donc introduit un protocole JSON-RPC qui reflétait la boucle TUI, qui est devenu la première version non officielle(ouverture dans une nouvelle fenêtre) de l'App Server. À l'époque, nous ne nous attendions pas à ce que d'autres clients dépendent de l'App Server, il n'a donc pas été conçu comme une API stable.
À mesure que l'adoption de Codex s'est développée au cours des mois suivants, les équipes internes et les partenaires externes ont souhaité pouvoir intégrer le même harness dans leurs propres produits afin d'accélérer les workflows de développement logiciel de leurs utilisateurs. Par exemple, JetBrains et Xcode souhaitaient bénéficier d'une expérience d'agent de niveau IDE, tandis que l'application de bureau Codex devait orchestrer plusieurs agents Codex en parallèle. Ces demandes nous ont incités à concevoir une plateforme sur laquelle nos produits et les intégrations de nos partenaires pourraient s'appuyer en toute sécurité au fil du temps. Elle devait être facile à intégrer et compatible avec les versions antérieures, ce qui nous permettrait de faire évoluer le protocole sans affecter nos clients.
À présent, nous allons vous expliquer comment nous avons conçu l'architecture et le protocole afin que différents clients puissent utiliser le même harness.
Tout d'abord, examinons de plus près le contenu du Codex harness et la manière dont le Codex App Server le met à disposition des clients. Dans notre dernier blog Codex, nous avons analysé en détail la boucle d'agent principale qui orchestre l'interaction entre l'utilisateur, le modèle et les outils. Il s'agit de la logique de base du Codex harness, mais l'expérience complète de l'agent ne s'arrête pas là :
1. Cycle de vie et persistance des threads Un thread est une conversation Codex entre un utilisateur et un agent. Codex crée, reprend, forke et archive les threads, et conserve l'historique des événements afin que les clients puissent se reconnecter et afficher une chronologie cohérente.
2. Configuration et authentification. Codex charge la configuration, gère les paramètres par défaut et exécute les flux d'authentification tels que « Se connecter avec ChatGPT », y compris l'état des informations d'identification.
3. Exécution des outils et extensions. Codex exécute des outils shell/file dans un environnement sandbox et effectue le lien entre les intégrations telles que les serveurs MCP et les compétences afin d'intégrer ces dernières dans la boucle de l'agent selon un modèle de politique cohérent.
Toute la logique de l'agent mentionnée ici, y compris la boucle centrale de l'agent, se trouve dans une partie du code source de Codex CLI appelée « Codex core(ouverture dans une nouvelle fenêtre) ». Codex core est à la fois une bibliothèque contenant tout le code des agents et un environnement d'exécution qui peut être lancé pour exécuter la boucle des agents et gérer la persistance d'un thread Codex (conversation).
Pour être utile, le Codex harness doit être accessible aux clients. C'est là que l'App Server entre en jeu.
L'App Server est à la fois le protocole JSON-RPC entre le client et le serveur et un processus de longue durée qui héberge les threads principaux de Codex. Comme le montre le schéma ci-dessus, un processus de l'App Server comporte quatre composants principaux : le lecteur stdio, le processeur de messages Codex, le gestionnaire de threads et les threads principaux. Le gestionnaire de threads lance une session principale pour chaque thread, puis le processeur de messages Codex communique directement avec chaque session principale pour soumettre les demandes des clients et recevoir les mises à jour.
Une seule requête client peut entraîner de nombreuses mises à jour d'événements, et ce sont ces événements détaillés qui nous permettent de créer une interface utilisateur complète en plus de l'App Server. De plus, le lecteur stdio et le processeur de messages Codex servent d'intermédiaire entre le client et les threads principaux de Codex. Ils traduisent les demandes JSON-RPC du client en opérations principales de Codex, surveillent le flux d'événements internes de Codex, puis transforment ces événements bas niveau en un petit ensemble de notifications JSON-RPC fiables et compatibles avec l'interface utilisateur.
Le protocole JSON-RPC entre le client et l'App Server est entièrement bidirectionnel. Un thread typique comprend une requête client et de nombreuses notifications serveur. De plus, le serveur peut initier des requêtes lorsque l'agent a besoin d'informations, comme une approbation, puis suspendre le tour jusqu'à ce que le client réponde.
Nous allons maintenant décomposer les éléments de base de la conversation, qui constituent les fondements du protocole App Server. Concevoir une API pour une boucle d'agent est complexe, car l'interaction entre l'utilisateur et l'agent ne se résume pas à une simple requête-réponse. Une requête utilisateur peut se déployer en une séquence structurée d'actions que le client doit représenter fidèlement : les entrées de l'utilisateur, la progression incrémentielle de l'agent, les artefacts produits en cours de route (par exemple, les diffs). Afin de faciliter l'intégration et la résilience de ce flux d'interaction entre les interfaces utilisateur, nous avons défini trois éléments fondamentaux avec des limites et des cycles de vie bien définis :
1. Élément : un élément est l'unité atomique d'entrée/sortie dans Codex. Les éléments sont classés par type (par exemple, message utilisateur, message agent, exécution d'outil, demande d'approbation, diff) et chacun a un cycle de vie explicite :
item/startedlorsque l'élément débute- événements
item/*/deltafacultatifs en tant que flux de contenu (pour les types d'éléments en streaming) item/completedlorsque l'élément est finalisé avec sa charge utile finale
Ce cycle de vie permet aux clients de commencer immédiatement le rendu sur started, de diffuser les mises à jour incrémentielles sur delta et de finaliser sur completed.
2. Tour : un tour est une unité de travail d'un agent initiée par une saisie utilisateur. Le processus débute lorsque le client soumet une entrée (par exemple, « exécuter des tests et faire une résumé des échecs ») et se termine lorsque l'agent a fini de produire des sorties pour cette entrée. Un tour contient une séquence d'éléments qui représentent les étapes intermédiaires et les sorties produites en cours de route.
3. Thread : un thread est un conteneur durable pour une session Codex en cours entre un utilisateur et un agent. Il comporte plusieurs étapes. Les threads peuvent être créés, réutilisés, forkés et archivés. L'historique des threads est conservé afin que les clients puissent se reconnecter et afficher une chronologie cohérente.
Nous allons maintenant nous intéresser à une conversation simplifiée entre un client et un agent, où la conversation est représentée par des éléments de base :
Au début de la conversation, le client et le serveur doivent établir le protocole initialize. Le client doit envoyer une seule requête initialize avant toute autre méthode, et le serveur en accuse réception par une réponse. Cela permet au serveur de présenter ses capacités et aux deux parties de se mettre d'accord sur la version du protocole, les indicateurs de fonctionnalités et les paramètres par défaut avant que le travail proprement dit ne commence. Voici un exemple de payload de l'extension VS Code d'OpenAI :
Voici ce que le serveur renvoie :
Lorsqu'un client effectue une nouvelle requête, il commencera par créer un thread, puis un tour. Le serveur renverra des notifications de progression (thread/started et turn/started). Il renverra également les entrées qu'il enregistre comme des éléments, tel que le message de l'utilisateur ici.
Les appels d'outils sont également renvoyés au client sous forme d'éléments. De plus, le serveur peut demander l'approbation du client avant de pouvoir exécuter une action en envoyant une requête au serveur. L'approbation mettra le tour en pause jusqu'à ce que le client autorise ou refuse l'action. Voici à quoi ressemble le flux d'approbation dans l'extension VS Code :

À la fin, le serveur envoie un message d'agent et termine ensuite le tour avec turn/completed. Les événements delta du message de l'agent renvoient des fragments du message jusqu'à ce que celui-ci soit finalisé avec item/completed.
Les messages dans le diagramme sont simplifiés pour une meilleure lisibilité. Si vous souhaitez visualiser le JSON pour un tour complet, vous pouvez exécuter le client test depuis le dépôt CLI Codex :
Maintenant, voyons comment différentes interfaces client intègrent Codex via l'App Server. Nous aborderons trois modèles : les applications locales et les IDE, l'environnement d'exécution web Codex, et la TUI (interface utilisateur de terminal).
Pour les trois, le transport est JSON-RPC sur stdio (JSONL). JSON-RPC facilite la création de liaisons client dans le langage de votre choix. Les interfaces Codex et les intégrations partenaires ont mis en œuvre des clients App Server dans des langages tels que Go, Python, TypeScript, Swift et Kotlin. Pour TypeScript, vous pouvez générer des définitions directement à partir du protocole Rust en exécutant :
Pour d'autres langues, vous pouvez générer un ensemble de schémas JSON et l'intégrer à votre générateur de code préféré en exécutant :

Les clients locaux regroupent ou récupèrent généralement un binaire App Server spécifique à la plateforme, le lancent en tant que processus enfant à exécution longue et maintiennent un canal stdio bidirectionnel ouvert pour JSON-RPC. Dans notre extension VS Code et notre application de bureau, par exemple, l'artefact fourni comprend le binaire Codex spécifique à la plateforme et est associé à une version testée afin que le client exécute toujours les bits exacts que nous avons validés.
Toutes les intégrations ne peuvent pas fournir des mises à jour fréquentes aux clients. Certains partenaires, tels que Xcode, dissocient les cycles de publication en maintenant la stabilité du client et en lui permettant de renvoyer vers un binaire App Server plus récent lorsque cela est nécessaire. De cette manière, ils peuvent adopter les améliorations côté serveur (par exemple, une meilleure auto-compactage dans le noyau Codex ou de nouvelles clés de configuration prises en charge) et déployer des corrections de bugs sans attendre la publication d'une nouvelle version du client. L'interface JSON-RPC de l'App Server est conçue pour être rétrocompatible, de sorte que les anciens clients peuvent communiquer en toute sécurité avec les nouveaux serveurs.

Codex Web utilise le Codex harness, mais l'exécute dans un environnement conteneurisé. Un travailleur provisionne un conteneur avec l'espace de travail vérifié, y lance le binaire App Server et maintient un JSON-RPC de longue durée sur le canal stdio2. L'application web (qui s'exécute dans l'onglet du navigateur de l'utilisateur) communique avec le backend Codex via HTTP et SSE, qui diffuse les événements de tâche produits par le travailleur. Cela permet de conserver une interface utilisateur légère côté navigateur tout en offrant un temps d'exécution cohérent sur les ordinateurs de bureau et le web.
Étant donné que les sessions Web sont éphémères (fermeture des onglets, coupures réseau), l'application Web ne peut pas constituer la source de vérité pour les tâches de longue durée. Conserver l'état et la progression sur le serveur permet de garantir la continuité du travail même si l'onglet disparaît. Le protocole de streaming et les sessions de thread enregistrées facilitent la reconnexion d'une nouvelle session, qui peut reprendre là où elle s'était arrêtée et récupérer les données sans avoir à reconstruire côté client.

À l'origine, la TUI était un client « natif » qui s'exécutait dans le même processus que la boucle de l'agent et communiquait directement avec les types de base Rust plutôt qu'avec le protocole de l'App Server. Cela a permis d'accélérer les premières itérations, mais a également fait de la TUI une surface particulière.
Maintenant que l'App Server existe, nous prévoyons de repenser la TUI(ouverture dans une nouvelle fenêtre) afin de l'utiliser comme n'importe quel autre client : lancer un processus enfant App Server, communiquer en JSON-RPC via stdio et restituer les mêmes événements et approbations en continu. Cela permet de débloquer des flux de travail dans lesquels l'interface utilisateur de terminal (TUI) peut se connecter à un serveur Codex fonctionnant sur une machine à distance, ce qui permet à l'agent de rester proche de l'ordinateur et de continuer à travailler même en cas de mise en veille ou de déconnexion, tout en continuant à fournir des mises à jour et des contrôles en direct au niveau local.
Codex App Server constituera la méthode d'intégration privilégiée que nous continuerons à utiliser à l'avenir, mais il existe également d'autres méthodes aux fonctionnalités plus limitées. Par défaut, nous recommandons à nos clients d'utiliser Codex App Server pour s'intégrer à Codex, mais il est utile d'examiner les différentes méthodes d'intégration et de comprendre leurs avantages et leurs inconvénients. Vous trouverez ci-dessous les méthodes les plus courantes pour utiliser Codex et les cas dans lesquels chacune d'entre elles peut être appropriée.
Exécutez codex mcp-server(ouverture dans une nouvelle fenêtre) et connectez-vous à partir de n'importe quel client MCP prenant en charge les serveurs stdio (par exemple, OpenAI Agents SDK(ouverture dans une nouvelle fenêtre)). Cette solution est particulièrement adaptée si vous disposez déjà d'un flux de travail basé sur MCP et souhaitez invoquer Codex en tant qu'outil exploitable. L'inconvénient est que vous n'obtenez que ce que MCP expose, de sorte que les interactions spécifiques à Codex qui reposent sur une sémantique de session plus complète (par exemple, les mises à jour diff) peuvent ne pas être correctement mappées via les endpoints MCP.
Certains écosystèmes proposent une interface portable pouvant cibler plusieurs fournisseurs de modèles et environnements d'exécution. Cela peut convenir si vous souhaitez une abstraction qui coordonne plusieurs agents. Le compromis est que ces protocoles convergent souvent vers un sous-ensemble commun de capacités, ce qui peut rendre plus difficile la représentation d'interactions plus complexes, en particulier lorsque les outils spécifiques au fournisseur et la sémantique des sessions ont leur importance. Ce domaine évolue rapidement et nous prévoyons l'émergence de normes plus courantes à mesure que nous déterminerons les meilleures primitives pour représenter les flux de travail des agents dans le monde réel (les compétences (ouverture dans une nouvelle fenêtre)en sont un bon exemple).
Choisissez l'App Server lorsque vous souhaitez que l'ensemble du Codex soit exposé sous forme de flux d'événements stable et convivial. Vous bénéficierez ainsi de toutes les fonctionnalités de la boucle d'agent et d'autres fonctionnalités complémentaires telles que la connexion avec ChatGPT, la découverte de modèles et la gestion de la configuration. Le coût principal réside dans le travail d'intégration, car vous devez créer la liaison JSON-RPC côté client dans votre langue. Dans la pratique, cependant, Codex est capable d'effectuer une grande partie du travail si vous lui fournissez le schéma JSON et la documentation. De nombreuses équipes avec lesquelles nous avons travaillé ont pu réaliser rapidement une intégration fonctionnelle grâce à Codex.
Un mode CLI léger et scriptable pour les tâches ponctuelles et les exécutions CI. Il convient parfaitement à l'automatisation et aux pipelines où vous souhaitez qu'une seule commande s'exécute de manière non interactive jusqu'à son terme, génère une sortie structurée pour les journaux et se termine par un signal clair de réussite ou d'échec.
Une bibliothèque TypeScript permettant de contrôler par programmation les agents Codex locaux depuis votre propre application. Elle est particulièrement utile lorsque vous souhaitez disposer d'une interface de bibliothèque native pour les outils et les workflows côté serveur sans avoir à créer un client JSON-RPC distinct. Étant donné qu'elle a été commercialisée avant l'App Server, elle prend actuellement en charge moins de langues et une surface plus réduite. Si les développeurs manifestent leur intérêt, nous pourrions ajouter des SDK supplémentaires qui encapsulent le protocole App Server afin que les équipes puissent couvrir une plus grande surface harness sans avoir à créer de liaisons JSON-RPC.
Dans cet article, nous avons présenté notre approche pour concevoir une nouvelle norme d'interaction avec les agents et transformer le Codex harness en un protocole stable et intuitif pour les clients. Nous avons expliqué comment l'App Server expose le cœur de Codex, permet aux clients de piloter la boucle complète de l'agent et alimente un large éventail de surfaces, notamment l'interface utilisateur de terminal (TUI), les intégrations IDE locales et l'environnement d'exécution web.
Si cela vous a donné des idées pour intégrer Codex à vos propres flux de travail, nous vous recommandons d'essayer App Server. Tout le code source se trouve dans le référentiel (ouverture dans une nouvelle fenêtre)open source Codex CLI. N'hésitez pas à partager vos feedbacks et vos demandes de fonctionnalités. Nous sommes impatients de recevoir vos suggestions et de continuer à rendre les agents plus accessibles à tous.
Auteur
Remerciements
Nous remercions tout particulièrement Michael Bolin, Owen Lin, Eric Traut et Rasmus Rygaard, qui ont contribué à cet article, ainsi que toute l'équipe Codex qui a travaillé sur l'App Server.
Notes de bas de page
- 1
Nous utilisons une variante « JSON-RPC lite » : elle conserve la structure requête/réponse/notification, mais omet l'en-tête
"jsonrpc": "2.0". et est structurée comme JSONL sur stdio plutôt que comme JSON‑RPC 2.0 strict. « stdio » fait référence aux entrées/sorties standard (stdin/stdout) de l'App Server dans le conteneur. Dans les configurations hébergées, ces flux sont souvent acheminés via une connexion réseau persistante (par exemple, de type WebSocket) vers l'environnement d'exécution du conteneur, de sorte qu'ils se comportent comme stdio même s'il ne s'agit pas d'un véritable canal local. [fn:2]


