Codex utilise l’interface app-server pour faire fonctionner ses clients riches, comme l’extension Codex pour VS Code. Utilisez-la pour intégrer directement à votre produit l’authentification, l’historique des conversations, les approbations et la diffusion en continu des événements de l’agent. Le code source d’app-server est disponible en open source dans le dépôt GitHub de Codex (openai/codex/codex-rs/app-server). Consultez la page Open source pour obtenir la liste complète des composants open source de Codex.
Pour automatiser des tâches ou exécuter Codex en intégration continue, utilisez plutôt le SDK Codex.
Connecter l’interface de terminal de la CLI
Le mode terminal à distance permet d’exécuter app-server sur une machine et de s’y connecter depuis une autre avec l’interface de terminal de Codex CLI. Démarrez le serveur en écoute sur WebSocket :
codex app-server --listen ws://127.0.0.1:4500
Connectez ensuite l’interface de terminal :
codex --remote ws://127.0.0.1:4500
Pour une connexion distante, configurez l’authentification WebSocket et protégez la connexion avec TLS. Stockez le jeton bearer dans une variable d’environnement et passez le nom de la variable pour éviter d’exposer le jeton sur la ligne de commande :
export CODEX_REMOTE_TOKEN="$(cat "$HOME/.codex/app-server-token")"
codex --remote wss://remote-host:4500 \
--remote-auth-token-env CODEX_REMOTE_TOKEN
L’option --remote accepte les points de terminaison ws://, wss://, unix:// et unix://PATH. Réservez les connexions WebSocket non chiffrées à localhost ou aux connexions avec redirection de port SSH.
Connecter un hôte Code Mode distant
Par défaut, app-server démarre un hôte Code Mode local. Pour partager un hôte distant entre les fils d’un même processus app-server, passez le point de terminaison gRPC sur HTTP/2 de cet hôte à --code-mode-host.
codex app-server --code-mode-host https://code-mode.example.com
Utilisez HTTPS pour un hôte distant afin de protéger les arguments et les résultats des outils. Réservez HTTP aux connexions sur l’interface de bouclage ou via un tunnel sécurisé. L’URL accepte un nom d’hôte suivi d’un port facultatif. Omettez les identifiants, les chemins, les chaînes de requête et les fragments. Utilisez --listen pour configurer séparément la connexion des clients à app-server.
Protocole
Comme MCP, codex app-server permet une communication bidirectionnelle par messages JSON-RPC 2.0 (l’en-tête "jsonrpc":"2.0" est omis lors de la transmission).
Transports disponibles :
stdio(--listen stdio://, par défaut) : un document JSON par ligne (JSONL).websocket(--listen ws://IP:PORT, expérimental et non pris en charge) : un message JSON-RPC par trame de texte WebSocket.- Socket Unix (
--listen unix://ou--listen unix://PATH) : connexions WebSocket via le socket de contrôle app-server par défaut de Codex ou un chemin de socket Unix personnalisé, avec la négociation HTTP Upgrade standard. off(--listen off) : n’expose aucun transport local.
Avec --listen ws://IP:PORT, le serveur répond également aux sondes HTTP de base sur le même point d’écoute :
GET /readyzrenvoie200 OKdès que le serveur accepte de nouvelles connexions.GET /healthzrenvoie200 OKsi la requête ne contient pas d’en-têteOrigin.- Le serveur rejette les requêtes contenant un en-tête
Originavec le statut403 Forbidden.
Le transport WebSocket est expérimental et non pris en charge. Les adresses d’écoute locales comme ws://127.0.0.1:PORT conviennent aux connexions sur localhost ou avec redirection de port SSH. Pendant le déploiement, les points d’écoute WebSocket hors de l’interface de bouclage acceptent par défaut les connexions non authentifiées. Configurez l’authentification WebSocket avant de les rendre accessibles à distance.
Options d’authentification WebSocket prises en charge :
--ws-auth capability-token --ws-token-file /absolute/path--ws-auth capability-token --ws-token-sha256 HEX--ws-auth signed-bearer-token --ws-shared-secret-file /absolute/path
Pour les jetons bearer signés, vous pouvez aussi définir --ws-issuer, --ws-audience et --ws-max-clock-skew-seconds. Les clients transmettent leurs identifiants sous la forme Authorization: Bearer <token> lors de la négociation WebSocket. App-server vérifie l’authentification avant l’appel JSON-RPC initialize.
Privilégiez --ws-token-file pour éviter de passer les jetons bearer en clair sur la ligne de commande. Utilisez --ws-token-sha256 uniquement si le client conserve le jeton d’origine, à forte entropie, dans un magasin de secrets local distinct. Le hachage sert uniquement à la vérification : les clients ont toujours besoin du jeton d’origine.
En mode WebSocket, app-server utilise des files d’attente de capacité limitée. Si la file des requêtes entrantes est pleine, le serveur rejette toute nouvelle requête avec le code d’erreur JSON-RPC -32001 et le message "Server overloaded; retry later.". Les clients doivent réessayer en augmentant le délai de manière exponentielle et en y ajoutant une variation aléatoire.
Schéma des messages
Les requêtes contiennent method, params et id.
Les exemples utilisent GPT-6.1 Sol. Le compte connecté ou l’espace de travail doit avoir accès à ce modèle. Utilisez model/list pour sélectionner un modèle disponible si nécessaire.
{ "method": "thread/start", "id": 10, "params": { "model": "gpt-6.1-sol" } }Les réponses reprennent l’id et contiennent soit result, soit error :
{ "id": 10, "result": { "thread": { "id": "thr_123" } } }
{ "id": 10, "error": { "code": 123, "message": "Something went wrong" } }
Les notifications omettent id et utilisent uniquement method et params :
{ "method": "turn/started", "params": { "turn": { "id": "turn_456" } } }
Vous pouvez générer un schéma TypeScript ou un ensemble de schémas JSON Schema depuis la CLI. Les fichiers générés correspondent exactement à la version de Codex utilisée pour exécuter la commande :
codex app-server generate-ts --out ./schemas
codex app-server generate-json-schema --out ./schemas
Premiers pas
- Démarrez le serveur avec
codex app-server(transport stdio par défaut),codex app-server --listen ws://127.0.0.1:4500(WebSocket sur TCP) oucodex app-server --listen unix://(socket Unix par défaut). - Connectez un client via le transport sélectionné, puis envoyez
initializesuivi de la notificationinitialized. - Démarrez un fil de conversation et un tour, puis continuez à lire les notifications sur le flux de transport actif.
Exemple (Node.js / TypeScript) :
import { spawn } from "node:child_process";
import readline from "node:readline";
const proc = spawn("codex", ["app-server"], {
stdio: ["pipe", "pipe", "inherit"],
});
const rl = readline.createInterface({ input: proc.stdout });
const send = (message: unknown) => {
proc.stdin.write(`${JSON.stringify(message)}\n`);
};
let threadId: string | null = null;
rl.on("line", (line) => {
const msg = JSON.parse(line) as any;
console.log("server:", msg);
if (msg.id === 0 && msg.result) {
send({ method: "initialized", params: {} });
send({
method: "thread/start",
id: 1,
params: { model: "gpt-6.1-sol" },
});
}
if (msg.method === "turn/completed") {
if (msg.params?.turn?.status !== "completed") {
console.error(msg.params?.turn?.error ?? "The turn did not complete.");
process.exitCode = 1;
}
proc.stdin.end();
rl.close();
}
if (msg.error) {
console.error(msg.error);
process.exitCode = 1;
proc.stdin.end();
rl.close();
}
if (msg.id === 1 && msg.result?.thread?.id && !threadId) {
threadId = msg.result.thread.id;
send({
method: "turn/start",
id: 2,
params: {
threadId,
input: [{ type: "text", text: "Summarize this repo." }],
},
});
}
});
send({
method: "initialize",
id: 0,
params: {
clientInfo: {
name: "my_product",
title: "My Product",
version: "0.1.0",
},
},
});
proc.on("error", (error) => {
console.error(error);
process.exitCode = 1;
rl.close();
});
proc.on("exit", (code) => {
if (code !== 0) process.exitCode = code ?? 1;
});Concepts fondamentaux
- Fil de conversation : conversation entre un utilisateur et l’agent Codex. Un fil contient des tours.
- Tour : requête d’un utilisateur et travail effectué ensuite par l’agent. Un tour contient des éléments et diffuse des mises à jour au fur et à mesure.
- Élément : unité d’entrée ou de sortie (message de l’utilisateur ou de l’agent, exécution de commande, modification de fichier, appel d’outil, etc.).
Utilisez les API de gestion des fils pour créer, lister ou archiver des conversations. Pilotez une conversation avec les API de gestion des tours et suivez sa progression en continu grâce aux notifications de tour.
Cycle de vie
- Initialisez chaque connexion une seule fois : dès l’ouverture de la connexion de transport, envoyez une requête
initializeavec les métadonnées du client, puis émettezinitialized. Avant cet échange, le serveur rejette toute autre requête sur cette connexion. - Démarrez ou reprenez un fil : appelez
thread/startpour créer une conversation,thread/resumepour en poursuivre une outhread/forkpour copier l’historique dans un nouveau fil doté de son propre identifiant. - Démarrez un tour : appelez
turn/startavec lethreadIdcible et la saisie de l’utilisateur. Des champs facultatifs permettent de redéfinir le modèle, le répertoire de travail et la politique du bac à sable. - Orientez un tour actif : appelez
turn/steerpour ajouter une saisie de l’utilisateur au tour en cours sans créer de nouveau tour. - Lisez les événements en continu : après
turn/start, continuez à lire les notifications sur stdout :thread/archived,thread/unarchived,item/started,item/completed,item/agentMessage/delta, progression des outils et autres mises à jour. - Terminez le tour : le serveur émet
turn/completedavec le statut final lorsque le modèle a terminé ou après une annulation viaturn/interrupt.
Initialisation
Pour chaque connexion de transport, le client doit envoyer une seule requête initialize avant d’appeler toute autre méthode, puis confirmer l’initialisation avec une notification initialized. Les requêtes envoyées avant l’initialisation reçoivent l’erreur Not initialized. Tout nouvel appel à initialize sur la même connexion renvoie Already initialized.
Le serveur renvoie la chaîne d’agent utilisateur qu’il présentera aux services en amont, ainsi que les valeurs platformFamily et platformOs décrivant la plateforme d’exécution cible. Renseignez clientInfo pour identifier votre intégration.
initialize.params.capabilities prend également en charge les capacités client suivantes :
optOutNotificationMethods: noms exacts des méthodes de notification à désactiver pour cette connexion. La correspondance doit être exacte, sans caractères génériques ni préfixes. Les noms inconnus sont acceptés et ignorés.requestAttestation: indique que le client accepte la requêteattestation/generateémise par le serveur. Les hôtes de bureau qui fournissent une attestation aux services en amont répondent avec une valeur opaque de la forme{ "token": "..." }.mcpServerOpenaiFormElicitation: autorise les serveurs MCP en aval à envoyer la variante demcpServer/elicitation/requestqui utilise le formulaire étendu d’OpenAI.
Important : utilisez clientInfo.name pour identifier votre client auprès de la plateforme de journaux de conformité d’OpenAI. Si vous développez une nouvelle intégration Codex destinée aux entreprises, contactez OpenAI pour la faire ajouter à la liste des clients connus. Pour en savoir plus, consultez la référence des journaux Codex.
Exemple tiré de l’extension Codex pour VS Code :
{
"method": "initialize",
"id": 0,
"params": {
"clientInfo": {
"name": "codex_vscode",
"title": "Codex VS Code Extension",
"version": "0.1.0"
}
}
}
Exemple avec désactivation de certaines notifications :
{
"method": "initialize",
"id": 1,
"params": {
"clientInfo": {
"name": "my_client",
"title": "My Client",
"version": "0.1.0"
},
"capabilities": {
"experimentalApi": true,
"optOutNotificationMethods": ["thread/started", "item/agentMessage/delta"]
}
}
}
Activation de l’API expérimentale
Certaines méthodes et certains champs d’app-server nécessitent l’activation explicite de la capacité experimentalApi.
- Omettez
capabilities(ou définissezexperimentalApisurfalse) pour utiliser uniquement l’API stable. Le serveur rejettera alors les méthodes et champs expérimentaux. - Définissez
capabilities.experimentalApisurtruepour activer les méthodes et champs expérimentaux.
{
"method": "initialize",
"id": 1,
"params": {
"clientInfo": {
"name": "my_client",
"title": "My Client",
"version": "0.1.0"
},
"capabilities": {
"experimentalApi": true
}
}
}
Si un client envoie une méthode ou un champ expérimental sans avoir activé cette capacité, app-server rejette la requête avec le message suivant :
<descriptor> requires experimentalApi capability
Vue d’ensemble de l’API
thread/startcrée un fil, émetthread/startedet abonne automatiquement le client aux événements des tours et des éléments de ce fil.thread/resumerouvre un fil existant à partir de son identifiant afin que les appels ultérieurs àturn/starty ajoutent des tours.thread/forkpermet de forker un fil sous un nouvel identifiant en copiant son historique enregistré. PassezlastTurnIdpour copier l’historique jusqu’à ce tour inclus et exclure les tours suivants, ouephemeral: truepour créer un fork en mémoire. La méthode émetthread/startedpour le nouveau fil. Les fils renvoyés contiennentforkedFromIdsi cette valeur est disponible.thread/readlit les métadonnées enregistrées d’un fil à partir de son identifiant sans le reprendre. Utilisezthread/turns/listetthread/items/listpour charger l’historique. Les objetsthreadrenvoyés contiennent le statut d’exécutionstatus.thread/listparcourt les fils enregistrés page par page et indique leur statut d’exécution. Consultez la section sur la pagination et les filtres.thread/turns/listparcourt l’historique des tours d’un fil enregistré sans le reprendre.itemsViewdétermine si les éléments des tours sont omis, résumés ou chargés intégralement.thread/items/listparcourt les éléments enregistrés d’un fil, avec la possibilité de limiter les résultats à un seulturnId. Le système de stockage actif doit prendre en charge la pagination des éléments.thread/loaded/listliste les identifiants des fils actuellement chargés en mémoire.thread/name/setdéfinit ou modifie le nom affiché à l’utilisateur pour un fil chargé ou un journal de session enregistré, puis émetthread/name/updated.thread/goal/setdéfinit l’objectif d’un fil et émetthread/goal/updated.thread/goal/getlit l’objectif actuel d’un fil.thread/goal/clearefface l’objectif d’un fil et émetthread/goal/cleared.thread/metadata/updatemet à jour les métadonnées Git enregistrées pour un fil.thread/archivedéplace le fichier journal d’un fil dans le répertoire des archives et tente d’archiver les journaux de ses descendants qui ne sont pas déjà archivés. La méthode renvoie{}en cas de réussite et émetthread/archivedpour chaque fil archivé.thread/deletesupprime définitivement un fil enregistré, actif ou archivé, ainsi que tous ses descendants. La méthode renvoie{}en cas de réussite et émetthread/deletedpour chaque fil supprimé.thread/unsubscribedésabonne la connexion des événements de tour et d’élément du fil. S’il s’agissait du dernier abonné, le serveur décharge le fil après un délai d’inactivité sans abonné et émetthread/closed.thread/unarchiverestaure le journal d’un fil archivé dans le répertoire des sessions actives, renvoie lethreadrestauré et émetthread/unarchived.thread/status/changedest une notification émise lorsque lestatusd’exécution d’un fil chargé change.thread/compact/startdéclenche le compactage de l’historique d’un fil et renvoie immédiatement{}. Les notificationsturn/*etitem/*indiquent la progression.thread/shellCommandexécute dans un fil une commande shell lancée par l’utilisateur. La commande s’exécute hors du bac à sable avec un accès complet, sans hériter de la politique du bac à sable du fil.thread/backgroundTerminals/cleanarrête tous les terminaux en arrière-plan en cours d’exécution pour un fil (expérimental, nécessitecapabilities.experimentalApi).thread/backgroundTerminals/listliste les terminaux en arrière-plan en cours d’exécution pour un fil chargé (expérimental, nécessitecapabilities.experimentalApi).thread/backgroundTerminals/terminatearrête un terminal en arrière-plan à partir de sonprocessIdapp-server (expérimental, nécessitecapabilities.experimentalApi).thread/revertsupprime un tour donné et tous les tours suivants de l’historique d’un fil persistant paginé. La méthode renvoie les métadonnées et les curseurs d’historique mis à jour, puis émetthread/reverted.turn/startajoute une saisie utilisateur ou la sortie autonome d’un outil à un fil et lance la génération par Codex. La méthode renvoie leturninitial et diffuse les événements. PourcollaborationMode,settings.developer_instructions: nullsignifie « utiliser les instructions intégrées du mode sélectionné ».thread/inject_itemsajoute des éléments bruts de l’API Responses à l’historique d’un fil chargé accessible au modèle, sans démarrer de tour utilisateur.turn/steerajoute une saisie utilisateur au tour en cours d’un fil et renvoie leturnIdaccepté.turn/interruptdemande l’annulation d’un tour en cours. En cas de réussite, la méthode renvoie{}et le tour se termine avecstatus: "interrupted".review/startlance la revue de code du fil par Codex et émet des élémentsenteredReviewModeetexitedReviewMode.command/execexécute une commande dans le bac à sable du serveur sans démarrer de fil ni de tour.command/exec/writeécrit des octets surstdindans une sessioncommand/execen cours ou fermestdin.command/exec/resizeredimensionne le pseudo-terminal d’une sessioncommand/execen cours.command/exec/terminatearrête une sessioncommand/execen cours.command/exec/outputDelta(notification) transmet les fragments de stdout et stderr encodés en base64 d’une sessioncommand/execdont la sortie est diffusée en continu.process/spawndémarre explicitement une session de processus hors du bac à sable de Codex (expérimental, nécessitecapabilities.experimentalApi).process/writeStdinécrit des octets sur stdin dans une sessionprocess/spawnen cours ou ferme stdin (expérimental).process/resizePtyredimensionne le pseudo-terminal d’une session de processus en cours (expérimental).process/killarrête une session de processus en cours (expérimental).process/outputDeltaetprocess/exited(notifications) transmettent respectivement la sortie du processus en continu et son statut de sortie (expérimental).model/listliste les modèles disponibles (définissezincludeHidden: truepour inclure les entrées avechidden: true), leurs niveaux d’effort, le champ facultatifupgradeetinputModalities.modelProvider/capabilities/readlit les limites des capacités du fournisseur pour chaque combinaison de modèle et de fournisseur.experimentalFeature/listliste les indicateurs de fonctionnalité avec leur stade de développement et une pagination par curseur.experimentalFeature/enablement/setmodifie les paramètres d’exécution en mémoire pour les clés de fonctionnalité prises en charge, commeappsetplugins.environment/info(expérimental) se connecte à un environnement d’exécution configuré et renvoie son shell et son répertoire de travail par défaut.permissionProfile/listliste les profils d’autorisations bêta avec pagination par curseur et indique si les exigences en vigueur permettent d’utiliser chaque profil.collaborationMode/listliste les modes de collaboration prédéfinis (expérimental, sans pagination).skills/listliste les skills pour une ou plusieurs valeurs decwd(prend en chargeforceReloadet le paramètre facultatifperCwdExtraUserRoots).skills/extraRoots/setremplace, pour le processus, les racines supplémentaires utilisées pour découvrir les skills autonomes, sans enregistrer ces racines de façon persistante.skills/changed(notification) signale la modification d’un fichier local de skill sous surveillance.hooks/listliste les hooks de cycle de vie détectés pour une ou plusieurs valeurs decwd.marketplace/addajoute une marketplace de plugins distante et l’enregistre dans la configuration des marketplaces de l’utilisateur.marketplace/removesupprime une marketplace configurée et son répertoire racine installé, s’il existe.marketplace/upgradeactualise une marketplace Git configurée, ou toutes les marketplaces Git configurées si vous omettez le nom.plugin/list(en développement) liste les marketplaces de plugins détectées et l’état des plugins, notamment les métadonnées des politiques d’installation et d’authentification, les erreurs de chargement des marketplaces, les identifiants des plugins mis en avant et les métadonnées des sources locales, Git, distantes ou issues d’un registre de paquets. Les résumés peuvent contenir laversiondistante, la version localelocalVersion, des icônes structurées pour les thèmes clair et sombre, ainsi queinstallPolicySource, qui peut valoirnull,WORKSPACE_SETTINGouIMPLICIT_CANONICAL_APPpour les entrées distantes actuelles. N’appelez pas encore cette méthode depuis des clients en production.plugin/read(en développement) lit un plugin à partir du chemin de la marketplace ou du nom de la marketplace distante, et du nom du plugin. La réponse comprend les skills et applications fournis, les noms des serveurs MCP et leshareUrldu plugin distant si le catalogue en fournit un. N’appelez pas encore cette méthode depuis des clients en production.plugin/install(en développement) installe un plugin à partir du chemin de la marketplace ou du nom de la marketplace distante. N’appelez pas encore cette méthode depuis des clients en production.plugin/uninstall(en développement) désinstalle un plugin installé. N’appelez pas encore cette méthode depuis des clients en production.plugin/skill/readlit à la demande le Markdown d’un skill de plugin distant à partir de la marketplace distante, de l’identifiant du plugin et du nom du skill.app/installedlit l’état d’exécution des applications installées et indique, pour chacune, si elle est effectivement activée et peut être appelée.app/listliste les applications (connecteurs) disponibles avec pagination et indique si elles sont accessibles et activées.app/readrécupère, pour les identifiants d’application spécifiés, les métadonnées et, sur demande, des résumés d’outils destinés uniquement à l’affichage.skills/config/writeactive ou désactive des skills à partir de leur chemin.mcpServer/oauth/loginlance la connexion OAuth à un serveur MCP configuré. Ouvrez l’URL HTTP ou HTTPS renvoyée dansauthorizationUrl, puis utilisezloginIdpour identifier la notificationmcpServer/oauthLogin/completedcorrespondante.tool/requestUserInputpose une à trois questions courtes à l’utilisateur pour un appel d’outil (expérimental). Une question peut définirisOtherpour proposer une réponse libre.mcpServer/elicitation/request(requête du serveur) demande au client de fournir des données structurées via un formulaire ou de confirmer une procédure par URL à la demande d’un serveur MCP.item/permissions/requestApproval(requête du serveur) demande au client d’accorder tout ou partie des autorisations réseau ou de système de fichiers demandées par l’outil intégrérequest_permissions.config/mcpServer/reloadrecharge la configuration des serveurs MCP depuis le disque et programme son actualisation pour les fils chargés.mcpServerStatus/listliste les serveurs MCP, leurs outils, leurs ressources et leur état d’authentification (pagination par curseur avec limite). Utilisezdetail: "full"pour obtenir toutes les données oudetail: "toolsAndAuthOnly"pour omettre les ressources. Dans les deux modes, la réponse contient les capacités annoncées par le serveur dansserverCapabilities, ounulltant que l’initialisation n’a pas réussi. PassezserverNamepour interroger un seul serveur. AvecthreadId, la requête réutilise la connexion MCP du fil.mcpServer/resource/readlit une ressource MCP via un serveur MCP initialisé.mcpServer/tool/callappelle un outil sur le serveur MCP configuré pour un fil.mcpServer/startupStatus/updated(notification) signale un changement de l’état de démarrage d’un serveur MCP configuré pour un fil chargé.windowsSandbox/readinessvérifie si le bac à sable Windows est prêt. Si la méthode renvoieupdateRequired, appelezwindowsSandbox/setupStartet attendezwindowsSandbox/setupCompleted.feedback/uploadenvoie un rapport de retour utilisateur avec sa catégorie, un motif et des journaux facultatifs, l’identifiant de conversation et, éventuellement, des fichiers joints viaextraLogFiles.config/readrécupère la configuration effective sur disque après combinaison des différentes couches de configuration.externalAgentConfig/detectdétecte les éléments d’agents externes pouvant être migrés, avecincludeHomeet le paramètre facultatifcwds. Chaque élément détecté contientcwd(nullpour le répertoire personnel).externalAgentConfig/importimporte les éléments sélectionnés d’un agent externe. Passez explicitementmigrationItemsaveccwd(nullpour le répertoire personnel). Les types pris en charge comprennent la configuration, les skills,AGENTS.md, les plugins, la configuration des serveurs MCP, les sous-agents, les hooks, les commandes et les sessions. Les imports non vides émettentexternalAgentConfig/import/progressetexternalAgentConfig/import/completedà mesure que les opérations se terminent. L’import des plugins et des sessions peut se terminer de manière asynchrone.config/value/writeécrit une paire clé-valeur dans le fichierconfig.tomlde l’utilisateur sur disque.config/batchWriteapplique de façon atomique plusieurs modifications au fichierconfig.tomlde l’utilisateur sur disque.configRequirements/readrécupère les exigences provenant derequirements.toml, de la gestion des appareils mobiles (MDM) ou des deux, notamment les listes d’autorisation et les valeurs imposées defeatureRequirements. Les clients qui activentexperimentalApipeuvent aussi lire les exigences réseau administrées.fs/readFile,fs/writeFile,fs/createDirectory,fs/getMetadata,fs/readDirectory,fs/remove,fs/copy,fs/watch,fs/unwatchetfs/changed(notification) opèrent sur des chemins absolus via l’API v2 du système de fichiers d’app-server.
Dans les résumés de plugins, source est un type union. Les plugins locaux renvoient { "type": "local", "path": ... }, les entrées de marketplace Git renvoient { "type": "git", "url": ..., "path": ..., "refName": ..., "sha": ... }, les entrées de registre de paquets renvoient { "type": "npm", "package": ..., "version": ..., "registry": ... } et les entrées de catalogue distant renvoient { "type": "remote" }. Pour les entrées disponibles uniquement dans un catalogue distant, PluginMarketplaceEntry.path peut valoir null. Passez remoteMarketplaceName à la place de marketplacePath pour lire ou installer ces plugins.
Modèles
Lister les modèles (model/list)
Appelez model/list pour afficher dans le sélecteur de modèle les modèles disponibles et leurs niveaux d’effort de raisonnement.
La réponse ci-dessous illustre la structure des données. Les modèles disponibles, les niveaux d’effort de raisonnement et les valeurs par défaut dépendent du client et du compte. Utilisez les valeurs renvoyées au lieu de coder en dur celles de cet exemple.
{ "method": "model/list", "id": 6, "params": { "limit": 20, "includeHidden": false } }
{ "id": 6, "result": {
"data": [{
"id": "gpt-6.1-sol",
"model": "gpt-6.1-sol",
"displayName": "GPT-6.1 Sol",
"hidden": false,
"defaultReasoningEffort": "medium",
"supportedReasoningEfforts": [{
"reasoningEffort": "medium",
"description": "Balances speed and reasoning depth for everyday tasks"
}],
"inputModalities": ["text", "image"],
"supportsPersonality": false,
"isDefault": true
}],
"nextCursor": null
} }
Chaque entrée de modèle peut contenir les champs suivants :
supportedReasoningEfforts: niveaux d’effort pris en charge par le modèle.defaultReasoningEffort: niveau d’effort par défaut suggéré aux clients.upgrade: identifiant facultatif du modèle recommandé pour les invitations à migrer affichées par les clients.upgradeInfo: métadonnées facultatives de mise à niveau pour ces invitations à migrer.hidden: indique si le modèle est masqué dans la liste par défaut du sélecteur.inputModalities: types d’entrée pris en charge par le modèle (par exempletext,image).supportsPersonality: champ de compatibilité obsolète, toujours égal àfalse. Les modèles ne prennent plus en charge la sélection d’une personnalité.isDefault: indique si ce modèle est recommandé par défaut.
Si le fournisseur utilisé au démarrage ne satisfait plus aux exigences administrées, model/list renvoie -32600 et demande au client de redémarrer Codex.
Par défaut, model/list renvoie uniquement les modèles visibles dans le sélecteur. Définissez includeHidden: true si vous avez besoin de la liste complète et souhaitez la filtrer côté client avec hidden.
Si inputModalities est absent (anciens catalogues de modèles), utilisez ["text", "image"] pour assurer la rétrocompatibilité.
Lister les fonctionnalités expérimentales (experimentalFeature/list)
Utilisez ce point de terminaison pour découvrir les indicateurs de fonctionnalité, leurs métadonnées et leur stade de développement :
{ "method": "experimentalFeature/list", "id": 7, "params": { "limit": 20 } }
{ "id": 7, "result": {
"data": [{
"name": "unified_exec",
"stage": "beta",
"displayName": "Unified exec",
"description": "Use the unified PTY-backed execution tool.",
"announcement": "Beta rollout for improved command execution reliability.",
"enabled": false,
"defaultEnabled": false
}],
"nextCursor": null
} }
stage peut valoir beta, underDevelopment, stable, deprecated ou removed. Pour les indicateurs hors bêta, displayName, description et announcement peuvent valoir null.
Inspecter un environnement d’exécution (expérimental)
Utilisez environment/info pour inspecter un environnement distant configuré avant d’y travailler. Cette méthode nécessite capabilities.experimentalApi = true.
{ "method": "environment/info", "id": 8, "params": { "environmentId": "devbox" } }
{ "id": 8, "result": {
"shell": { "name": "zsh", "path": "/bin/zsh" },
"cwd": "file:///workspace/project"
} }
cwd peut valoir null. Lorsqu’il est renseigné, il s’agit d’un URI file: canonique utilisant la syntaxe de chemin native de l’environnement. Un identifiant d’environnement inconnu, un échec de connexion ou une erreur de protocole entraîne une erreur de requête.
Fils de conversation
thread/readlit les métadonnées enregistrées d’un fil sans abonner le client à ses événements.thread/turns/listparcourt l’historique des tours d’un fil enregistré sans le reprendre. UtilisezitemsViewpour omettre les éléments des tours, en obtenir un résumé ou les charger intégralement.thread/items/listparcourt les éléments enregistrés du fil, avec la possibilité de limiter les résultats à un tour.thread/listparcourt les fils enregistrés page par page. UtilisezsectionIdpour lister les fils d’une section ouexcludedThreadIdspour exclure les fils déjà affichés.thread/loaded/listrenvoie les identifiants des fils actuellement en mémoire.thread/archivedéplace le journal JSONL enregistré du fil dans le répertoire des archives et tente d’archiver les journaux de ses descendants qui ne sont pas déjà archivés.thread/deletesupprime définitivement un fil enregistré, actif ou archivé, ainsi que ses descendants.thread/metadata/updatemet à jour le champgitInfoenregistré pour un fil.thread/unsubscribedésabonne la connexion actuelle d’un fil chargé et peut déclencherthread/closedaprès un délai d’inactivité.thread/unarchiverestaure le journal d’un fil archivé dans le répertoire des sessions actives.thread/compact/startdéclenche le compactage et renvoie immédiatement{}.thread/revertsupprime un tour donné et tous les tours suivants de l’historique d’un fil persistant paginé. Les fichiers locaux ne sont pas modifiés.thread/inject_itemsajoute des éléments bruts de l’API Responses à l’historique d’un fil chargé accessible au modèle, sans démarrer de tour utilisateur.
Démarrer ou reprendre un fil
Démarrez un fil pour créer une nouvelle conversation Codex.
{ "method": "thread/start", "id": 10, "params": {
"model": "gpt-6.1-sol",
"cwd": "/Users/me/project",
"approvalPolicy": "never",
"sandbox": "workspace-write",
"serviceName": "my_app_server_client"
} }
{ "id": 10, "result": {
"thread": {
"id": "thr_123",
"sessionId": "thr_123",
"preview": "",
"ephemeral": false,
"modelProvider": "openai",
"createdAt": 1730910000
}
} }
{ "method": "thread/started", "params": { "thread": { "id": "thr_123" } } }serviceName est facultatif. Renseignez-le pour qu’app-server associe le nom de service de votre intégration aux métriques du fil.
thread/start, thread/resume et thread/fork renvoient instructionSources, un tableau contenant les chemins des fichiers d’instructions chargés. Chaque chemin absolu utilise la syntaxe native de son environnement d’origine, y compris pour les environnements distants.
Par défaut, les nouveaux fils locaux persistants utilisent un historique paginé. Chargez l’historique avec thread/turns/list et thread/items/list. La définition explicite de historyMode sur "legacy" ou "paginated" lors d’un appel à thread/start est expérimentale et nécessite capabilities.experimentalApi = true.
Les clients bêta qui activent capabilities.experimentalApi peuvent passer l’identifiant d’un profil d’autorisations nommé dans permissions à la place de l’ancien champ sandbox. N’envoyez pas permissions et sandbox ensemble. Utilisez permissionProfile/list avec le cwd du projet pour connaître les profils disponibles et vérifier si les exigences administrées autorisent chacun d’eux.
thread.sessionId identifie la racine de l’arborescence de la session active. Les fils racines utilisent leur propre identifiant comme identifiant de session. Les fils issus d’un fork conservent l’identifiant de session de leur racine d’origine. Les clients doivent lire l’identifiant de session dans thread.sessionId plutôt que de le déduire de l’identifiant du fil.
Pour poursuivre une session enregistrée, appelez thread/resume avec le thread.id conservé précédemment. Passez excludeTurns: true pour obtenir les métadonnées du fil et l’état de la session active, puis chargez l’historique avec les méthodes de pagination :
{ "method": "thread/resume", "id": 11, "params": {
"threadId": "thr_123",
"excludeTurns": true
} }
{ "id": 11, "result": { "thread": { "id": "thr_123", "name": "Bug bash notes", "ephemeral": false } } }
Pour les fils paginés, les réponses de thread/resume et thread/fork contenant l’historique complet sont obsolètes et entraînent l’émission de deprecationNotice. Les deux méthodes acceptent excludeTurns: true sans activation de l’API expérimentale. Une réponse de thread/resume peut également contenir turnsBackwardsCursor et itemsBackwardsCursor. Passez chaque curseur à la méthode de pagination correspondante avec sortDirection: "desc". La première page inclut l’entrée sur laquelle pointe le curseur.
La reprise d’un fil ne met pas à jour à elle seule thread.updatedAt ni la date de modification du fichier journal de session. L’horodatage est mis à jour au démarrage d’un tour.
Si vous marquez un serveur MCP activé comme required dans la configuration et que son initialisation échoue, thread/start et thread/resume échouent au lieu de poursuivre sans ce serveur.
Le champ dynamicTools de thread/start est expérimental (il nécessite capabilities.experimentalApi = true). Codex enregistre ces outils dynamiques dans les métadonnées du journal de session du fil et les restaure lors de thread/resume si vous ne fournissez pas de nouveaux outils dynamiques.
Si le fournisseur de modèles configuré diffère de celui enregistré pour le fil, thread/resume et toute nouvelle saisie renvoient -32600 avec data.type égal à modelProviderMismatch. Pour afficher l’historique du fil, parcourez ses tours page par page avec thread/turns/list. Rétablissez le fournisseur enregistré pour poursuivre le fil ou appelez thread/fork pour démarrer un nouveau fil à partir de cet historique avec le fournisseur actuel.
Si vous reprenez le fil avec un modèle différent de celui enregistré dans le journal de session, Codex émet un avertissement et applique une instruction de changement de modèle uniquement au tour suivant.
Gérer l’objectif d’un fil
Utilisez thread/goal/set, thread/goal/get et thread/goal/clear pour gérer l’état persistant de l’objectif que /goal affiche dans l’interface de terminal.
{ "method": "thread/goal/set", "id": 13, "params": {
"threadId": "thr_123",
"objective": "Finish the migration and keep tests green",
"status": "active",
"tokenBudget": 40000
} }
{ "id": 13, "result": { "goal": {
"threadId": "thr_123",
"objective": "Finish the migration and keep tests green",
"status": "active",
"tokenBudget": 40000,
"tokensUsed": 0,
"timeUsedSeconds": 0
} } }
{ "method": "thread/goal/updated", "params": {
"threadId": "thr_123",
"goal": {
"threadId": "thr_123",
"objective": "Finish the migration and keep tests green",
"status": "active",
"tokenBudget": 40000,
"tokensUsed": 0,
"timeUsedSeconds": 0
}
} }
Le texte de l’objectif doit être non vide et comporter au maximum 4 000 caractères. Un nouvel objectif remplace le précédent et remet les compteurs d’utilisation à zéro. Si vous fournissez l’objectif actuel alors qu’il n’a pas atteint un état final, ou si vous omettez objective, vous pouvez mettre à jour le statut ou le budget de tokens tout en conservant l’historique d’utilisation.
Pour créer une branche à partir d’une session enregistrée, appelez thread/fork avec le thread.id. Cette opération crée un nouvel identifiant de fil et émet une notification thread/started pour ce fil. Passez lastTurnId pour copier l’historique jusqu’à ce tour inclus et exclure les tours suivants :
{ "method": "thread/fork", "id": 12, "params": { "threadId": "thr_123", "lastTurnId": "turn_456", "excludeTurns": true } }
{ "id": 12, "result": { "thread": { "id": "thr_456", "sessionId": "thr_123", "forkedFromId": "thr_123" } } }
{ "method": "thread/started", "params": { "thread": { "id": "thr_456" } } }
App-server rejette un lastTurnId correspondant à un tour en cours. Si vous omettez ce champ alors qu’un tour est en cours dans le fil source, le fork enregistre un marqueur d’interruption pour signaler que ce tour est partiel.
Passez ephemeral: true pour créer un fork en mémoire sans l’ajouter à la liste des fils enregistrés :
{
"method": "thread/fork",
"id": 13,
"params": {
"threadId": "thr_123",
"ephemeral": true,
"excludeTurns": true
}
}
{
"id": 13,
"result": {
"thread": {
"id": "thr_789",
"sessionId": "thr_789",
"forkedFromId": "thr_123",
"ephemeral": true
}
}
}
Les forks éphémères de fils paginés nécessitent excludeTurns: true.
Si un titre destiné à l’utilisateur a été défini pour le fil, app-server renseigne thread.name dans les réponses de thread/list, thread/read, thread/resume et thread/unarchive. Les méthodes thread/start et thread/fork peuvent omettre name (ou renvoyer null) tant qu’aucun titre n’a été défini.
Lire un fil enregistré sans le reprendre
Utilisez thread/read pour obtenir les données enregistrées d’un fil sans le reprendre ni vous abonner à ses événements.
includeTurns: avecfalseou en l’absence de ce champ, la réponse contient uniquement le résumé du fil. La valeurtruecharge l’historique complet. Ce comportement est obsolète pour les fils paginés et entraîne l’émission dedeprecationNotice. Utilisez plutôt les méthodes de pagination.- Les objets
threadrenvoyés contiennent le statut d’exécutionstatus(notLoaded,idle,systemErrorouactiveavecactiveFlags).
{ "method": "thread/read", "id": 19, "params": { "threadId": "thr_123" } }
{ "id": 19, "result": { "thread": { "id": "thr_123", "name": "Bug bash notes", "ephemeral": false, "status": { "type": "notLoaded" }, "turns": [] } } }
Contrairement à thread/resume, thread/read ne charge pas le fil en mémoire et n’émet pas thread/started.
Lister les tours d’un fil
Utilisez thread/turns/list pour parcourir l’historique des tours d’un fil enregistré sans le reprendre. Par défaut, les résultats commencent par les tours les plus récents. Le client peut ainsi récupérer les tours plus anciens avec nextCursor. La réponse contient aussi backwardsCursor. Passez-le dans cursor avec la valeur opposée de sortDirection pour inverser le sens de parcours. Le tour sur lequel pointe le curseur est alors inclus de nouveau, ce qui permet de récupérer ses éventuelles mises à jour.
itemsView détermine le niveau de détail des éléments de tour dans la réponse :
notLoadedomet les éléments.summaryrenvoie un résumé des éléments. C’est la valeur par défaut si le champ est omis.fullrenvoie toutes les données des éléments.
{ "method": "thread/turns/list", "id": 20, "params": {
"threadId": "thr_123",
"limit": 50,
"sortDirection": "desc",
"itemsView": "summary"
} }
{ "id": 20, "result": {
"data": [],
"nextCursor": "older-turns-cursor-or-null",
"backwardsCursor": "newer-turns-cursor-or-null"
} }
Lister les éléments d’un fil
thread/items/list parcourt les éléments enregistrés sans reprendre le fil. Passez turnId pour limiter les résultats à un tour ou omettez-le pour parcourir les éléments de tout le fil. Par défaut, les éléments les plus anciens apparaissent en premier (sortDirection: "asc"). Le système de stockage actif doit prendre en charge la pagination des éléments, sinon le serveur renvoie une erreur indiquant que la méthode n’est pas prise en charge.
Passez un nextCursor opaque issu d’une réponse précédente pour poursuivre la pagination. Pour commencer après un élément connu, passez cet élément comme point d’ancrage ainsi qu’un turnId non vide :
{ "method": "thread/items/list", "id": 21, "params": {
"threadId": "thr_123",
"turnId": "turn_456",
"cursor": { "type": "item", "itemId": "item_123" },
"sortDirection": "asc",
"limit": 50
} }
{ "id": 21, "result": {
"data": [],
"nextCursor": null,
"backwardsCursor": null
} }
L’élément d’ancrage est exclu des résultats : l’ordre croissant renvoie les éléments plus récents et l’ordre décroissant, les éléments plus anciens. L’élément doit appartenir à l’historique visible du tour demandé. Si turnId est absent, si l’identifiant de l’élément est vide ou si l’élément est inconnu ou hors du périmètre demandé, le serveur renvoie une erreur de paramètres non valides (-32602). Poursuivez avec la chaîne nextCursor renvoyée. Chaque entrée contient turnId, item et, s’ils ont été enregistrés, les horodatages de début et de fin.
Lister les fils avec pagination et filtres
thread/list permet d’afficher l’historique dans une interface. Par défaut, les résultats sont triés du plus récent au plus ancien selon createdAt. Les filtres s’appliquent avant la pagination. Vous pouvez combiner les paramètres suivants :
cursor: chaîne opaque issue d’une réponse précédente. Omettez-la pour la première page.limit: si cette valeur est omise, le serveur choisit une taille de page adaptée.sortKey:created_at(par défaut),updated_at,recency_atousection_position. Pour utilisersection_position, fournissez unsectionIdnon nul.sortDirection:ascoudesc. Si vous omettezsortDirection, le tri est croissant poursection_positionet décroissant pour les clés temporelles.sectionId: passez l’identifiant d’une section pour lister ses fils ounullpour lister les fils sans section. Omettez le champ pour inclure les fils de toutes les sections ainsi que ceux sans section.excludedThreadIds: spécifiez jusqu’à 100 identifiants de fils à exclure. Les doublons comptent dans la limite de 100 identifiants. Le serveur exclut les fils correspondants avant d’appliquer la limite de la page. Envoyez les mêmes exclusions avec chaque curseur.modelProviders: limite les résultats aux fournisseurs spécifiés. Passez[]pour inclure tous les fournisseurs. Si vous omettez ce champ ou passeznull, le serveur utilise le fournisseur configuré, sauf si vous filtrez les fils selon leur relation de parenté, auquel cas il inclut tous les fournisseurs.sourceKinds: limite les résultats aux sources de fils spécifiées. Si vous omettez ce champ ou passez[], le serveur inclut par défaut uniquement les sources interactivesclietvscode.archived: avectrue, liste uniquement les fils archivés. Avecfalseou en l’absence de ce champ, liste les fils non archivés (comportement par défaut).cwd: limite les résultats aux fils dont le répertoire de travail courant de la session correspond exactement à ce chemin ou à l’un des chemins d’un tableau. Les chemins relatifs sont résolus à partir du répertoire de travail du processus app-server.useStateDbOnly: avectrue, renvoie les résultats de la base de données d’état sans analyser les journaux JSONL des fils pour réparer les métadonnées. Omettez ce champ ou passezfalsepour conserver l’analyse et la réparation par défaut.searchTerm: limite les résultats aux fils dont le titre extrait contient ce fragment de texte, en respectant la casse.parentThreadId: limite les résultats aux enfants directs du fil parent spécifié. Ce filtre est expérimental et nécessitecapabilities.experimentalApi = true.ancestorThreadId: limite les résultats aux descendants du fil spécifié, à tous les niveaux. Ce filtre est expérimental et nécessitecapabilities.experimentalApi = true. Ne le combinez pas avecparentThreadId.
sourceKinds accepte les valeurs suivantes :
clivscodeexecappServersubAgentsubAgentReviewsubAgentCompactsubAgentThreadSpawnsubAgentOtherunknown
Exemple :
{ "method": "thread/list", "id": 20, "params": {
"cursor": null,
"limit": 25,
"sortKey": "created_at"
} }
{ "id": 20, "result": {
"data": [
{ "id": "thr_a", "preview": "Create a TUI", "ephemeral": false, "section": { "id": "01984de2-8f74-7c91-a3b2-5c5e937cf318", "name": "Pinned", "appearance": null }, "modelProvider": "openai", "createdAt": 1730831111, "updatedAt": 1730831111, "name": "TUI prototype", "status": { "type": "notLoaded" } },
{ "id": "thr_b", "preview": "Fix tests", "ephemeral": false, "section": null, "modelProvider": "openai", "createdAt": 1730750000, "updatedAt": 1730750000, "status": { "type": "notLoaded" } }
],
"nextCursor": "opaque-token-or-null"
} }
Lorsque nextCursor vaut null, vous avez atteint la dernière page.
Organiser les fils en sections
Créez une section nommée avec threadSection/create, puis utilisez le section.id renvoyé dans thread/section/move. Passez beforeThreadId pour insérer le fil avant un autre fil de la section ou omettez ce champ pour l’ajouter à la fin. Passez sectionId: null pour retirer un fil de sa section. Utilisez threadSection/list, threadSection/update et threadSection/delete pour parcourir les sections personnalisées page par page, les renommer et les supprimer. Pour épingler un fil, déplacez-le vers la section intégrée Pinned renvoyée par threadSection/list.
Gérer les ressources associées à un fil
Associez des ressources, comme des pull requests, à un fil enregistré. Vous pouvez gérer ces références sans reprendre le fil.
thread/attachment/addacceptethreadId,attachmentType,identityKeyet unpayloadJSON. Si vous ajoutez à nouveau le même type et la même clé au même fil, la méthode renvoie l’association existante.thread/attachment/listparcourt les ressources associées à un fil page par page. Pour retrouver les fils qui font référence à une ressource, appelezthread/attachmentOwner/listavec sonattachmentTypeet sa cléidentityKey.thread/attachment/removeacceptethreadId,attachmentTypeetidentityKey. La ressource elle-même reste disponible.thread/attachment/updatedsignale une opérationcreatedoudeletedlorsque l’association change.
Mettre à jour les métadonnées enregistrées d’un fil
Utilisez thread/metadata/update pour modifier les métadonnées enregistrées d’un fil sans le reprendre. Passez les champs Git à mettre à jour dans gitInfo. Omettez un champ pour conserver sa valeur ou passez null pour l’effacer.
{ "method": "thread/metadata/update", "id": 21, "params": {
"threadId": "thr_123",
"gitInfo": { "branch": "feature/sidebar-pr" }
} }
{ "id": 21, "result": {
"thread": {
"id": "thr_123",
"gitInfo": { "sha": null, "branch": "feature/sidebar-pr", "originUrl": null }
}
} }
Suivre les changements de statut d’un fil
Le serveur émet thread/status/changed chaque fois que le statut d’exécution d’un fil chargé change. La notification contient threadId et le nouveau status.
{
"method": "thread/status/changed",
"params": {
"threadId": "thr_123",
"status": { "type": "active", "activeFlags": ["waitingOnApproval"] }
}
}
Lister les fils chargés
thread/loaded/list renvoie les identifiants des fils actuellement chargés en mémoire.
{ "method": "thread/loaded/list", "id": 21 }
{ "id": 21, "result": { "data": ["thr_123", "thr_456"] } }
Se désabonner d’un fil chargé
thread/unsubscribe désabonne la connexion actuelle d’un fil. La réponse contient l’un des statuts suivants :
unsubscribedsi la connexion était abonnée et que l’abonnement a été supprimé.notSubscribedsi la connexion n’était pas abonnée à ce fil.notLoadedsi le fil n’est pas chargé.
Après le départ du dernier abonné, app-server décharge le fil après 60 secondes d’inactivité par défaut. Définissez thread_unload_delay_secs pour modifier ce délai. Lorsqu’il décharge le fil, app-server émet thread/status/changed avec le statut notLoaded, ainsi qu’une notification thread/closed.
{ "method": "thread/unsubscribe", "id": 22, "params": { "threadId": "thr_123" } }
{ "id": 22, "result": { "status": "unsubscribed" } }
Si le délai expire ensuite pour ce fil :
{ "method": "thread/status/changed", "params": {
"threadId": "thr_123",
"status": { "type": "notLoaded" }
} }
{ "method": "thread/closed", "params": { "threadId": "thr_123" } }
Archiver un fil
Utilisez thread/archive pour déplacer le journal persistant du fil (un fichier JSONL sur disque) dans le répertoire des sessions archivées. L’opération tente également d’archiver les descendants du fil qui ne sont pas déjà archivés.
{ "method": "thread/archive", "id": 22, "params": { "threadId": "thr_b" } }
{ "id": 22, "result": {} }
{ "method": "thread/archived", "params": { "threadId": "thr_b" } }
{ "method": "thread/archived", "params": { "threadId": "thr_child" } }
Les appels ultérieurs à thread/list excluent les fils archivés, sauf si vous passez archived: true. Le serveur émet une notification thread/archived pour chaque fil effectivement archivé. Si un descendant ne peut pas être archivé, la requête peut tout de même réussir, sans notification d’archivage pour ce descendant.
Supprimer un fil
Utilisez thread/delete pour supprimer définitivement un fil enregistré, actif ou archivé, ainsi que ses descendants. Le serveur supprime les fichiers journaux de session existants et les métadonnées associées avant de confirmer la réussite. Les fichiers absents sont considérés comme déjà supprimés. Les fils racines éphémères ne peuvent pas être supprimés.
{ "method": "thread/delete", "id": 23, "params": { "threadId": "thr_b" } }
{ "id": 23, "result": {} }
{ "method": "thread/deleted", "params": { "threadId": "thr_b" } }
{ "method": "thread/deleted", "params": { "threadId": "thr_child" } }
Restaurer un fil archivé
Utilisez thread/unarchive pour replacer le journal d’un fil archivé dans le répertoire des sessions actives.
{ "method": "thread/unarchive", "id": 24, "params": { "threadId": "thr_b" } }
{ "id": 24, "result": { "thread": { "id": "thr_b", "name": "Bug bash notes" } } }
{ "method": "thread/unarchived", "params": { "threadId": "thr_b" } }
Déclencher le compactage d’un fil
Utilisez thread/compact/start pour déclencher manuellement le compactage de l’historique d’un fil. La requête renvoie immédiatement {}.
App-server signale la progression par des notifications standard turn/* et item/* sur le même threadId, notamment les événements du cycle de vie d’un élément contextCompaction (item/started puis item/completed).
{ "method": "thread/compact/start", "id": 25, "params": { "threadId": "thr_b" } }
{ "id": 25, "result": {} }
Exécuter une commande shell dans un fil
Utilisez thread/shellCommand pour les commandes shell lancées par l’utilisateur dans un fil. La requête renvoie immédiatement {} et les notifications standard turn/* et item/* indiquent la progression.
Cette API s’exécute hors du bac à sable avec un accès complet et n’hérite pas de la politique du bac à sable du fil. Les clients doivent la réserver aux commandes lancées explicitement par l’utilisateur.
Si un tour est déjà actif dans le fil, la commande s’exécute comme une action auxiliaire de ce tour et sa sortie formatée est insérée dans le flux de messages du tour. Si le fil est inactif, app-server démarre un tour distinct pour la commande shell.
Définissez timeoutMs pour limiter le temps d’exécution en millisecondes. Si vous omettez ce champ ou passez null, le délai par défaut est d’une heure. La valeur 0 demande une expiration immédiate. Les valeurs négatives sont rejetées. Le délai ne retarde pas l’accusé de réception immédiat de l’appel RPC.
{ "method": "thread/shellCommand", "id": 26, "params": { "threadId": "thr_b", "command": "git status --short", "timeoutMs": 10000 } }
{ "id": 26, "result": {} }
Arrêter les terminaux en arrière-plan
Utilisez thread/backgroundTerminals/clean pour arrêter tous les terminaux en arrière-plan en cours d’exécution associés à un fil. Cette méthode est expérimentale et nécessite capabilities.experimentalApi = true.
{ "method": "thread/backgroundTerminals/clean", "id": 27, "params": { "threadId": "thr_b" } }
{ "id": 27, "result": {} }
Utilisez thread/backgroundTerminals/list pour inspecter les terminaux en arrière-plan en cours d’exécution pour un fil chargé. La requête prend en charge la pagination standard avec cursor et limit. Le processId renvoyé est l’identifiant de processus attribué par app-server. Cette méthode est expérimentale et nécessite capabilities.experimentalApi = true :
{ "method": "thread/backgroundTerminals/list", "id": 28, "params": { "threadId": "thr_b" } }
{ "id": 28, "result": { "data": [
{
"itemId": "item_456",
"processId": "42",
"command": "python3 -m http.server",
"cwd": "/workspace",
"osPid": null,
"cpuPercent": null,
"rssKb": null
}
], "nextCursor": null } }
Utilisez thread/backgroundTerminals/terminate avec ce processId pour arrêter un seul terminal en arrière-plan. Cette méthode est expérimentale et nécessite capabilities.experimentalApi = true :
{ "method": "thread/backgroundTerminals/terminate", "id": 29, "params": { "threadId": "thr_b", "processId": "42" } }
{ "id": 29, "result": { "terminated": true } }
Rétablir un état antérieur de l’historique
Utilisez thread/revert pour supprimer de l’historique d’un fil persistant paginé le tour identifié par beforeTurnId et tous les tours suivants. Cette opération n’annule pas les modifications des fichiers locaux. Reprenez d’abord le fil s’il n’est pas chargé. Les fils éphémères et les fils utilisant l’ancien format d’historique ne sont pas pris en charge.
{ "method": "thread/revert", "id": 30, "params": { "threadId": "thr_b", "beforeTurnId": "turn_456" } }
{ "id": 30, "result": {
"thread": { "id": "thr_b", "ephemeral": false, "turns": [] },
"turnsBackwardsCursor": "retained-turn-cursor-or-null",
"itemsBackwardsCursor": "retained-item-cursor-or-null"
} }
{ "method": "thread/reverted", "params": { "threadId": "thr_b" } }
Le champ thread.turns renvoyé est toujours vide. Utilisez les curseurs renvoyés avec thread/turns/list ou thread/items/list et sortDirection: "desc" pour charger l’historique conservé, y compris l’entrée sur laquelle pointe le curseur.
La méthode thread/rollback a été supprimée et renvoie une erreur de méthode inconnue. Les marqueurs de retour en arrière présents dans les anciens fils enregistrés restent lisibles.
Tours
Le champ input accepte une liste d’éléments :
{ "type": "text", "text": "Explain this diff" }{ "type": "image", "url": "https://.../design.png" }{ "type": "localImage", "path": "/tmp/screenshot.png" }
Vous pouvez redéfinir les paramètres de configuration pour un tour (modèle, effort, cwd, politique du bac à sable, résumé). Les paramètres fournis deviennent les valeurs par défaut des tours suivants du même fil. outputSchema s’applique uniquement au tour actuel. Pour sandboxPolicy.type = "externalSandbox", définissez networkAccess sur restricted ou enabled. Pour workspaceWrite, networkAccess reste un booléen.
Pour turn/start.collaborationMode, settings.developer_instructions: null signifie « utiliser les instructions intégrées du mode sélectionné ». Cette valeur n’efface pas les instructions du mode.
Accès en lecture dans le bac à sable (ReadOnlyAccess)
sandboxPolicy permet de configurer explicitement les accès en lecture :
readOnly: champaccessfacultatif ({ "type": "fullAccess" }par défaut, ou accès limité à certaines racines).workspaceWrite: champreadOnlyAccessfacultatif ({ "type": "fullAccess" }par défaut, ou accès limité à certaines racines).
Structure d’un accès en lecture restreint :
{
"type": "restricted",
"includePlatformDefaults": true,
"readableRoots": ["/Users/me/shared-read-only"]
}
Sur macOS, includePlatformDefaults: true ajoute une politique Seatbelt prédéfinie pour la plateforme aux sessions dont l’accès en lecture est restreint. Cela améliore la compatibilité des outils sans autoriser l’accès à l’ensemble de /System.
Exemples :
{ "type": "readOnly", "access": { "type": "fullAccess" } }
{
"type": "workspaceWrite",
"writableRoots": ["/Users/me/project"],
"readOnlyAccess": {
"type": "restricted",
"includePlatformDefaults": true,
"readableRoots": ["/Users/me/shared-read-only"]
},
"networkAccess": false
}
Démarrer un tour
{ "method": "turn/start", "id": 30, "params": {
"threadId": "thr_123",
"input": [ { "type": "text", "text": "Run tests" } ],
"cwd": "/Users/me/project",
"approvalPolicy": "on-request",
"sandboxPolicy": {
"type": "workspaceWrite",
"writableRoots": ["/Users/me/project"],
"networkAccess": true
},
"model": "gpt-6.1-sol",
"effort": "medium",
"summary": "concise",
"outputSchema": {
"type": "object",
"properties": { "answer": { "type": "string" } },
"required": ["answer"],
"additionalProperties": false
}
} }
{ "id": 30, "result": { "turn": { "id": "turn_456", "status": "inProgress", "items": [], "error": null } } }Définissez serviceTierForTurn pour modifier l’offre uniquement pour le nouveau tour. Utilisez "default" pour la vitesse standard ou omettez le champ pour hériter de l’offre du fil. Pour modifier l’offre de ce tour et des tours suivants, définissez serviceTier.
Pour démarrer un tour avec la sortie d’un outil exécuté par votre client, passez toolOutput avec un name non vide, un namespace facultatif et un champ output contenant une chaîne ou un tableau d’éléments de contenu. Définissez input sur un tableau vide. Vous ne pouvez pas combiner toolOutput avec une saisie utilisateur non vide.
{
"method": "turn/start",
"id": 31,
"params": {
"threadId": "thr_123",
"input": [],
"toolOutput": {
"name": "run_tests",
"namespace": null,
"output": "All 42 tests passed."
}
}
}
Dans la conversation, la sortie conserve son type de sortie d’outil. Elle apparaît sous la forme d’un élément functionCallOutput dans les notifications et l’historique enregistré. Si un tour ordinaire est déjà actif, Codex place la sortie dans la file d’attente de ce tour.
Insérer des éléments dans un fil
Utilisez thread/inject_items pour ajouter des éléments préconstruits de l’API Responses à l’historique des prompts d’un fil chargé sans démarrer de tour utilisateur. Ces éléments sont enregistrés dans le journal de session et inclus dans les requêtes ultérieures au modèle.
{ "method": "thread/inject_items", "id": 31, "params": {
"threadId": "thr_123",
"items": [
{
"type": "message",
"role": "assistant",
"content": [{ "type": "output_text", "text": "Previously computed context." }]
}
]
} }
{ "id": 31, "result": {} }
Orienter un tour actif
Utilisez turn/steer pour ajouter une saisie utilisateur au tour en cours.
- Incluez
expectedTurnId. Il doit correspondre à l’identifiant du tour actif. - La requête échoue si aucun tour n’est actif dans le fil.
turn/steern’émet pas de nouvelle notificationturn/started.turn/steern’accepte pas la redéfinition de paramètres du tour (model,cwd,sandboxPolicyououtputSchema).
{ "method": "turn/steer", "id": 32, "params": {
"threadId": "thr_123",
"input": [ { "type": "text", "text": "Actually focus on failing tests first." } ],
"expectedTurnId": "turn_456"
} }
{ "id": 32, "result": { "turnId": "turn_456" } }
Démarrer un tour avec un skill
Pour appeler explicitement un skill, incluez $<skill-name> dans la saisie textuelle et ajoutez un élément d’entrée skill à côté du texte.
{ "method": "turn/start", "id": 33, "params": {
"threadId": "thr_123",
"input": [
{ "type": "text", "text": "$skill-creator Add a new skill for triaging flaky CI and include step-by-step usage." },
{ "type": "skill", "name": "skill-creator", "path": "/Users/me/.codex/skills/skill-creator/SKILL.md" }
]
} }
{ "id": 33, "result": { "turn": { "id": "turn_457", "status": "inProgress", "items": [], "error": null } } }
Interrompre un tour
{ "method": "turn/interrupt", "id": 31, "params": { "threadId": "thr_123", "turnId": "turn_456" } }
{ "id": 31, "result": {} }
En cas de réussite, le tour se termine avec status: "interrupted".
Revue de code
review/start lance une revue de code par Codex dans un fil et diffuse les éléments de revue en continu. Les cibles possibles sont les suivantes :
uncommittedChangesbaseBranch(diff par rapport à une branche)commit(revue d’un commit précis)custom(instructions libres)
review/start effectue la revue dans le fil fourni. Omettez delivery ou passez "inline". Pour effectuer une revue distincte, utilisez thread/fork pour inclure l’historique existant ou thread/start pour partir d’un fil vierge. Appelez ensuite review/start avec l’identifiant du nouveau fil.
Exemple de requête et de réponse :
{ "method": "review/start", "id": 40, "params": {
"threadId": "thr_123",
"delivery": "inline",
"target": { "type": "commit", "sha": "1234567deadbeef", "title": "Polish tui colors" }
} }
{ "id": 40, "result": {
"turn": {
"id": "turn_900",
"status": "inProgress",
"items": [
{ "type": "userMessage", "id": "turn_900", "content": [ { "type": "text", "text": "Review commit 1234567: Polish tui colors" } ] }
],
"error": null
},
"reviewThreadId": "thr_123"
} }
Codex émet la notification habituelle turn/started, puis item/started avec un élément enteredReviewMode :
{
"method": "item/started",
"params": {
"item": {
"type": "enteredReviewMode",
"id": "turn_900",
"review": "current changes"
}
}
}
À la fin de la revue, le serveur émet item/started et item/completed avec un élément exitedReviewMode contenant le texte final de la revue :
{
"method": "item/completed",
"params": {
"item": {
"type": "exitedReviewMode",
"id": "turn_900",
"review": "Looks solid overall..."
}
}
}
Utilisez cette notification pour afficher le résultat de la revue dans votre client.
Exécution de processus
process/* est une API expérimentale de contrôle explicite des processus. Elle nécessite capabilities.experimentalApi = true et s’exécute hors du bac à sable de Codex. Utilisez-la uniquement si votre client propose délibérément de contrôler les processus locaux sans bac à sable.
Démarrez un processus avec process/spawn en fournissant un processHandle. Utilisez ensuite cet identifiant pour les requêtes d’écriture sur stdin, de redimensionnement et d’arrêt. Les notifications process/outputDelta diffusent la sortie en continu et process/exited signale la fin du processus.
{ "method": "process/spawn", "id": 48, "params": {
"command": ["python3", "-m", "pytest", "-q"],
"processHandle": "pytest-1",
"cwd": "/Users/me/project",
"tty": true
} }
{ "id": 48, "result": {} }
{ "method": "process/outputDelta", "params": {
"processHandle": "pytest-1",
"stream": "stdout",
"deltaBase64": "Li4u"
} }
{ "method": "process/exited", "params": {
"processHandle": "pytest-1",
"exitCode": 0
} }
Utilisez process/writeStdin avec deltaBase64, closeStdin ou les deux pour transmettre l’entrée. Utilisez process/resizePty pour les événements de redimensionnement du pseudo-terminal et process/kill pour arrêter un processus en cours.
Exécution de commandes
command/exec exécute une seule commande (tableau argv) dans le bac à sable du serveur sans créer de fil.
{ "method": "command/exec", "id": 50, "params": {
"command": ["ls", "-la"],
"cwd": "/Users/me/project",
"sandboxPolicy": { "type": "workspaceWrite" },
"timeoutMs": 10000
} }
{ "id": 50, "result": { "exitCode": 0, "stdout": "...", "stderr": "" } }
Utilisez sandboxPolicy.type = "externalSandbox" si vous isolez déjà le processus serveur dans un bac à sable et souhaitez que Codex n’applique pas le sien. En mode bac à sable externe, définissez networkAccess sur restricted (par défaut) ou enabled. Pour readOnly et workspaceWrite, utilisez la même structure facultative access / readOnlyAccess que dans les exemples précédents.
Remarques :
- Le serveur rejette les tableaux
commandvides. sandboxPolicyaccepte la même structure queturn/start(par exempledangerFullAccess,readOnly,workspaceWrite,externalSandbox).- Si vous omettez
timeoutMs, le serveur utilise son délai par défaut. - Définissez
tty: truepour les sessions utilisant un pseudo-terminal. UtilisezprocessIdsi vous prévoyez d’appeler ensuitecommand/exec/write,command/exec/resizeoucommand/exec/terminate. - Définissez
streamStdoutStderr: truepour recevoir des notificationscommand/exec/outputDeltapendant l’exécution de la commande.
Lire les exigences d’administration (configRequirements/read)
Utilisez configRequirements/read pour consulter les exigences d’administration en vigueur, chargées depuis requirements.toml, la MDM ou les deux.
{ "method": "configRequirements/read", "id": 52, "params": {} }
{ "id": 52, "result": {
"requirements": {
"allowedApprovalPolicies": ["on-request", "never"],
"allowedSandboxModes": ["read-only", "workspace-write"],
"featureRequirements": {
"unified_exec": false
}
}
} }
result.requirements vaut null si aucune exigence n’est configurée. Lorsque result.supportsIndependentSpeedModes vaut true, les exigences fast_mode et ultrafast_mode s’appliquent indépendamment. Les serveurs plus anciens omettent ce champ et utilisent fast_mode pour les deux modes. Pour connaître les clés et les valeurs prises en charge, consultez la référence de requirements.toml.
Configurer le bac à sable Windows (windowsSandbox/setupStart)
Appelez windowsSandbox/readiness avant de proposer la configuration. MXC et l’ancien bac à sable, s’il est configuré, peuvent tous deux renvoyer ready. Si l’ancien bac à sable renvoie updateRequired, appelez windowsSandbox/setupStart pour lancer la configuration de manière asynchrone. La vérification renvoie notConfigured si le bac à sable Windows est désactivé ou si l’hôte utilise un autre système d’exploitation.
{ "method": "windowsSandbox/setupStart", "id": 53, "params": { "mode": "elevated" } }
{ "id": 53, "result": { "started": true } }
App-server lance la configuration en arrière-plan et émet une notification lorsqu’elle est terminée :
{
"method": "windowsSandbox/setupCompleted",
"params": { "mode": "elevated", "success": true, "error": null }
}
Modes :
elevatedlance la procédure de configuration du bac à sable Windows avec élévation de privilèges.unelevatedlance l’ancienne procédure de configuration et de vérifications préalables.
Système de fichiers
Les API v2 du système de fichiers utilisent des chemins absolus. Utilisez fs/watch si le client doit invalider l’état de son interface après la modification d’un fichier ou d’un répertoire.
{ "method": "fs/watch", "id": 54, "params": {
"watchId": "0195ec6b-1d6f-7c2e-8c7a-56f2c4a8b9d1",
"path": "/Users/me/project/.git/HEAD"
} }
{ "id": 54, "result": { "path": "/Users/me/project/.git/HEAD" } }
{ "method": "fs/changed", "params": {
"watchId": "0195ec6b-1d6f-7c2e-8c7a-56f2c4a8b9d1",
"changedPaths": ["/Users/me/project/.git/HEAD"]
} }
{ "method": "fs/unwatch", "id": 55, "params": {
"watchId": "0195ec6b-1d6f-7c2e-8c7a-56f2c4a8b9d1"
} }
{ "id": 55, "result": {} }
La surveillance d’un fichier émet fs/changed pour son chemin, y compris lorsque la mise à jour résulte d’un remplacement ou d’un renommage.
Événements
Le serveur diffuse des notifications d’événements pour signaler les étapes du cycle de vie des fils, des tours et de leurs éléments. Après avoir démarré ou repris un fil, continuez à lire le flux de transport actif pour recevoir les notifications thread/started, thread/archived, thread/unarchived, thread/closed, thread/status/changed, turn/*, item/* et serverRequest/resolved.
Désactivation de notifications
Les clients peuvent désactiver certaines notifications pour une connexion en envoyant les noms exacts des méthodes dans initialize.params.capabilities.optOutNotificationMethods.
- La correspondance doit être exacte :
item/agentMessage/deltadésactive uniquement cette méthode. - Les noms de méthode inconnus sont ignorés.
- La désactivation s’applique aux notifications v2 actuelles
thread/*,turn/*,item/*et aux notifications associées. - Elle ne s’applique pas aux requêtes, aux réponses ni aux erreurs.
Événements de recherche approximative de fichiers (expérimental)
L’API de session de recherche approximative de fichiers émet des notifications pour chaque recherche :
fuzzyFileSearch/sessionUpdated:{ sessionId, query, files }contient les correspondances actuelles pour la recherche active.fuzzyFileSearch/sessionCompleted:{ sessionId }indique que l’indexation et la recherche des correspondances sont terminées pour cette requête.
Avertissements
configWarning:{ summary, details?, path?, range? }signale un problème de configuration ou d’initialisation dont le serveur peut se remettre.warning:{ threadId?, message }transmet un avertissement d’exécution non bloquant.
Événements de configuration du bac à sable Windows
windowsSandbox/setupCompleted: le serveur émet{ mode, success, error }à la fin d’une requêtewindowsSandbox/setupStart.
Événements de tour
turn/started:{ turn }contient l’identifiant du tour, un tableauitemsvide etstatus: "inProgress".turn/completed:{ turn }contient unturn.statuségal àcompleted,interruptedoufailed. En cas d’échec, la notification contient{ error: { message, codexErrorInfo?, additionalDetails? } }.turn/diff/updated:{ threadId, turnId, diff }contient le dernier diff unifié regroupant toutes les modifications de fichiers du tour.turn/plan/updated:{ turnId, explanation?, plan }est émis chaque fois que l’agent communique ou modifie son plan. Chaque entrée deplana la forme{ step, status }, avec unstatuségal àpending,inProgressoucompleted.hook/startedethook/completed:{ threadId, turnId?, run }est émis au démarrage d’un hook de cycle de vie synchrone, puis lorsque son bilan d’exécution est disponible. Ces notifications ne sont pas émises pour les hooks asynchrones.model/safetyBuffering/updated:{ threadId, turnId, model, useCases, reasons, showBufferingUi, fasterModel }est émis lorsqu’une réponse est temporairement mise en mémoire tampon pour des raisons de sécurité.model/rerouted:{ threadId, turnId, fromModel, toModel, reason }est émis lorsque le service redirige une requête vers un autre modèle.model/verification:{ threadId, turnId, verifications }est émis lorsque le service exige une vérification supplémentaire du compte.thread/tokenUsage/updatedtransmet les mises à jour de consommation du fil actif.
turn/diff/updated et turn/plan/updated contiennent actuellement des tableaux items vides, même si des événements d’élément sont diffusés. Utilisez les notifications item/* comme référence pour les éléments du tour.
Éléments
ThreadItem est le type union discriminé utilisé dans les réponses de tour et les notifications item/*. Les types d’éléments courants sont les suivants :
userMessage:{id, content}, oùcontentest une liste d’entrées utilisateur (text,imageoulocalImage).functionCallOutput:{id, name, namespace, output}représente une sortie d’outil autonome fournie viaturn/start.toolOutput.namespacepeut valoirnull.agentMessage:{id, text, phase?}contient la réponse de l’agent accumulée jusqu’ici. S’il est présent,phaseutilise les valeurs du protocole de l’API Responses (commentary,partial_answer,final_answer). Unpartial_answercontient du texte de réponse stable que peuvent suivre d’autres sorties ou appels d’outils.plan:{id, text}contient le texte du plan proposé en mode plan. L’élémentplanfinal deitem/completedfait foi.reasoning:{id, summary, content}, oùsummarycontient les résumés de raisonnement diffusés en continu etcontent, les blocs de raisonnement bruts.commandExecution:{id, command, cwd, status, commandActions, aggregatedOutput?, exitCode?, durationMs?}.fileChange:{id, changes, status}décrit les modifications proposées.changescontient la liste des entrées{path, kind, diff}.mcpToolCallenregistre les champsid,server,tool,statusetargumentsde l’appel. L’appel contient aussiappContext,mcpAppUi,pluginId,readOnlyHint,result,erroretdurationMs. Chacun de ces champs peut valoirnull. L’ancien champmcpAppResourceUriest facultatif. Pour les applications MCP de confiance,appContextcontientconnectorId. Ses autres champs (linkId,resourceUri,appNameetactionName) peuvent valoirnull. Lorsque le descripteur de l’outil spécifie un URI de ressource et un mode d’affichage (inlineoufullscreen),mcpAppUicontientresourceUrietpreferredModelDisplayMode. Pour les appels enregistrés sans ces métadonnées de présentation, app-server renvoienullpourmcpAppUi.dynamicToolCall:{id, tool, arguments, status, contentItems?, success?, durationMs?}représente un appel d’outil dynamique exécuté par le client.collabToolCall:{id, tool, status, senderThreadId, receiverThreadId?, newThreadId?, prompt?, agentStatus?}.webSearch:{id, query, action?}représente une requête de recherche web émise par l’agent.imageView:{id, path}est émis lorsque l’agent appelle l’outil de visualisation d’images.enteredReviewMode:{id, review}est envoyé au début de la revue.exitedReviewMode:{id, review}est émis à la fin de la revue.contextCompaction:{id}est émis lorsque Codex compacte l’historique de la conversation.
Pour webSearch.action, le type d’action peut être search (query?, queries?), openPage (url?) ou findInPage (url?, pattern?).
App Server considère l’ancienne notification thread/compacted comme obsolète. Utilisez l’élément contextCompaction à la place.
Tous les éléments émettent deux événements de cycle de vie communs :
item/startedémet l’itemcomplet au début d’une nouvelle unité de travail. Sonitem.idcorrespond à l’itemIdutilisé dans les mises à jour incrémentales.item/completedenvoie l’itemfinal à la fin du travail. Cet état fait foi.
Mises à jour incrémentales des éléments
item/agentMessage/deltaajoute le texte reçu en continu au message de l’agent.item/plan/deltadiffuse le texte du plan proposé. L’élémentplanfinal peut différer de la concaténation des fragments.item/reasoning/summaryTextDeltadiffuse des résumés lisibles du raisonnement.summaryIndexaugmente au début de chaque nouvelle section du résumé.item/reasoning/summaryPartAddedmarque la limite entre deux sections du résumé de raisonnement.item/reasoning/textDeltadiffuse le texte brut du raisonnement si le modèle le prend en charge.item/commandExecution/outputDeltadiffuse stdout et stderr pour une commande. Ajoutez les fragments dans l’ordre.item/fileChange/outputDeltaest une notification de compatibilité obsolète pour l’ancienne sortie textuelle deapply_patch. Les versions actuelles d’app-server ne l’émettent plus. Utilisez les élémentsfileChangeetturn/diff/updated.
Erreurs
Lorsqu’app-server refuse de nouvelles tâches pendant un arrêt progressif, il renvoie une erreur JSON-RPC avec le code -32600 et data.reason égal à serverShuttingDown.
La notification error contient un objet error imbriqué avec un champ message et un champ facultatif additionalDetails. Son champ codexErrorInfo peut valoir null. Si willRetry vaut true, le serveur réessaie et le tour reste actif. Un tour qui échoue se termine avec status: "failed". Les valeurs courantes de codexErrorInfo comprennent contextWindowExceeded, usageLimitExceeded, badRequest, unauthorized et sandboxError. En cas d’échec d’une requête en amont, la valeur peut être un objet tel que { "httpConnectionFailed": { "httpStatusCode": 503 } }.
Approbations
Selon les paramètres Codex de l’utilisateur, l’exécution de commandes et la modification de fichiers peuvent nécessiter une approbation. App-server envoie une requête JSON-RPC au client, qui répond en indiquant la décision.
-
Décisions pour l’exécution d’une commande :
accept,acceptForSession,decline,cancelou{ "acceptWithExecpolicyAmendment": { "execpolicy_amendment": ["cmd", "..."] } }. -
Décisions pour la modification d’un fichier :
accept,acceptForSession,decline,cancel. -
Les requêtes contiennent
threadIdetturnId. Utilisez-les pour rattacher l’état de l’interface à la conversation active. -
Le serveur poursuit ou refuse l’opération et clôt l’élément avec
item/completed.
Approbation de l’exécution de commandes
Ordre des messages :
item/startedprésente l’élémentcommandExecutionen attente, aveccommand,cwdet d’autres champs.item/commandExecution/requestApprovalcontientitemId,threadId,turnIdet, éventuellement,reason,command,cwd,commandActions,proposedExecpolicyAmendment,networkApprovalContextetavailableDecisions. Lorsqueinitialize.params.capabilities.experimentalApi = true, la requête peut également contenir le champ expérimentaladditionalPermissionsdécrivant les accès au bac à sable demandés pour cette commande. Tous les chemins du système de fichiers transmis dansadditionalPermissionssont absolus.- Le client répond avec l’une des décisions d’approbation d’exécution de commande indiquées ci-dessus.
serverRequest/resolvedconfirme que la requête en attente a reçu une réponse ou a été retirée.item/completedrenvoie l’élémentcommandExecutionfinal avecstatus: completed | failed | declined.
Si networkApprovalContext est présent, la demande porte spécifiquement sur un accès réseau administré, et non sur l’approbation générale d’une commande shell. Le schéma v2 actuel indique l’hôte cible host et le protocole protocol. Les clients doivent afficher une demande spécifique à l’accès réseau. Ils ne doivent pas supposer que command contient un aperçu de commande shell compréhensible pour l’utilisateur.
Codex regroupe les demandes simultanées d’approbation réseau par destination (host, protocole et port). App-server peut donc envoyer une seule demande qui débloque plusieurs requêtes en attente vers la même destination. Les différents ports d’un même hôte sont traités séparément.
Approbation des modifications de fichiers
Ordre des messages :
item/startedémet un élémentfileChangeavec les modifications proposées danschangesetstatus: "inProgress".item/fileChange/requestApprovalcontientitemId,threadId,turnIdet, éventuellement,reasonetgrantRoot.- Le client répond avec l’une des décisions d’approbation de modification de fichier indiquées ci-dessus.
serverRequest/resolvedconfirme que la requête en attente a reçu une réponse ou a été retirée.item/completedrenvoie l’élémentfileChangefinal avecstatus: completed | failed | declined.
tool/requestUserInput
Lorsque le client répond à item/tool/requestUserInput, app-server émet serverRequest/resolved avec { threadId, requestId }. Si le démarrage, la fin ou l’interruption d’un tour entraîne le retrait de la requête avant que le client réponde, le serveur émet la même notification pour signaler ce retrait.
Les paramètres de la requête contiennent autoResolutionMs, un délai exprimé en millisecondes entières, ou null. Si un délai est spécifié et que l’utilisateur ne répond pas, les clients hôtes peuvent résoudre automatiquement la demande à l’expiration du délai.
Demandes d’autorisations
L’outil intégré request_permissions envoie item/permissions/requestApproval avec threadId, turnId, itemId, environmentId, cwd, un reason facultatif et les autorisations réseau ou de système de fichiers demandées. Répondez avec permissions en incluant uniquement les autorisations accordées. Définissez scope sur "session" pour conserver ces autorisations lors des tours suivants de la même session. Omettez ce champ ou utilisez "turn" pour les limiter au tour. Les autorisations qui n’ont pas été demandées sont ignorées.
Requêtes d’élicitation d’un serveur MCP
Un serveur MCP peut interrompre un tour avec mcpServer/elicitation/request. La requête contient threadId, un turnId facultatif, serverName et l’une des structures suivantes :
mode: "form"oumode: "openai/form", avecmessageetrequestedSchema.mode: "url", avecmessage,urletelicitationId.
Répondez avec action: "accept" et le content demandé, ou avec action: "decline" ou "cancel" et content: null. App-server émet ensuite serverRequest/resolved. Pour recevoir la variante openai/form, activez initialize.params.capabilities.mcpServerOpenaiFormElicitation.
Appels d’outils dynamiques (expérimental)
Le champ dynamicTools de thread/start et l’échange de requêtes et de réponses item/tool/call correspondant relèvent des API expérimentales.
Les noms des outils dynamiques et de leurs espaces de noms doivent respecter les règles de nommage de l’API Responses. Évitez les noms d’espaces réservés aux outils intégrés de Codex.
Lorsqu’un outil dynamique est appelé pendant un tour, les messages s’enchaînent ainsi :
- App-server émet
item/startedavecitem.type = "dynamicToolCall",status = "inProgress", ainsi quetooletarguments. - Le serveur envoie la requête
item/tool/callau client. - Le client répond avec les éléments de contenu renvoyés.
- App-server émet
item/completedavecitem.type = "dynamicToolCall", lestatusfinal et les éventuelles valeurscontentItemsousuccessrenvoyées.
Approbation des appels d’outils MCP (applications)
Les appels d’outils d’application (connecteur) peuvent également nécessiter une approbation. Si un appel a des effets de bord, le serveur peut demander une approbation avec tool/requestUserInput et proposer des options comme Accepter, Refuser et Annuler. Une annotation signalant un outil destructeur déclenche toujours une demande d’approbation, même si d’autres indications de l’outil suggèrent des privilèges moindres. Si l’utilisateur refuse ou annule, l’élément mcpToolCall correspondant se termine par une erreur sans que l’outil soit exécuté.
Skills
Pour appeler un skill, incluez $<skill-name> dans la saisie textuelle de l’utilisateur. Ajoutez un élément d’entrée skill (recommandé) afin que le serveur insère les instructions complètes du skill sans dépendre du modèle pour retrouver le skill à partir de son nom.
{
"method": "turn/start",
"id": 101,
"params": {
"threadId": "thread-1",
"input": [
{
"type": "text",
"text": "$skill-creator Add a new skill for triaging flaky CI."
},
{
"type": "skill",
"name": "skill-creator",
"path": "/Users/me/.codex/skills/skill-creator/SKILL.md"
}
]
}
}
Si vous omettez l’élément skill, le modèle analyse tout de même le marqueur $<skill-name> et tente de localiser le skill, ce qui peut augmenter la latence.
Exemple :
$skill-creator Ajoutez un skill pour trier les échecs intermittents de l’intégration continue et expliquez étape par étape comment l’utiliser.
Utilisez skills/list pour récupérer les skills disponibles (éventuellement pour des répertoires cwds spécifiques, avec forceReload). Vous pouvez aussi inclure perCwdExtraUserRoots pour analyser des chemins absolus supplémentaires avec la portée user pour certaines valeurs de cwd. App-server ignore les entrées dont le cwd ne figure pas dans cwds. skills/list peut réutiliser un résultat en cache pour chaque cwd. Définissez forceReload: true pour actualiser les résultats depuis le disque. Le serveur lit interface et dependencies dans SKILL.json lorsque ces données sont présentes.
{ "method": "skills/list", "id": 25, "params": {
"cwds": ["/Users/me/project", "/Users/me/other-project"],
"forceReload": true,
"perCwdExtraUserRoots": [
{
"cwd": "/Users/me/project",
"extraUserRoots": ["/Users/me/shared-skills"]
}
]
} }
{ "id": 25, "result": {
"data": [{
"cwd": "/Users/me/project",
"skills": [
{
"name": "skill-creator",
"description": "Create or update a Codex skill",
"enabled": true,
"interface": {
"displayName": "Skill Creator",
"shortDescription": "Create or update a Codex skill"
},
"dependencies": {
"tools": [
{
"type": "env_var",
"value": "GITHUB_TOKEN",
"description": "GitHub API token"
},
{
"type": "mcp",
"value": "github",
"transport": "streamable_http",
"url": "https://example.com/mcp"
}
]
}
}
],
"errors": []
}]
} }
Le serveur émet également des notifications skills/changed lorsqu’un fichier local de skill sous surveillance est modifié. Ces notifications indiquent que les résultats précédents peuvent être périmés. Rappelez skills/list avec vos paramètres actuels si nécessaire.
Pour activer ou désactiver un skill à partir de son chemin :
{
"method": "skills/config/write",
"id": 26,
"params": {
"path": "/Users/me/.codex/skills/skill-creator/SKILL.md",
"enabled": false
}
}
Applications (connecteurs)
Utilisez app/installed pour lire le dernier instantané enregistré de l’état d’exécution des applications installées. Chaque résultat contient l’id de l’application, son runtimeName (ou null), son état d’activation effectif enabled et son état callable. Une application peut être appelée uniquement si la configuration effective l’active et si au moins un outil visible par le modèle respecte les politiques de l’application et des outils.
{
"method": "app/installed",
"id": 49,
"params": {
"threadId": "thread-1",
"forceRefresh": false
}
}
{
"id": 49,
"result": {
"apps": [
{
"id": "demo-app",
"runtimeName": "Demo App",
"enabled": true,
"callable": true
}
]
}
}
Omettez threadId pour utiliser la configuration globale à la place de celle d’un fil chargé. Définissez forceRefresh: true pour actualiser l’instantané d’exécution des connecteurs avant de le lire. Si la politique globale ou celle de l’espace de travail bloque l’accès aux applications, une application détectée peut tout de même apparaître avec enabled et callable à false.
Utilisez app/list pour récupérer les applications disponibles. Dans la CLI ou l’interface de terminal, /apps ouvre le sélecteur destiné à l’utilisateur. Dans un client personnalisé, appelez directement app/list. Chaque entrée contient isAccessible (application accessible à l’utilisateur) et isEnabled (application activée dans config.toml). Les clients peuvent ainsi distinguer l’installation et l’accès de l’activation locale. Les entrées peuvent également contenir les champs facultatifs branding, appMetadata et labels.
{ "method": "app/list", "id": 50, "params": {
"cursor": null,
"limit": 50,
"threadId": "thread-1",
"forceRefetch": false
} }
{ "id": 50, "result": {
"data": [
{
"id": "demo-app",
"name": "Demo App",
"description": "Example connector for documentation.",
"logoUrl": "https://example.com/demo-app.png",
"logoUrlDark": null,
"distributionChannel": null,
"branding": null,
"appMetadata": null,
"labels": null,
"installUrl": "https://chatgpt.com/apps/demo-app/demo-app",
"isAccessible": true,
"isEnabled": true
}
],
"nextCursor": null
} }
Si vous fournissez threadId, l’activation de la fonctionnalité d’applications (features.apps) dépend de l’instantané de configuration de ce fil. Si vous l’omettez, app-server utilise la configuration globale la plus récente.
app/list renvoie sa réponse une fois chargées les applications accessibles et celles du répertoire. Définissez forceRefetch: true pour ignorer les caches et récupérer des données à jour. Les entrées du cache sont remplacées uniquement si l’actualisation réussit.
Le serveur émet également des notifications app/list/updated chaque fois que le chargement de l’une des sources (applications accessibles ou applications du répertoire) se termine. Chaque notification contient la dernière liste fusionnée des applications.
{
"method": "app/list/updated",
"params": {
"data": [
{
"id": "demo-app",
"name": "Demo App",
"description": "Example connector for documentation.",
"logoUrl": "https://example.com/demo-app.png",
"logoUrlDark": null,
"distributionChannel": null,
"branding": null,
"appMetadata": null,
"labels": null,
"installUrl": "https://chatgpt.com/apps/demo-app/demo-app",
"isAccessible": true,
"isEnabled": true
}
]
}
}
Utilisez app/read si vous connaissez déjà les identifiants des applications et avez besoin de leurs métadonnées plutôt que de leur état d’exécution après installation. Passez au maximum 100 identifiants dans appIds. Le serveur conserve uniquement la première occurrence de chaque identifiant et respecte cet ordre dans apps et missingAppIds. Les applications inconnues ou inaccessibles figurent dans missingAppIds sans faire échouer toute la requête.
{
"method": "app/read",
"id": 52,
"params": {
"appIds": ["demo-app", "missing-app"],
"includeTools": true
}
}
{
"id": 52,
"result": {
"apps": [
{
"id": "demo-app",
"name": "Demo App",
"description": "Example connector for documentation.",
"iconUrl": null,
"iconUrlDark": null,
"distributionChannel": null,
"installUrl": null,
"pluginDisplayNames": [],
"toolSummaries": [
{
"name": "search",
"title": "Search",
"description": "Search the app.",
"isEnabled": true,
"disabledReason": null,
"isReadOnly": true
}
]
}
],
"missingAppIds": ["missing-app"]
}
}
Définissez includeTools: true pour demander des résumés publics d’outils destinés uniquement à l’affichage. La réponse de métadonnées ne contient pas l’état d’exécution des applications installées et n’autorise aucun appel d’outil. Utilisez app/installed pour vérifier les valeurs effectives de enabled et callable.
Pour appeler une application, insérez $<app-slug> dans la saisie textuelle et ajoutez un élément d’entrée mention avec le chemin app://<id> (recommandé).
{
"method": "turn/start",
"id": 51,
"params": {
"threadId": "thread-1",
"input": [
{
"type": "text",
"text": "$demo-app Pull the latest updates from the team."
},
{
"type": "mention",
"name": "Demo App",
"path": "app://demo-app"
}
]
}
}
Exemples d’appels RPC pour configurer les applications
Utilisez config/read, config/value/write et config/batchWrite pour consulter ou modifier les paramètres des applications dans config.toml.
Lisez la structure de la configuration effective des applications (y compris _default et les paramètres propres à chaque outil) :
{ "method": "config/read", "id": 60, "params": { "includeLayers": false } }
{ "id": 60, "result": {
"config": {
"apps": {
"_default": {
"enabled": true,
"destructive_enabled": true,
"open_world_enabled": true,
"approvals_reviewer": "user",
"default_tools_approval_mode": "auto"
},
"google_drive": {
"enabled": true,
"destructive_enabled": false,
"approvals_reviewer": "auto_review",
"default_tools_approval_mode": "prompt",
"tools": {
"files/delete": { "enabled": false, "approval_mode": "approve" }
}
}
}
}
} }
apps._default.approvals_reviewer détermine qui examine les demandes d’approbation pour toutes les applications, sauf si une valeur spécifique à l’application est définie. Si les deux valeurs sont omises, l’application hérite du paramètre de premier niveau approvals_reviewer. apps._default.default_tools_approval_mode définit le mode d’approbation par défaut des outils pour lesquels aucun paramètre propre à l’application ou à l’outil n’est défini. Les exigences administrées relatives au mode d’approbation priment sur les paramètres d’approbation des outils.
Modifiez un paramètre d’application :
{
"method": "config/value/write",
"id": 61,
"params": {
"keyPath": "apps.google_drive.default_tools_approval_mode",
"value": "prompt",
"mergeStrategy": "replace"
}
}
Appliquez plusieurs modifications de façon atomique :
{
"method": "config/batchWrite",
"id": 62,
"params": {
"edits": [
{
"keyPath": "apps._default.destructive_enabled",
"value": false,
"mergeStrategy": "upsert"
},
{
"keyPath": "apps.google_drive.tools.files/delete.approval_mode",
"value": "approve",
"mergeStrategy": "upsert"
}
]
}
}
Détecter et importer la configuration d’un agent externe
Utilisez externalAgentConfig/detect pour découvrir les éléments d’agents externes pouvant être migrés, puis passez les entrées sélectionnées à externalAgentConfig/import.
Exemple de détection :
{ "method": "externalAgentConfig/detect", "id": 63, "params": {
"includeHome": true,
"cwds": ["/Users/me/project"]
} }
{ "id": 63, "result": {
"items": [
{
"itemType": "AGENTS_MD",
"description": "Import /Users/me/project/CLAUDE.md to /Users/me/project/AGENTS.md.",
"cwd": "/Users/me/project"
},
{
"itemType": "SKILLS",
"description": "Copy skill folders from /Users/me/.claude/skills to /Users/me/.agents/skills.",
"cwd": null
}
]
} }
Exemple d’import :
{ "method": "externalAgentConfig/import", "id": 64, "params": {
"migrationItems": [
{
"itemType": "AGENTS_MD",
"description": "Import /Users/me/project/CLAUDE.md to /Users/me/project/AGENTS.md.",
"cwd": "/Users/me/project"
}
],
"source": "claude-code"
} }
{ "id": 64, "result": { "importId": "8ae96ff3-3425-4f4c-8772-b6fd61502868" } }
Le paramètre d’import facultatif de premier niveau source indique le produit à l’origine des éléments sélectionnés pour la migration.
Le serveur émet externalAgentConfig/import/progress à la fin du traitement de chaque type d’élément, puis externalAgentConfig/import/completed lorsque tous les imports synchrones et en arrière-plan sont terminés. Ces notifications contiennent le même importId que la réponse, ainsi que itemTypeResults avec les successes et les failures par type. La notification de fin peut arriver immédiatement après la réponse ou après la fin des imports distants en arrière-plan.
{ "method": "externalAgentConfig/import/progress", "params": {
"importId": "8ae96ff3-3425-4f4c-8772-b6fd61502868",
"itemTypeResults": [
{
"itemType": "AGENTS_MD",
"successes": [
{ "itemType": "AGENTS_MD", "cwd": "/Users/me/project", "source": null, "target": "/Users/me/project/AGENTS.md" }
],
"failures": []
}
]
} }
{ "method": "externalAgentConfig/import/completed", "params": {
"importId": "8ae96ff3-3425-4f4c-8772-b6fd61502868",
"itemTypeResults": [
{
"itemType": "AGENTS_MD",
"successes": [
{ "itemType": "AGENTS_MD", "cwd": "/Users/me/project", "source": null, "target": "/Users/me/project/AGENTS.md" }
],
"failures": []
}
]
} }
Consultez les imports précédents terminés :
{ "method": "externalAgentConfig/import/readHistories", "id": 65 }
{ "id": 65, "result": { "data": [
{
"importId": "8ae96ff3-3425-4f4c-8772-b6fd61502868",
"completedAtMs": 1781784000000,
"successes": [
{ "itemType": "AGENTS_MD", "cwd": "/Users/me/project", "source": null, "target": "/Users/me/project/AGENTS.md" }
],
"failures": []
}
] } }
Les valeurs de itemType prises en charge sont AGENTS_MD, CONFIG, SKILLS, PLUGINS, MCP_SERVER_CONFIG, SUBAGENTS, HOOKS, COMMANDS et SESSIONS. Pour les éléments PLUGINS, details.plugins liste chaque marketplaceName et les pluginNames que Codex peut tenter de migrer. La détection renvoie uniquement les éléments pour lesquels une opération reste à effectuer. Par exemple, Codex ignore la migration AGENTS si AGENTS.md existe déjà et n’est pas vide, et l’import de skills n’écrase pas les répertoires de skills existants.
Lorsqu’il détecte des plugins dans .claude/settings.json, Codex lit les sources de marketplace configurées dans extraKnownMarketplaces. Si enabledPlugins contient des plugins de claude-plugins-official mais que la source de la marketplace est absente, Codex utilise anthropics/claude-plugins-official comme source déduite.
Points de terminaison d’authentification
Si vous avez créé une application locale ou open source utilisant l’authentification de Codex app-server, vous pouvez continuer à l’utiliser. Nous vous recommandons toutefois de migrer vers la connexion avec ChatGPT pour permettre aux utilisateurs de mieux suivre et contrôler leur utilisation. Consultez la documentation développeur sur la connexion avec ChatGPT et notre guide de mise en œuvre. L’authentification d’app-server n’a jamais été autorisée pour les services commerciaux ou hébergés. Nous avons lancé la connexion avec ChatGPT pour prendre en charge ces cas d’usage et nous avons hâte de découvrir vos réalisations. Inscrivez-vous sur notre liste d’attente des partenaires.
L’API JSON-RPC d’authentification et de gestion des comptes propose des méthodes de requête-réponse et des notifications émises par le serveur (sans id). Utilisez-les pour vérifier l’état d’authentification, démarrer ou annuler une connexion, vous déconnecter, consulter les limites de débit de ChatGPT et avertir les propriétaires d’espaces de travail lorsque les crédits sont épuisés ou qu’une limite d’utilisation est atteinte.
Modes d’authentification
Codex prend en charge les modes d’authentification suivants. account/updated.authMode indique le mode actif et la notification contient également le planType ChatGPT actuel s’il est disponible. account/read fournit aussi des informations sur le compte et l’offre.
- Clé API (
apikey) : l’appelant fournit une clé API OpenAI avectype: "apiKey". Codex l’enregistre pour les requêtes API. - Authentification ChatGPT gérée (
chatgpt) : Codex gère le flux OAuth de ChatGPT, enregistre les jetons et les renouvelle automatiquement. Démarrez avectype: "chatgpt"pour la connexion via le navigateur outype: "chatgptDeviceCode"pour la connexion par code d’appareil. - Jetons ChatGPT externes (
chatgptAuthTokens) : ce mode expérimental est destiné aux applications hôtes qui gèrent déjà le cycle d’authentification ChatGPT de l’utilisateur. L’application hôte fournit directementaccessToken,chatgptAccountIdet, éventuellement,chatgptPlanType. Elle doit renouveler le jeton sur demande. - Amazon Bedrock :
account/readidentifie les comptes Bedrock partype: "amazonBedrock"et indique si les identifiants proviennent d’une clé API Bedrock gérée par Codex (credentialSource: "codexManaged") ou de la chaîne externe de fournisseurs d’identifiants AWS (credentialSource: "awsManaged").account/updated.authModeutilisebedrockApiKeypour les clés API Bedrock gérées par Codex.
Vue d’ensemble de l’API
account/readrécupère les informations du compte actuel et peut renouveler les jetons.account/login/startlance une connexion (apiKey,chatgpt,chatgptDeviceCodeou, à titre expérimental,chatgptAuthTokens).account/login/completed(notification) signale la fin d’une tentative de connexion, qu’elle réussisse ou échoue.account/login/cancelannule une connexion ChatGPT gérée en attente à partir de sonloginId.account/logoutdéconnecte le compte et déclencheaccount/updated.account/updated(notification) signale tout changement de mode d’authentification (authMode:apikey,chatgpt,chatgptAuthTokens,agentIdentity,personalAccessToken,bedrockApiKeyounull) et contientplanTypes’il est disponible.account/chatgptAuthTokens/refresh(requête du serveur) demande le renouvellement des jetons ChatGPT gérés en externe après une erreur d’autorisation.account/rateLimits/readrécupère les limites de débit de ChatGPT.account/rateLimits/updated(notification) signale tout changement des limites de débit ChatGPT d’un utilisateur.account/sendAddCreditsNudgeEmaildemande à ChatGPT d’avertir par e-mail un propriétaire de l’espace de travail lorsque les crédits sont épuisés ou qu’une limite d’utilisation est atteinte.account/rateLimitResetCredit/consumeutilise une réinitialisation de limite de débit acquise, avec une valeuridempotencyKeyfournie par l’appelant.account/usage/readrécupère les statistiques de consommation de tokens du compte ChatGPT et les totaux quotidiens.account/workspaceMessages/readrécupère les messages actifs de l’espace de travail, y compris les titres des notifications lorsqu’ils sont disponibles.mcpServer/oauthLogin/completed(notification) signale la fin d’une procéduremcpServer/oauth/loginet contient{ name, threadId, loginId?, success, error? }. Les serveurs plus anciens omettentloginId.threadIdpeut valoirnullpour les procédures OAuth propres à une application ou à un plugin.mcpServer/startupStatus/updated(notification) signale un changement de l’état de démarrage d’un serveur MCP configuré et contient{ threadId, name, status, error, failureReason }.threadIdvautnullpour un démarrage à l’échelle de l’application. En cas d’échec du démarrage,failureReason: "reauthenticationRequired"signifie que les identifiants OAuth enregistrés ont expiré et n’ont pas pu être renouvelés. Le client doit alors proposer de reconnecter le serveur.
1) Vérifier l’état d’authentification
Requête :
{ "method": "account/read", "id": 1, "params": { "refreshToken": false } }
Exemples de réponses :
{ "id": 1, "result": { "account": null, "requiresOpenaiAuth": false } }
{ "id": 1, "result": { "account": null, "requiresOpenaiAuth": true } }
{
"id": 1,
"result": { "account": { "type": "apiKey" }, "requiresOpenaiAuth": true }
}
{
"id": 1,
"result": {
"account": {
"type": "amazonBedrock",
"credentialSource": "codexManaged"
},
"requiresOpenaiAuth": false
}
}
{
"id": 1,
"result": {
"account": {
"type": "amazonBedrock",
"credentialSource": "awsManaged"
},
"requiresOpenaiAuth": false
}
}
{
"id": 1,
"result": {
"account": {
"type": "chatgpt",
"email": "user@example.com",
"planType": "pro"
},
"requiresOpenaiAuth": true
}
}
Précisions sur les champs :
refreshToken(booléen) : définissez-le surtruepour forcer le renouvellement du jeton en mode ChatGPT géré. En mode jetons externes (chatgptAuthTokens), app-server ignore cette option.emailvautnullsi le compte ChatGPT n’a pas d’adresse e-mail.requiresOpenaiAuthdépend du fournisseur actif. Lorsque sa valeur estfalse, Codex peut fonctionner sans identifiants OpenAI.- Amazon Bedrock indique
credentialSource: "codexManaged"lorsqu’il utilise une clé API Bedrock gérée par Codex. Il indiquecredentialSource: "awsManaged"pour les identifiants AWS externes. Cette valeur identifie la source sélectionnée sans vérifier que la chaîne de fournisseurs d’identifiants AWS peut effectivement fournir des identifiants.
2) Se connecter avec une clé API
-
Envoyez la requête suivante :
{ "method": "account/login/start", "id": 2, "params": { "type": "apiKey", "apiKey": "sk-..." } } -
Attendez la réponse suivante :
{ "id": 2, "result": { "type": "apiKey" } } -
Notifications :
{ "method": "account/login/completed", "params": { "loginId": null, "success": true, "error": null } }{ "method": "account/updated", "params": { "authMode": "apikey", "planType": null } }
3) Se connecter avec ChatGPT via le navigateur
-
Démarrez la connexion :
{ "method": "account/login/start", "id": 3, "params": { "type": "chatgpt", "useHostedLoginSuccessPage": true, "appBrand": "chatgpt" } }Par défaut, lorsque le rappel du navigateur réussit, il redirige l’utilisateur vers une page locale de confirmation. Définissez
useHostedLoginSuccessPage: truepour utiliser la page de confirmation hébergée si aucune configuration de l’organisation n’est nécessaire. Si cette page hébergée est activée,appBrandpeut valoir"codex"ou"chatgpt". Une valeur omise ou égale ànullest remplacée par"codex".{ "id": 3, "result": { "type": "chatgpt", "loginId": "<uuid>", "authUrl": "https://chatgpt.com/...&redirect_uri=http%3A%2F%2Flocalhost%3A<port>%2Fauth%2Fcallback" } } -
Ouvrez
authUrldans un navigateur. App-server héberge le point de rappel local. -
Attendez les notifications suivantes :
{ "method": "account/login/completed", "params": { "loginId": "<uuid>", "success": true, "error": null } }{ "method": "account/updated", "params": { "authMode": "chatgpt", "planType": "plus" } }
3b) Se connecter avec ChatGPT par code d’appareil
Utilisez cette procédure si votre client gère le parcours de connexion ou si le rappel du navigateur manque de fiabilité.
-
Démarrez la connexion :
{ "method": "account/login/start", "id": 4, "params": { "type": "chatgptDeviceCode" } }{ "id": 4, "result": { "type": "chatgptDeviceCode", "loginId": "<uuid>", "verificationUrl": "https://auth.openai.com/codex/device", "userCode": "ABCD-1234" } } -
Affichez
verificationUrletuserCodeà l’utilisateur. L’interface cliente gère cette étape. -
Attendez les notifications suivantes :
{ "method": "account/login/completed", "params": { "loginId": "<uuid>", "success": true, "error": null } }{ "method": "account/updated", "params": { "authMode": "chatgpt", "planType": "plus" } }
3c) Se connecter avec des jetons ChatGPT gérés en externe (chatgptAuthTokens)
Utilisez ce mode expérimental uniquement si une application hôte gère le cycle d’authentification ChatGPT de l’utilisateur et fournit directement les jetons. Les clients doivent définir capabilities.experimentalApi = true lors de initialize avant d’utiliser ce type de connexion.
-
Envoyez la requête suivante :
{ "method": "account/login/start", "id": 7, "params": { "type": "chatgptAuthTokens", "accessToken": "<jwt>", "chatgptAccountId": "org-123", "chatgptPlanType": "business" } } -
Attendez la réponse suivante :
{ "id": 7, "result": { "type": "chatgptAuthTokens" } } -
Notifications :
{ "method": "account/login/completed", "params": { "loginId": null, "success": true, "error": null } }{ "method": "account/updated", "params": { "authMode": "chatgptAuthTokens", "planType": "business" } }
Lorsque le serveur reçoit 401 Unauthorized, il peut demander à l’application hôte de renouveler les jetons :
{
"method": "account/chatgptAuthTokens/refresh",
"id": 8,
"params": { "reason": "unauthorized", "previousAccountId": "org-123" }
}
{ "id": 8, "result": { "accessToken": "<jwt>", "chatgptAccountId": "org-123", "chatgptPlanType": "business" } }
Si le renouvellement réussit, le serveur retente la requête initiale. Le délai d’expiration des requêtes est d’environ 10 secondes.
4) Annuler une connexion ChatGPT
{ "method": "account/login/cancel", "id": 4, "params": { "loginId": "<uuid>" } }
{ "method": "account/login/completed", "params": { "loginId": "<uuid>", "success": false, "error": "..." } }
5) Se déconnecter
{ "method": "account/logout", "id": 5 }
{ "id": 5, "result": {} }
{ "method": "account/updated", "params": { "authMode": null, "planType": null } }
6) Limites de débit (ChatGPT)
{ "method": "account/rateLimits/read", "id": 6 }
{ "id": 6, "result": {
"rateLimits": {
"limitId": "codex",
"limitName": null,
"primary": { "usedPercent": 25, "windowDurationMins": 15, "resetsAt": 1730947200 },
"secondary": null,
"rateLimitReachedType": null
},
"rateLimitsByLimitId": {
"codex": {
"limitId": "codex",
"limitName": null,
"primary": { "usedPercent": 25, "windowDurationMins": 15, "resetsAt": 1730947200 },
"secondary": null,
"rateLimitReachedType": null
},
"codex_other": {
"limitId": "codex_other",
"limitName": "codex_other",
"primary": { "usedPercent": 42, "windowDurationMins": 60, "resetsAt": 1730950800 },
"secondary": null,
"rateLimitReachedType": null
}
},
"rateLimitResetCredits": {
"availableCount": 2,
"credits": [{
"id": "RateLimitResetCredit_1",
"resetType": "codexRateLimits",
"status": "available",
"grantedAt": 1781654400,
"expiresAt": 1784246400,
"title": "Rate-limit reset",
"description": "Reset an eligible Codex rate-limit window."
}]
}
} }
{ "method": "account/rateLimits/updated", "params": {
"rateLimits": {
"limitId": "codex",
"primary": { "usedPercent": 31, "windowDurationMins": 15, "resetsAt": 1730948100 }
}
} }
Précisions sur les champs :
rateLimitsfournit une vue rétrocompatible d’un seul quota.rateLimitsByLimitId, s’il est présent, fournit une vue de plusieurs quotas indexés par leurlimit_idde comptabilisation (par exemplecodex).limitIdidentifie le quota dont l’utilisation est comptabilisée.limitNameest le libellé facultatif du quota destiné à l’utilisateur.usedPercentindique le pourcentage consommé pendant la période du quota en cours.windowDurationMinsindique la durée de la période du quota.resetsAtest l’horodatage Unix, en secondes, de la prochaine réinitialisation.planTypeest présent lorsque le serveur renvoie l’offre ChatGPT associée à un quota.creditsest présent lorsque le serveur renvoie le détail des crédits restants de l’espace de travail.rateLimitReachedTypeindique comment le serveur classe la limite atteinte.rateLimitResetCreditscontient le nombre de réinitialisations acquises encore disponibles lorsque le service le fournit. Sinon, il vautnull.rateLimitResetCredits.creditsvautnullsi seul le nombre de crédits est connu. Un tableau vide signifie que le service a récupéré les détails et n’a trouvé aucun crédit disponible. Le service peut limiter le nombre d’entrées détaillées renvoyées :availableCountfait foi.- Chaque entrée détaillée contient un
idopaque,resetType,status,grantedAt,expiresAt(qui peut valoirnull),title(qui peut valoirnull) etdescription(qui peut valoirnull). - Appelez
account/rateLimits/readaprès avoir utilisé une réinitialisation.
7) Consommation de tokens (ChatGPT)
Utilisez account/usage/read pour récupérer les statistiques de consommation de tokens de ChatGPT et, s’ils sont disponibles, les totaux quotidiens.
{ "method": "account/usage/read", "id": 7 }
{ "id": 7, "result": {
"summary": {
"lifetimeTokens": 1234567,
"peakDailyTokens": 45678,
"longestRunningTurnSec": 540,
"currentStreakDays": 8,
"longestStreakDays": 14
},
"dailyUsageBuckets": [
{ "startDate": "2026-06-18", "tokens": 12345 }
]
} }
Précisions sur les champs :
- Les valeurs de
summarypeuvent êtrenullsi le service n’a pas renvoyé la métrique correspondante. dailyUsageBucketspeut valoirnull. Lorsqu’il est renseigné, chaque entrée contientstartDateettokens.- Le point de terminaison nécessite une authentification reposant sur les services Codex. Il accepte l’authentification ChatGPT, les jetons ChatGPT externes, l’identité d’agent et les jetons d’accès personnels. L’authentification par clé API seule et l’authentification Bedrock ne sont pas prises en charge.
8) Réinitialisations de limite de débit acquises (ChatGPT)
Appelez account/rateLimitResetCredit/consume pour utiliser une réinitialisation acquise.
{ "method": "account/rateLimitResetCredit/consume", "id": 8, "params": { "idempotencyKey": "8ae96ff3-3425-4f4c-8772-b6fd61502868", "creditId": "RateLimitResetCredit_1" } }
{ "id": 8, "result": { "outcome": "reset" } }
Précisions sur les champs :
idempotencyKeydoit être non vide. Utilisez un UUID distinct pour chaque opération de réinitialisation et réutilisez cette valeur si vous retentez la même opération.creditIdest facultatif. Si vous le fournissez, utilisez un identifiant opaque non vide issu deaccount/rateLimits/read. Si vous l’omettez, le service sélectionne le prochain crédit disponible.resetsignifie qu’un crédit a été utilisé.alreadyRedeemedsignifie que la même opération a déjà abouti. Traitez cette réponse comme une réussite idempotente et actualisez les limites du compte.nothingToResetsignifie qu’aucune période de limite de débit ne peut être réinitialisée.noCreditsignifie que le compte ne dispose d’aucun crédit de réinitialisation acquis.- Appelez
account/rateLimits/readaprès avoir utilisé une réinitialisation pour obtenir les périodes à jour, sans les déduire de cette réponse.
9) Avertir un propriétaire de l’espace de travail qu’une limite est atteinte
Utilisez account/sendAddCreditsNudgeEmail pour demander à ChatGPT d’avertir par e-mail un propriétaire de l’espace de travail lorsque les crédits sont épuisés ou qu’une limite d’utilisation est atteinte.
{ "method": "account/sendAddCreditsNudgeEmail", "id": 9, "params": { "creditType": "credits" } }
{ "id": 9, "result": { "status": "sent" } }
Utilisez creditType: "credits" lorsque les crédits de l’espace de travail sont épuisés ou creditType: "usage_limit" lorsque sa limite d’utilisation est atteinte. Si le propriétaire a déjà été averti récemment, la réponse contient le statut cooldown_active.
10) Messages de l’espace de travail (ChatGPT)
Utilisez account/workspaceMessages/read pour récupérer les messages actifs de l’espace de travail actuel, y compris les titres des notifications lorsqu’ils sont disponibles.
{ "method": "account/workspaceMessages/read", "id": 10 }
{ "id": 10, "result": { "featureEnabled": true, "messages": [
{ "messageId": "msg_123", "messageType": "headline", "messageBody": "Workspace maintenance starts at 5pm.", "createdAt": 1781395200, "archivedAt": null }
] } }