Skip to content

docs: clarify Codex Mobile support with custom providers #149

Description

@masterkain

summary

Codex Mobile / Remote Control does not currently provide reliable new-thread support when the connected desktop host uses a custom Codex Pooler model provider.

A thread created from mobile can be persisted and executed by the connected desktop host while being initialized with the built-in openai model provider instead of the host's configured custom provider. The model request can then bypass Codex Pooler and use the OpenAI/ChatGPT account path available to the host.

By contrast, a thread created on Codex Desktop with the Codex Pooler provider and later resumed from mobile generally retains its persisted provider when the client does not submit a model/provider override and the persisted thread metadata is available.

Status checked August 13, 2026: no fix for Remote new-thread provider inheritance is present in current upstream main or the checked public release tags and release branches. The desktop-first workaround below remains the only evidence-backed workaround.

upstream context

The direct upstream reports are:

  • openai/codex#23659 documents the likely Android root condition: Remote sends modelProvider=openai as a client default, and app-server treats it as an explicit override instead of letting the host configuration resolve the provider
  • openai/codex#31370, updated August 10, reports Android Remote creating usable host-local threads with model_provider=openai instead of the configured host provider; this remains the closest match to the Codex Pooler routing problem
  • openai/codex#33054, opened after this issue and updated July 31, independently reports the same provider mismatch: the Remote picker can expose a custom-catalog model while a new mobile-created thread persists as model_provider=openai and uses the ChatGPT account path

An upstream commit 43dfb545 implements the normalization proposed in #23659: Android Remote's default openai value is treated as no provider override, while deliberate non-default provider choices are preserved. The change also covers resume and fork. However, that commit belongs to a divergent, unmerged lineage. It is absent from current main and from the checked public releases through rust-v0.148.0-alpha.12, so it must not be treated as shipped.

Configuration and permission reports provide supporting context but are not provider-routing proof:

  • openai/codex#25186 was closed by its reporter on August 4 with an unqualified fixed comment, but has no linked maintainer confirmation, PR, commit, release note, or provider-routing verification
  • openai/codex#24270 remains open and shows that mobile-selected permission settings can diverge from the effective host configuration; this concerns approval/sandbox state, not the model provider or Pooler credential

Related thread visibility reports must also remain causally separate:

  • openai/codex#24780, openai/codex#24648, and openai/codex#35617 show a provider-filtered history failure: omitted or null modelProviders defaults to the currently configured provider, while an empty list means all providers. A valid custom-provider thread can therefore disappear from a refreshed list without being deleted or rerouted
  • openai/codex#22800, openai/codex#30123, and the canonical sidebar issue openai/codex#30895 cover additional mobile-created versus desktop-created thread lifecycle, restore, project-association, and sidebar synchronization differences. These remain relevant context, but do not establish the provider-routing cause
  • openai/codex#31187 tracks host/account identity ambiguity. Official Remote documentation now describes pairing and switching between multiple hosts under the same account and workspace, but simultaneous multi-account operation and durable thread-to-host provenance remain unclear

A broader non-Remote report, openai/codex#37245, describes a custom model remaining selected while the reporter observed sampling traffic going to ChatGPT/OpenAI endpoints rather than the configured custom endpoint. This is reporter evidence from a desktop build, not a confirmed universal behavior, but it reinforces the verification rule for this issue: a model name or successful response is not routing proof.

current Codex behavior

Current app-server source explains the start/resume difference:

  • thread/start accepts client-provided model/provider values as configuration overrides. An explicit modelProvider takes precedence over the host's configured provider
  • if modelProvider is omitted, the configured host model_provider is used when present; built-in openai is the final fallback
  • thread/resume restores the provider persisted with a non-running thread when persisted metadata is available and the client does not submit a model/provider override
  • explicit resume overrides, already-loaded threads, or missing persisted metadata can change those semantics, so resumption must still be verified rather than assumed

This means the failure is not that every Remote start always selects openai. The demonstrated Android failure is that the client can submit its default openai value as an authoritative override, preventing the host configuration from winning.

impact on Codex Pooler users

  • A successful mobile response can create the false impression that the request used Codex Pooler
  • Pool policy, upstream selection, quota accounting, and request logs are bypassed when the effective request never reaches Pooler
  • Usage can be charged against the OpenAI/ChatGPT account path instead of a Pool-selected upstream
  • A custom-catalog model can appear selectable but fail at runtime because the mobile-created thread uses built-in openai
  • Custom-provider threads can also be hidden by provider-filtered history or remain absent from normal Desktop/mobile project lists even when their local thread state is intact

current workaround

Create the thread on Codex Desktop while the Codex Pooler provider is active, then open or resume that existing thread from mobile.

This normally preserves the provider stored in the desktop-created thread when the mobile client does not submit a model/provider override. Creating a brand-new thread from mobile should not currently be documented as guaranteed to use Codex Pooler.

The workaround should be verified for the actual client build by checking the resumed thread's effective provider and a matching Codex Pooler request row. Thread visibility or a successful response alone is insufficient.

configuration constraints

The provider id alone is not routing proof. In current Codex, model_provider = "openai" is a valid selection of the built-in provider, and the top-level openai_base_url can redirect that provider. What Codex rejects is redefining the reserved built-in id through [model_providers.openai].

Current Codex Pooler documentation therefore uses distinct Codex provider ids such as codex-pooler-ws and codex-pooler-http, with name = "OpenAI" to preserve OpenAI-family client behavior. Other clients can legitimately use an openai provider id in their own configuration schema; that is a separate namespace and should not be generalized to Codex's reserved provider table.

openai_base_url changes the built-in openai provider's API endpoint, but it does not configure a Pool API-key credential for that provider. On a Remote host signed in with ChatGPT, built-in openai uses the first-party Codex authentication available to the client. Replacing that sign-in with API-key authentication changes the account mode and can remove account-dependent features required by Remote, so it is not an established Mobile workaround.

For a custom Codex Pooler provider, the recommended configuration remains env_key = "CODEX_POOLER_API_KEY". Codex resolves that provider-scoped key before falling back to global Codex/ChatGPT authentication. If the environment variable is missing or empty, provider authentication fails.

Codex also supports experimental_bearer_token = "<pool-api-key>" inside a custom provider block. This can be used as a short-lived diagnostic to distinguish an environment-propagation failure from a provider-selection failure, but it is discouraged for normal use because it stores the secret directly in config.toml.

Hardcoding the bearer only helps when the effective provider is still the custom Codex Pooler provider. If a mobile-created thread persists as model_provider=openai, the custom provider block, its env_key, and its hardcoded bearer are all bypassed. It therefore does not work around the primary Remote thread/start provider-inheritance defect documented here.

requires_openai_auth is independent of env_key:

  • true can preserve account-dependent Codex/Desktop features while env_key still supplies the bearer token sent to Codex Pooler
  • false provides a gateway-only, fail-closed configuration but may make account-dependent Desktop, app-server, or mobile features unavailable

Codex Pooler runtime routes require a Pool API-key bearer token before dispatch, routing, and accounting. A correct URL, provider name, model name, or successful response does not prove that Pooler handled the request.

This issue should not lead to proxying ChatGPT control-plane, account, identity, pairing, realtime, or app-server helper routes. Codex Pooler supports authenticated model-provider traffic through its explicit runtime routes; it is not a wildcard Remote Control proxy.

proposed repository scope

  • Add a public Codex Mobile / Remote Control limitation section to the Codex CLI client documentation and docs site
  • State explicitly that mobile-created new threads are not currently guaranteed to use Codex Pooler
  • Distinguish Remote thread/start from resuming a desktop-created thread
  • Name thread/start, thread/resume, pairing, account, identity, permission-profile, and realtime helpers as unsupported Pooler proxy surfaces; clarify that Remote communicates with the host app-server and only the resulting model-provider request may reach Pooler
  • Explain that requires_openai_auth controls local account-dependent client behavior and does not enable app-server or Remote helper proxying
  • Document direct bearer configuration only as a diagnostic for environment propagation, not as a permanent credential recommendation or a fix for provider selection
  • Keep the direct provider reports, the unmerged normalization commit, and the separate visibility/permission issue families linked so the limitation can be revisited without conflating their causes
  • Add a metadata-only verification procedure that compares desktop-created/resumed and mobile-created/new threads

acceptance criteria

  • Public documentation clearly distinguishes mobile thread/start from resuming a desktop-created thread
  • The documented workaround does not imply that every resumed or mobile-created turn is accounted by Codex Pooler
  • Verification records the request-side provider override, the effective/persisted provider, the actual request destination, the credential class or safe fingerprint, and the corresponding Pooler request/accounting row
  • Verification covers both a desktop-created thread resumed from mobile and a brand-new mobile-created thread
  • Provider-filtered history, sidebar synchronization, permission inheritance, and host/account selection are tested or documented as separate boundaries rather than treated as proof of provider routing
  • Any future configuration recommendation proves both routing and authentication through a Pool API key
  • Verification distinguishes environment propagation from provider selection by testing the same custom provider with env_key and, only in a disposable diagnostic configuration, a direct bearer token
  • Any future implementation remains compatible with multi-node Codex Pooler deployments and preserves the current explicit model-provider-only proxy boundary unless that product scope is deliberately changed

Metadata

Metadata

Assignees

No one assigned

    Labels

    wontfixThis will not be worked on

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions