For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
Navigation principale
Theme

Codex App Server

Intégrez Codex à votre produit avec le protocole app-server

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 /readyz renvoie 200 OK dès que le serveur accepte de nouvelles connexions.
  • GET /healthz renvoie 200 OK si la requête ne contient pas d’en-tête Origin.
  • Le serveur rejette les requêtes contenant un en-tête Origin avec le statut 403 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

  1. 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) ou codex app-server --listen unix:// (socket Unix par défaut).
  2. Connectez un client via le transport sélectionné, puis envoyez initialize suivi de la notification initialized.
  3. 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 initialize avec les métadonnées du client, puis émettez initialized. Avant cet échange, le serveur rejette toute autre requête sur cette connexion.
  • Démarrez ou reprenez un fil : appelez thread/start pour créer une conversation, thread/resume pour en poursuivre une ou thread/fork pour copier l’historique dans un nouveau fil doté de son propre identifiant.
  • Démarrez un tour : appelez turn/start avec le threadId cible 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/steer pour 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/completed avec le statut final lorsque le modèle a terminé ou après une annulation via turn/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ête attestation/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 de mcpServer/elicitation/request qui 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éfinissez experimentalApi sur false) pour utiliser uniquement l’API stable. Le serveur rejettera alors les méthodes et champs expérimentaux.
  • Définissez capabilities.experimentalApi sur true pour 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/start crée un fil, émet thread/started et abonne automatiquement le client aux événements des tours et des éléments de ce fil.
  • thread/resume rouvre un fil existant à partir de son identifiant afin que les appels ultérieurs à turn/start y ajoutent des tours.
  • thread/fork permet de forker un fil sous un nouvel identifiant en copiant son historique enregistré. Passez lastTurnId pour copier l’historique jusqu’à ce tour inclus et exclure les tours suivants, ou ephemeral: true pour créer un fork en mémoire. La méthode émet thread/started pour le nouveau fil. Les fils renvoyés contiennent forkedFromId si cette valeur est disponible.
  • thread/read lit les métadonnées enregistrées d’un fil à partir de son identifiant sans le reprendre. Utilisez thread/turns/list et thread/items/list pour charger l’historique. Les objets thread renvoyés contiennent le statut d’exécution status.
  • thread/list parcourt 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/list parcourt l’historique des tours d’un fil enregistré sans le reprendre. itemsView détermine si les éléments des tours sont omis, résumés ou chargés intégralement.
  • thread/items/list parcourt les éléments enregistrés d’un fil, avec la possibilité de limiter les résultats à un seul turnId. Le système de stockage actif doit prendre en charge la pagination des éléments.
  • thread/loaded/list liste les identifiants des fils actuellement chargés en mémoire.
  • thread/name/set définit ou modifie le nom affiché à l’utilisateur pour un fil chargé ou un journal de session enregistré, puis émet thread/name/updated.
  • thread/goal/set définit l’objectif d’un fil et émet thread/goal/updated.
  • thread/goal/get lit l’objectif actuel d’un fil.
  • thread/goal/clear efface l’objectif d’un fil et émet thread/goal/cleared.
  • thread/metadata/update met à jour les métadonnées Git enregistrées pour un fil.
  • thread/archive dé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 émet thread/archived pour chaque fil archivé.
  • thread/delete supprime définitivement un fil enregistré, actif ou archivé, ainsi que tous ses descendants. La méthode renvoie {} en cas de réussite et émet thread/deleted pour chaque fil supprimé.
  • thread/unsubscribe dé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 émet thread/closed.
  • thread/unarchive restaure le journal d’un fil archivé dans le répertoire des sessions actives, renvoie le thread restauré et émet thread/unarchived.
  • thread/status/changed est une notification émise lorsque le status d’exécution d’un fil chargé change.
  • thread/compact/start déclenche le compactage de l’historique d’un fil et renvoie immédiatement {}. Les notifications turn/* et item/* indiquent la progression.
  • thread/shellCommand exé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/clean arrête tous les terminaux en arrière-plan en cours d’exécution pour un fil (expérimental, nécessite capabilities.experimentalApi).
  • thread/backgroundTerminals/list liste les terminaux en arrière-plan en cours d’exécution pour un fil chargé (expérimental, nécessite capabilities.experimentalApi).
  • thread/backgroundTerminals/terminate arrête un terminal en arrière-plan à partir de son processId app-server (expérimental, nécessite capabilities.experimentalApi).
  • thread/revert supprime 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 émet thread/reverted.
  • turn/start ajoute une saisie utilisateur ou la sortie autonome d’un outil à un fil et lance la génération par Codex. La méthode renvoie le turn initial et diffuse les événements. Pour collaborationMode, settings.developer_instructions: null signifie « utiliser les instructions intégrées du mode sélectionné ».
  • thread/inject_items ajoute 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/steer ajoute une saisie utilisateur au tour en cours d’un fil et renvoie le turnId accepté.
  • turn/interrupt demande l’annulation d’un tour en cours. En cas de réussite, la méthode renvoie {} et le tour se termine avec status: "interrupted".
  • review/start lance la revue de code du fil par Codex et émet des éléments enteredReviewMode et exitedReviewMode.
  • command/exec exécute une commande dans le bac à sable du serveur sans démarrer de fil ni de tour.
  • command/exec/write écrit des octets sur stdin dans une session command/exec en cours ou ferme stdin.
  • command/exec/resize redimensionne le pseudo-terminal d’une session command/exec en cours.
  • command/exec/terminate arrête une session command/exec en cours.
  • command/exec/outputDelta (notification) transmet les fragments de stdout et stderr encodés en base64 d’une session command/exec dont la sortie est diffusée en continu.
  • process/spawn démarre explicitement une session de processus hors du bac à sable de Codex (expérimental, nécessite capabilities.experimentalApi).
  • process/writeStdin écrit des octets sur stdin dans une session process/spawn en cours ou ferme stdin (expérimental).
  • process/resizePty redimensionne le pseudo-terminal d’une session de processus en cours (expérimental).
  • process/kill arrête une session de processus en cours (expérimental).
  • process/outputDelta et process/exited (notifications) transmettent respectivement la sortie du processus en continu et son statut de sortie (expérimental).
  • model/list liste les modèles disponibles (définissez includeHidden: true pour inclure les entrées avec hidden: true), leurs niveaux d’effort, le champ facultatif upgrade et inputModalities.
  • modelProvider/capabilities/read lit les limites des capacités du fournisseur pour chaque combinaison de modèle et de fournisseur.
  • experimentalFeature/list liste les indicateurs de fonctionnalité avec leur stade de développement et une pagination par curseur.
  • experimentalFeature/enablement/set modifie les paramètres d’exécution en mémoire pour les clés de fonctionnalité prises en charge, comme apps et plugins.
  • 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/list liste les profils d’autorisations bêta avec pagination par curseur et indique si les exigences en vigueur permettent d’utiliser chaque profil.
  • collaborationMode/list liste les modes de collaboration prédéfinis (expérimental, sans pagination).
  • skills/list liste les skills pour une ou plusieurs valeurs de cwd (prend en charge forceReload et le paramètre facultatif perCwdExtraUserRoots).
  • skills/extraRoots/set remplace, 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/list liste les hooks de cycle de vie détectés pour une ou plusieurs valeurs de cwd.
  • marketplace/add ajoute une marketplace de plugins distante et l’enregistre dans la configuration des marketplaces de l’utilisateur.
  • marketplace/remove supprime une marketplace configurée et son répertoire racine installé, s’il existe.
  • marketplace/upgrade actualise 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 la version distante, la version locale localVersion, des icônes structurées pour les thèmes clair et sombre, ainsi que installPolicySource, qui peut valoir null, WORKSPACE_SETTING ou IMPLICIT_CANONICAL_APP pour 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 le shareUrl du 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/read lit à 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/installed lit 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/list liste les applications (connecteurs) disponibles avec pagination et indique si elles sont accessibles et activées.
  • app/read ré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/write active ou désactive des skills à partir de leur chemin.
  • mcpServer/oauth/login lance la connexion OAuth à un serveur MCP configuré. Ouvrez l’URL HTTP ou HTTPS renvoyée dans authorizationUrl, puis utilisez loginId pour identifier la notification mcpServer/oauthLogin/completed correspondante.
  • tool/requestUserInput pose une à trois questions courtes à l’utilisateur pour un appel d’outil (expérimental). Une question peut définir isOther pour 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/reload recharge la configuration des serveurs MCP depuis le disque et programme son actualisation pour les fils chargés.
  • mcpServerStatus/list liste les serveurs MCP, leurs outils, leurs ressources et leur état d’authentification (pagination par curseur avec limite). Utilisez detail: "full" pour obtenir toutes les données ou detail: "toolsAndAuthOnly" pour omettre les ressources. Dans les deux modes, la réponse contient les capacités annoncées par le serveur dans serverCapabilities, ou null tant que l’initialisation n’a pas réussi. Passez serverName pour interroger un seul serveur. Avec threadId, la requête réutilise la connexion MCP du fil.
  • mcpServer/resource/read lit une ressource MCP via un serveur MCP initialisé.
  • mcpServer/tool/call appelle 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/readiness vérifie si le bac à sable Windows est prêt. Si la méthode renvoie updateRequired, appelez windowsSandbox/setupStart et attendez windowsSandbox/setupCompleted.
  • feedback/upload envoie un rapport de retour utilisateur avec sa catégorie, un motif et des journaux facultatifs, l’identifiant de conversation et, éventuellement, des fichiers joints via extraLogFiles.
  • config/read récupère la configuration effective sur disque après combinaison des différentes couches de configuration.
  • externalAgentConfig/detect détecte les éléments d’agents externes pouvant être migrés, avec includeHome et le paramètre facultatif cwds. Chaque élément détecté contient cwd (null pour le répertoire personnel).
  • externalAgentConfig/import importe les éléments sélectionnés d’un agent externe. Passez explicitement migrationItems avec cwd (null pour 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 émettent externalAgentConfig/import/progress et externalAgentConfig/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 fichier config.toml de l’utilisateur sur disque.
  • config/batchWrite applique de façon atomique plusieurs modifications au fichier config.toml de l’utilisateur sur disque.
  • configRequirements/read récupère les exigences provenant de requirements.toml, de la gestion des appareils mobiles (MDM) ou des deux, notamment les listes d’autorisation et les valeurs imposées de featureRequirements. Les clients qui activent experimentalApi peuvent 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/unwatch et fs/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 exemple text, 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/read lit les métadonnées enregistrées d’un fil sans abonner le client à ses événements.
  • thread/turns/list parcourt l’historique des tours d’un fil enregistré sans le reprendre. Utilisez itemsView pour omettre les éléments des tours, en obtenir un résumé ou les charger intégralement.
  • thread/items/list parcourt les éléments enregistrés du fil, avec la possibilité de limiter les résultats à un tour.
  • thread/list parcourt les fils enregistrés page par page. Utilisez sectionId pour lister les fils d’une section ou excludedThreadIds pour exclure les fils déjà affichés.
  • thread/loaded/list renvoie les identifiants des fils actuellement en mémoire.
  • thread/archive dé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/delete supprime définitivement un fil enregistré, actif ou archivé, ainsi que ses descendants.
  • thread/metadata/update met à jour le champ gitInfo enregistré pour un fil.
  • thread/unsubscribe désabonne la connexion actuelle d’un fil chargé et peut déclencher thread/closed après un délai d’inactivité.
  • thread/unarchive restaure le journal d’un fil archivé dans le répertoire des sessions actives.
  • thread/compact/start déclenche le compactage et renvoie immédiatement {}.
  • thread/revert supprime 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_items ajoute 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 : avec false ou en l’absence de ce champ, la réponse contient uniquement le résumé du fil. La valeur true charge l’historique complet. Ce comportement est obsolète pour les fils paginés et entraîne l’émission de deprecationNotice. Utilisez plutôt les méthodes de pagination.
  • Les objets thread renvoyés contiennent le statut d’exécution status (notLoaded, idle, systemError ou active avec activeFlags).
{ "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 :

  • notLoaded omet les éléments.
  • summary renvoie un résumé des éléments. C’est la valeur par défaut si le champ est omis.
  • full renvoie 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_at ou section_position. Pour utiliser section_position, fournissez un sectionId non nul.
  • sortDirection : asc ou desc. Si vous omettez sortDirection, le tri est croissant pour section_position et décroissant pour les clés temporelles.
  • sectionId : passez l’identifiant d’une section pour lister ses fils ou null pour 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 passez null, 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 interactives cli et vscode.
  • archived : avec true, liste uniquement les fils archivés. Avec false ou 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 : avec true, 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 passez false pour 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écessite capabilities.experimentalApi = true.
  • ancestorThreadId : limite les résultats aux descendants du fil spécifié, à tous les niveaux. Ce filtre est expérimental et nécessite capabilities.experimentalApi = true. Ne le combinez pas avec parentThreadId.

sourceKinds accepte les valeurs suivantes :

  • cli
  • vscode
  • exec
  • appServer
  • subAgent
  • subAgentReview
  • subAgentCompact
  • subAgentThreadSpawn
  • subAgentOther
  • unknown

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/add accepte threadId, attachmentType, identityKey et un payload JSON. 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/list parcourt les ressources associées à un fil page par page. Pour retrouver les fils qui font référence à une ressource, appelez thread/attachmentOwner/list avec son attachmentType et sa clé identityKey.
  • thread/attachment/remove accepte threadId, attachmentType et identityKey. La ressource elle-même reste disponible.
  • thread/attachment/updated signale une opération created ou deleted lorsque 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 :

  • unsubscribed si la connexion était abonnée et que l’abonnement a été supprimé.
  • notSubscribed si la connexion n’était pas abonnée à ce fil.
  • notLoaded si 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 : champ access facultatif ({ "type": "fullAccess" } par défaut, ou accès limité à certaines racines).
  • workspaceWrite : champ readOnlyAccess facultatif ({ "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/steer n’émet pas de nouvelle notification turn/started.
  • turn/steer n’accepte pas la redéfinition de paramètres du tour (model, cwd, sandboxPolicy ou outputSchema).
{ "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 :

  • uncommittedChanges
  • baseBranch (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 command vides.
  • sandboxPolicy accepte la même structure que turn/start (par exemple dangerFullAccess, readOnly, workspaceWrite, externalSandbox).
  • Si vous omettez timeoutMs, le serveur utilise son délai par défaut.
  • Définissez tty: true pour les sessions utilisant un pseudo-terminal. Utilisez processId si vous prévoyez d’appeler ensuite command/exec/write, command/exec/resize ou command/exec/terminate.
  • Définissez streamStdoutStderr: true pour recevoir des notifications command/exec/outputDelta pendant 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 :

  • elevated lance la procédure de configuration du bac à sable Windows avec élévation de privilèges.
  • unelevated lance 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/delta dé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ête windowsSandbox/setupStart.

Événements de tour

  • turn/started : { turn } contient l’identifiant du tour, un tableau items vide et status: "inProgress".
  • turn/completed : { turn } contient un turn.status égal à completed, interrupted ou failed. 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 de plan a la forme { step, status }, avec un status égal à pending, inProgress ou completed.
  • hook/started et hook/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/updated transmet 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ù content est une liste d’entrées utilisateur (text, image ou localImage).
  • functionCallOutput : {id, name, namespace, output} représente une sortie d’outil autonome fournie via turn/start.toolOutput. namespace peut valoir null.
  • agentMessage : {id, text, phase?} contient la réponse de l’agent accumulée jusqu’ici. S’il est présent, phase utilise les valeurs du protocole de l’API Responses (commentary, partial_answer, final_answer). Un partial_answer contient 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ément plan final de item/completed fait foi.
  • reasoning : {id, summary, content}, où summary contient les résumés de raisonnement diffusés en continu et content, les blocs de raisonnement bruts.
  • commandExecution : {id, command, cwd, status, commandActions, aggregatedOutput?, exitCode?, durationMs?}.
  • fileChange : {id, changes, status} décrit les modifications proposées. changes contient la liste des entrées {path, kind, diff}.
  • mcpToolCall enregistre les champs id, server, tool, status et arguments de l’appel. L’appel contient aussi appContext, mcpAppUi, pluginId, readOnlyHint, result, error et durationMs. Chacun de ces champs peut valoir null. L’ancien champ mcpAppResourceUri est facultatif. Pour les applications MCP de confiance, appContext contient connectorId. Ses autres champs (linkId, resourceUri, appName et actionName) peuvent valoir null. Lorsque le descripteur de l’outil spécifie un URI de ressource et un mode d’affichage (inline ou fullscreen), mcpAppUi contient resourceUri et preferredModelDisplayMode. Pour les appels enregistrés sans ces métadonnées de présentation, app-server renvoie null pour mcpAppUi.
  • 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’item complet au début d’une nouvelle unité de travail. Son item.id correspond à l’itemId utilisé dans les mises à jour incrémentales.
  • item/completed envoie l’item final à la fin du travail. Cet état fait foi.

Mises à jour incrémentales des éléments

  • item/agentMessage/delta ajoute le texte reçu en continu au message de l’agent.
  • item/plan/delta diffuse le texte du plan proposé. L’élément plan final peut différer de la concaténation des fragments.
  • item/reasoning/summaryTextDelta diffuse des résumés lisibles du raisonnement. summaryIndex augmente au début de chaque nouvelle section du résumé.
  • item/reasoning/summaryPartAdded marque la limite entre deux sections du résumé de raisonnement.
  • item/reasoning/textDelta diffuse le texte brut du raisonnement si le modèle le prend en charge.
  • item/commandExecution/outputDelta diffuse stdout et stderr pour une commande. Ajoutez les fragments dans l’ordre.
  • item/fileChange/outputDelta est une notification de compatibilité obsolète pour l’ancienne sortie textuelle de apply_patch. Les versions actuelles d’app-server ne l’émettent plus. Utilisez les éléments fileChange et turn/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, cancel ou { "acceptWithExecpolicyAmendment": { "execpolicy_amendment": ["cmd", "..."] } }.

  • Décisions pour la modification d’un fichier : accept, acceptForSession, decline, cancel.

  • Les requêtes contiennent threadId et turnId. 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 :

  1. item/started présente l’élément commandExecution en attente, avec command, cwd et d’autres champs.
  2. item/commandExecution/requestApproval contient itemId, threadId, turnId et, éventuellement, reason, command, cwd, commandActions, proposedExecpolicyAmendment, networkApprovalContext et availableDecisions. Lorsque initialize.params.capabilities.experimentalApi = true, la requête peut également contenir le champ expérimental additionalPermissions décrivant les accès au bac à sable demandés pour cette commande. Tous les chemins du système de fichiers transmis dans additionalPermissions sont absolus.
  3. Le client répond avec l’une des décisions d’approbation d’exécution de commande indiquées ci-dessus.
  4. serverRequest/resolved confirme que la requête en attente a reçu une réponse ou a été retirée.
  5. item/completed renvoie l’élément commandExecution final avec status: 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 :

  1. item/started émet un élément fileChange avec les modifications proposées dans changes et status: "inProgress".
  2. item/fileChange/requestApproval contient itemId, threadId, turnId et, éventuellement, reason et grantRoot.
  3. Le client répond avec l’une des décisions d’approbation de modification de fichier indiquées ci-dessus.
  4. serverRequest/resolved confirme que la requête en attente a reçu une réponse ou a été retirée.
  5. item/completed renvoie l’élément fileChange final avec status: 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" ou mode: "openai/form", avec message et requestedSchema.
  • mode: "url", avec message, url et elicitationId.

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 :

  1. App-server émet item/started avec item.type = "dynamicToolCall", status = "inProgress", ainsi que tool et arguments.
  2. Le serveur envoie la requête item/tool/call au client.
  3. Le client répond avec les éléments de contenu renvoyés.
  4. App-server émet item/completed avec item.type = "dynamicToolCall", le status final et les éventuelles valeurs contentItems ou success renvoyé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 avec type: "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 avec type: "chatgpt" pour la connexion via le navigateur ou type: "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 directement accessToken, chatgptAccountId et, éventuellement, chatgptPlanType. Elle doit renouveler le jeton sur demande.
  • Amazon Bedrock : account/read identifie les comptes Bedrock par type: "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.authMode utilise bedrockApiKey pour les clés API Bedrock gérées par Codex.

Vue d’ensemble de l’API

  • account/read récupère les informations du compte actuel et peut renouveler les jetons.
  • account/login/start lance une connexion (apiKey, chatgpt, chatgptDeviceCode ou, à titre expérimental, chatgptAuthTokens).
  • account/login/completed (notification) signale la fin d’une tentative de connexion, qu’elle réussisse ou échoue.
  • account/login/cancel annule une connexion ChatGPT gérée en attente à partir de son loginId.
  • account/logout déconnecte le compte et déclenche account/updated.
  • account/updated (notification) signale tout changement de mode d’authentification (authMode : apikey, chatgpt, chatgptAuthTokens, agentIdentity, personalAccessToken, bedrockApiKey ou null) et contient planType s’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/read ré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/sendAddCreditsNudgeEmail demande à 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/consume utilise une réinitialisation de limite de débit acquise, avec une valeur idempotencyKey fournie par l’appelant.
  • account/usage/read récupère les statistiques de consommation de tokens du compte ChatGPT et les totaux quotidiens.
  • account/workspaceMessages/read ré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édure mcpServer/oauth/login et contient { name, threadId, loginId?, success, error? }. Les serveurs plus anciens omettent loginId. threadId peut valoir null pour 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 }. threadId vaut null pour 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 sur true pour forcer le renouvellement du jeton en mode ChatGPT géré. En mode jetons externes (chatgptAuthTokens), app-server ignore cette option.
  • email vaut null si le compte ChatGPT n’a pas d’adresse e-mail.
  • requiresOpenaiAuth dépend du fournisseur actif. Lorsque sa valeur est false, Codex peut fonctionner sans identifiants OpenAI.
  • Amazon Bedrock indique credentialSource: "codexManaged" lorsqu’il utilise une clé API Bedrock gérée par Codex. Il indique credentialSource: "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

  1. Envoyez la requête suivante :

    {
      "method": "account/login/start",
      "id": 2,
      "params": { "type": "apiKey", "apiKey": "sk-..." }
    }
  2. Attendez la réponse suivante :

    { "id": 2, "result": { "type": "apiKey" } }
  3. 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

  1. 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: true pour 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, appBrand peut valoir "codex" ou "chatgpt". Une valeur omise ou égale à null est 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"
      }
    }
  2. Ouvrez authUrl dans un navigateur. App-server héberge le point de rappel local.

  3. 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é.

  1. 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"
      }
    }
  2. Affichez verificationUrl et userCode à l’utilisateur. L’interface cliente gère cette étape.

  3. 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.

  1. Envoyez la requête suivante :

    {
      "method": "account/login/start",
      "id": 7,
      "params": {
        "type": "chatgptAuthTokens",
        "accessToken": "<jwt>",
        "chatgptAccountId": "org-123",
        "chatgptPlanType": "business"
      }
    }
  2. Attendez la réponse suivante :

    { "id": 7, "result": { "type": "chatgptAuthTokens" } }
  3. 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 :

  • rateLimits fournit une vue rétrocompatible d’un seul quota.
  • rateLimitsByLimitId, s’il est présent, fournit une vue de plusieurs quotas indexés par leur limit_id de comptabilisation (par exemple codex).
  • limitId identifie le quota dont l’utilisation est comptabilisée.
  • limitName est le libellé facultatif du quota destiné à l’utilisateur.
  • usedPercent indique le pourcentage consommé pendant la période du quota en cours.
  • windowDurationMins indique la durée de la période du quota.
  • resetsAt est l’horodatage Unix, en secondes, de la prochaine réinitialisation.
  • planType est présent lorsque le serveur renvoie l’offre ChatGPT associée à un quota.
  • credits est présent lorsque le serveur renvoie le détail des crédits restants de l’espace de travail.
  • rateLimitReachedType indique comment le serveur classe la limite atteinte.
  • rateLimitResetCredits contient le nombre de réinitialisations acquises encore disponibles lorsque le service le fournit. Sinon, il vaut null.
  • rateLimitResetCredits.credits vaut null si 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 : availableCount fait foi.
  • Chaque entrée détaillée contient un id opaque, resetType, status, grantedAt, expiresAt (qui peut valoir null), title (qui peut valoir null) et description (qui peut valoir null).
  • Appelez account/rateLimits/read aprè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 summary peuvent être null si le service n’a pas renvoyé la métrique correspondante.
  • dailyUsageBuckets peut valoir null. Lorsqu’il est renseigné, chaque entrée contient startDate et tokens.
  • 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 :

  • idempotencyKey doit ê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.
  • creditId est facultatif. Si vous le fournissez, utilisez un identifiant opaque non vide issu de account/rateLimits/read. Si vous l’omettez, le service sélectionne le prochain crédit disponible.
  • reset signifie qu’un crédit a été utilisé.
  • alreadyRedeemed signifie 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.
  • nothingToReset signifie qu’aucune période de limite de débit ne peut être réinitialisée.
  • noCredit signifie que le compte ne dispose d’aucun crédit de réinitialisation acquis.
  • Appelez account/rateLimits/read aprè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 }
] } }