ChatGPT Desktop — Hybrid Architecture and Mode Hierarchy
RE of the desktop app — Swift shell + Chromium renderer + embedded Codex app-server, the three conversation surfaces and their transports
ChatGPT Desktop — Hybrid Architecture and Mode Hierarchy
Part of openai-research.
Binary composition
/Applications/ChatGPT.app — bundle id com.openai.codex (the desktop app is the Codex app).
| Layer | Technology | Role |
|---|---|---|
| Shell | Native Swift (SDK macosx15.5, Sparkle updater, provisionprofile) | Window, menu, macOS integration |
Codex Framework.framework | Renamed Electron (Chromium 151.0.7922.170 — Chromium locale.pak in the bundle) | UI runtime ("Codex Framework" is branding of the Electron framework, not Rust) |
Resources/app.asar (271MB) | Electron (.vite/build/main-*.js main + /webview/ Vite renderer, 7609 files) | The whole app UI — works offline |
Resources/codex | Rust — compiled Codex app-server (Mach-O arm64, 220MB, 3669 rustc/cargo strings; same base as the codex-rs open source, desktop build) | App-server: auth/keychain, threads, realtime, HTTP to the codex backend (models polling ~3min, responses, images/generations) carrying x-oai-attestation; NOTE (2026-08-27): X-OAI-IS not observed in flow A / A1 / the manual runs (0 occurrences in the captured main headers of those flows); flow B: unknown (not executed) — the rust client request headers of any flow were never captured. The earlier "chain" claim came from the web-flow/vendor analysis |
~/.codex/ is the desktop app's CODEX_HOME (auth.json, models_cache.json, logs_2.sqlite with codex_http_client Rust logs, bundled plugins). Electron ↔ app-server communication: stdio JSON-RPC (app_server.request{rpc.transport="stdio"}).
ChatGPT Desktop ≠ Codex CLI: distinct products. The desktop embeds the Codex app-server (same codebase as the codex-rs open source, own binary and protocol) — it does not depend on the Codex CLI being installed, and the desktop binary has code the open source does not (e.g. the DeviceCheck attestation integration — x-oai-attestation; the public codex-rs has the AttestationProvider trait, the desktop supplies the Apple implementation). X-OAI-IS: not observed in the executed flows (A/A1/manual; 0 hits in the captured main headers); unknown for flow B (not executed); rust request headers never captured. The ~/workdir/codex source is a reference for the shared protocol, not the absolute source of the closed binary.
Mode hierarchy
MODO CHATGPT
├─ submodo work → chatgpt.com/backend-api + handoff tool (Codex quota, /compact)
└─ submodo chat → chatgpt.com/backend-api (chat quota, no compact) ← RESEARCH FOCUS
MODO CODEX → app-server direct → /backend-api/codex
Submode marking in the payload (/f/conversation)
The body builder is r3r() in the renderer. Chat vs Work is not a mode boolean:
- The distinguishing mechanism is
local_function_signatures— thehandofftool with the server-provided description that is always offered in the ChatGPT mode conversation_mode: {kind: 'gizmo_interaction', gizmo_id}+gizmo_id= Projectsconversation_execution_target— execution target (tpp/local tasks)
Renderer → network transport
- Renderer calls the typed API client (
safeGet/safePost, OpenAPI paths — 163 mapped) - Transport
Hpsends via IPC (fetch-responseevents) — the renderer never fetches directly - Control headers renderer→main:
X-OpenAI-Attach-Auth: 1(main injectsAuthorization: Bearer+ChatGPT-Account-Idfrom the app-server),X-OpenAI-Attach-Integrity-State: 1(main resolves the session integrity marker — see theoai_isfield of the OAuth refresh; NOT observed as anX-OAI-ISrequest header in the real f/* traffic),X-OpenAI-Attach-Desktop-Surface,X-OpenAI-Attach-DeviceCheck-Token(DeviceCheck) - Main cleans the User-Agent (
excludedUserAgentProducts: ['Electron', app name]) - Client defaults:
OAI-Language: en,originator: Codex Desktop,oai-did(persisted device uuid)
Authenticated webviews (the only exception)
Webviews that render site pages (checkout /purchase/*, workspace settings, Sites) use SR()/OR() in the main: clear cookies, POST /api/auth/link-session with {auth_token, expires_in} + x-i-am-a-browser: true (see auth-and-link-session), then set routing cookies (_account, _account_residency_region, _account_is_fedramp). The chat does not use this path.
Plugin primary runtime (on-demand download)
The app downloads a bundled "primary runtime" on demand: GET persistent.oaistatic.com/codex-primary-runtime/<version>/codex-primary-runtime-darwin-arm64-<version>.tar.xz with UA codex-primary-runtime-installer (main process). Version 26.826.11250 (newer than the app 26.820.60940 — the runtime tracks its own release line). Extracts into ~/.codex/plugins/cache/openai-primary-runtime/{template-creator,spreadsheets,pdf,presentations,documents}/26.826.11250/ — the plugin runtime surfaces (docs, sheets, PDF, slides, template creator) used by the agent mode.
Cross-references
- Chat submode protocol: chat-submode-protocol
- Codex backend: codex-flow-protocol
- Auth and tokens: auth-and-link-session