Codex Mobile remote-control tasks with custom provider disappear from thread list after refresh

Open 💬 4 comments Opened May 27, 2026 by jj-cheng25
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of the Codex App are you using?

Codex Desktop: 26.519.81530
Codex CLI: 0.133.0

What platform is your computer?

macOS 26.3.1 (a) (25D771280a)

What issue are you seeing?

When Codex Desktop on macOS is configured to use a custom OpenAI-compatible Responses API provider, Codex Mobile remote control can start a new task and the Mac host executes it successfully. However, after refreshing the Codex Mobile thread/task list, that task disappears from the mobile list.

The task is not deleted locally. It remains present in the Mac host's local Codex state (~/.codex/state_5.sqlite) and rollout JSONL under ~/.codex/sessions/....

This appears related to custom-provider thread list/history filtering, but the user-visible symptom is specifically in Codex Mobile remote control:

  • Mobile can create/send the task to the Mac host.
  • The Mac host executes the task using the custom provider.
  • The live task is visible while it is running.
  • After refreshing/reopening the mobile list, the task is no longer visible.
  • Threads created with the normal openai provider are visible in the mobile history/list.
  • Existing local custom_responses_provider/custom-provider Mac threads are not discoverable from the mobile history/list.

The custom provider is configured in ~/.codex/config.toml similarly to:

model = "gpt-5.5"
model_provider = "custom_responses_provider"

[model_providers.custom_responses_provider]
name = "Custom Responses Provider"
base_url = "<redacted OpenAI-compatible /v1 endpoint>"
wire_api = "responses"
env_key = "CUSTOM_RESPONSES_API_KEY"

The Mac host is still logged in to the ChatGPT/OpenAI account for Codex Mobile remote control. Remote control enrollment is present and working: mobile remote control can reach the Mac and submit work.

What steps can reproduce the bug?

  1. On Codex Desktop for macOS, configure a custom model provider in ~/.codex/config.toml, for example model_provider = "custom_responses_provider" with wire_api = "responses".
  2. Keep Codex Desktop logged in to the ChatGPT/OpenAI account used by Codex Mobile.
  3. Connect Codex Mobile to the Mac host through remote control.
  4. From Codex Mobile, start a new task/thread on that Mac host.
  5. Observe that the Mac host receives the task and executes it successfully through the custom provider.
  6. Refresh or reopen the Codex Mobile task/thread list.
  7. Observe that the newly created custom-provider task disappears from the mobile list.
  8. Switch the Mac host back to the normal openai provider and create a task. That task appears in the mobile history/list as expected.

What is the expected behavior?

Codex Mobile should list and allow reopening/continuing local Mac-host threads created through remote control even when the host used a custom model provider.

More specifically:

  1. A task created from Codex Mobile and executed on the Mac host with model_provider != "openai" should remain visible after mobile list refresh.
  2. The mobile history/list should include local host threads across providers, or at least include threads for the currently connected host regardless of provider.
  3. Opening a custom-provider thread from mobile should route continuation back to the same Mac host and preserve the thread's persisted model provider.

What is the actual behavior?

  1. The custom-provider task runs successfully on the Mac host.
  2. It may appear temporarily while live/running.
  3. After refreshing the Codex Mobile list, it disappears.
  4. Local Mac state still contains the thread and rollout file.
  5. Normal openai provider threads remain visible in the mobile history/list.

Local evidence

On the affected machine, local SQLite state shows custom-provider threads are persisted and not archived:

model_provider  source  thread_source  archived  n
--------------  ------  -------------  --------  --
custom_provider  cli     user           0         1
custom_provider  vscode  user           0         7
openai          cli                    0         17
openai          exec                   0         12
openai          vscode                 0         34
openai          vscode  user           0         8

Remote control enrollment exists locally, and the mobile-to-Mac execution path works:

app_server_client_name  server_name               websocket_url_len
----------------------  ------------------------  -----------------
Codex Desktop           <local Mac host name>      56

The custom-provider threads also have rollout JSONL files under ~/.codex/sessions/YYYY/MM/DD/.

Related issues

This seems related to existing custom-provider history/list issues, but this report is specifically about Codex Mobile remote-control visibility after refreshing the mobile list:

Security notes

No API key or private provider URL is included here. Thread titles and message content are intentionally omitted.

View original on GitHub ↗

4 Comments

github-actions[bot] contributor · 3 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #24462
  • #24464
  • #24749
  • #24737

Powered by Codex Action

jj-cheng25 · 3 months ago

Thanks for the duplicate suggestions. I reviewed #24462, #24464, #24749, and #24737.

They look related to the broader Codex Mobile Remote persisted thread-list / refresh path, especially the "appears briefly, then disappears" behavior. This issue adds one more specific dimension that I did not see covered in those reports: the visibility problem is reproducible when the connected desktop host is using a custom OpenAI-compatible Responses provider, while threads created with the normal openai provider on the same host/account remain visible in the mobile history/list.

So this may share the same underlying mobile remote enumeration/indexing bug, but the provider filter/custom-provider dimension seems important for diagnosis. If maintainers prefer to consolidate this into one of the existing mobile remote list issues, that is fine; I wanted to capture the custom-provider contrast and local evidence separately.

jj-cheng25 · 3 months ago

I did a source-level pass over the public app-server/thread-list path and this looks like a plausible root cause / minimal fix direction.

At current main (bf72be59278e23002a352a53207182985cabb9d0), ThreadListParams.model_providers is documented as:

  • set to a non-empty list: filter to those providers
  • set to an empty list: include all providers
  • null/omitted: implementation default

Relevant source:

  • codex-rs/app-server-protocol/src/protocol/v2/thread.rs lines 993-996: When present but empty, includes all providers.
  • codex-rs/thread-store/src/types.rs lines 188-190: None means implementation default, while an empty vector means all providers.
  • codex-rs/app-server/src/request_processors/thread_processor.rs lines 3468-3477 implements that default as current-provider filtering:
let model_provider_filter = match model_providers {
    Some(providers) => {
        if providers.is_empty() {
            None
        } else {
            Some(providers)
        }
    }
    None => Some(vec![self.config.model_provider_id.clone()]),
};

That behavior seems consistent with the symptom here:

  1. Mobile Remote live delivery works, so the mobile-created task reaches the desktop host and the host persists it locally.
  2. On refresh/reopen, the mobile list likely re-enumerates persisted host threads via thread/list or an equivalent path.
  3. If that persisted-list request sends modelProviders: null / omits modelProviders, the app-server applies the current-provider default filter rather than returning all local host threads.
  4. For a custom-provider thread, this can make the newly created thread disappear from the refreshed mobile list even though the local SQLite/rollout state still contains it.

This also matches the existing remote-thread-store test shape: codex-rs/app-server/tests/suite/v2/remote_thread_store.rs lines 144-152 explicitly sends model_providers: Some(Vec::new()) when listing remote-created threads, which is the all-provider form.

Suggested minimal fix direction:

  • In the Mobile Remote persistent host thread-list / project-thread-list path, send modelProviders: [] when the UI is asking for local host history, unless the user explicitly selected a provider filter.
  • Preserve modelProviders: [provider] for UI flows that intentionally filter by provider.
  • Avoid relying on null / omitted for Mobile Remote history refresh, because today that means current-provider default rather than all providers.

Possible regression coverage:

  • Seed two persisted local threads for the same host/cwd, one with model_provider = "openai" and one with model_provider = "custom_responses_provider".
  • Exercise the same thread/list params used by Mobile Remote refresh.
  • Assert the mobile/remote history enumeration returns both when no explicit user-facing provider filter is intended.
  • Separately keep existing coverage that a non-empty modelProviders list filters intentionally.

I am not opening an unsolicited PR because docs/contributing.md says external code contributions are by invitation only. If this diagnosis matches the intended architecture and maintainers would like a targeted PR, I can prepare a minimal patch/regression test around the public app-server/protocol path.

iamitp · 1 month ago

I hit a related Codex Remote failure class and built a small conformance-style
artifact that may help separate "thread list/indexing" bugs from the broader
remote attachment contract.

Repo: https://github.com/iamitp/codex-remote-attach-lab

This is not a claim that #24780 has the same root cause. This issue looks
specifically tied to custom-provider history enumeration. The thing I wanted to
add is a runnable way to classify the user-visible remote state from app-server
evidence:

  • Live Attached: this client is connected to the live thread.
  • Running Elsewhere: work appears active, but this client is not attached.
  • Launchable: thread exists and can be resumed, but no live turn is attached.
  • Reconnecting: recent transport loss with a plausible recovery path.
  • Mirrored Recent: recent metadata exists, but live attachment is not proven.
  • Stale Mirror: old metadata exists and should not be shown as live.
  • Offline: no app-server transport is reachable.

The lab uses the public codex app-server protocol:

  • JSON-RPC initialize / initialized handshake;
  • thread/loaded/list;
  • thread/list;
  • optional thread/resume for a target thread;
  • synthetic tests for the status classifier.

My diagnosis: Codex Remote is framed as a control plane, and a control plane
needs a first-class attachment truth contract. On foreground/reopen/host switch,
the client should prove whether it is attached to live work, running elsewhere,
launchable, stale, or offline before showing the user a generic reconnecting
state.

Potential maintainers' uses:

  • add an app-server diagnostic / doctor view for attachment status;
  • add conformance tests around foreground/reconnect, socket drop, host switch,

running-thread resume, and stale metadata;

  • document how rich clients should classify live attachment vs. mirrored

history;

  • if the product path wants a protocol addition, expose a compact

thread/attach/status view with host, loaded, active, subscribed,
last-event, and supported-action fields.

I saw the contributing guide says external code contributions are by invitation
only, so I am not opening an unsolicited PR. If this matches the intended
architecture, I can prepare a small invited PR around diagnostics/docs/tests or
keep this as an external conformance reference.