Skip to content

Bug: 注入 opencodex 后 Codex App 左侧 Project 线程列表消失 #11

Closed

Description

@l269438

问题描述

使用 opencodex 给 Codex 增加/切换模型后,重新打开 Codex App,左侧 Project 里的历史线程列表消失,看起来像线程都没了。

排查后确认本地数据并没有被删除:~/.codex/state_5.sqlite、~/.codex/session_index.jsonl、~/.codex/history.jsonl 和 ~/.codex/.codex-global-state.json 都还在,sqlite 完整性检查也是 ok。所以更像是 opencodex 注入配置后,Codex App 读取/过滤项目线程列表出现异常。

复现步骤

  1. 在 macOS 上安装并初始化 opencodex。

  2. 通过 opencodex 添加/启用模型,让它注入 Codex 配置。

  3. opencodex 代理启动后,~/.codex/config.toml 中默认 provider 被改成:

    model_provider = "opencodex"
    
    [model_providers.opencodex]
    base_url = "http://localhost:10100/v1"
  4. 退出并重新打开 Codex App。

  5. 观察左侧 Project 区域,历史项目线程列表消失。

期望行为

opencodex 注入模型 provider 后,不应该影响 Codex App 左侧 Project/线程列表的展示。历史项目和线程应该照常可见。

实际行为

重新进入 Codex App 后,左侧 Project 中看不到原来的线程,用户会误以为线程数据被删了。

但实际本地数据仍存在:

~/.codex/state_5.sqlite: 398 threads, 378 unarchived
~/.codex/.codex-global-state.json: electron-saved-workspace-roots 仍有 22 个项目路径
sqlite pragma integrity_check: ok

threads 表里旧线程主要还是 model_provider = openai,新线程出现了 model_provider = opencodex。怀疑 Codex App 的项目/线程列表在 provider、模型 catalog 或注入后的配置状态上出现了过滤/兼容问题。

临时恢复方式

执行:

ocx restore

后,~/.codex/config.toml 中 opencodex 路由会被移除,models cache 也恢复为 native models。然后完全退出并重新打开 Codex App,理论上应恢复原生 Codex 读取逻辑。

建议 opencodex 在注入/恢复时:

  • 不影响 Codex App 的 Project/线程列表读取;
  • 或在注入前备份并明确提示可能影响 App UI;
  • 或提供更明确的诊断/恢复命令,告诉用户线程没有被删除。

环境信息

macOS: 15.7.4
opencodex: @bitkyc08/opencodex 2.1.1
codex-cli: 0.141.0
Codex App: 149.0.7827.115

额外观察

执行 ocx restore --help 时,没有显示 help,而是直接执行了 restore。这个行为也比较危险,建议子命令遇到 --help 时只展示帮助,不要产生配置变更。

Activity

  1. 0disoft commented on Jun 22, 2026

    @0disoft
    Contributor

    Thanks for writing this up. I hit a very similar Codex App sidebar symptom on Windows: project threads looked like they disappeared while opencodex was active, but ocx restore made them visible again.

    I opened #13 as a related safety change. It makes resume-history remapping opt-in instead of rewriting existing openai threads to opencodex during injection. That PR intentionally does not claim to fully close this issue, because your observation suggests another possible path too: Codex App may be filtering existing openai project threads when the root model_provider is switched to opencodex, even if the old rows remain openai.

    So I think there are two separate concerns here:

    1. Avoid mutating existing Codex resume history by default (Preserve Codex resume history by default #13).
    2. Investigate whether Codex App hides existing openai project threads whenever the active root provider is opencodex.

    Your extra ocx restore --help note also looks like a separate CLI safety bug: subcommand help should not execute restore.

  2. 0disoft commented on Jun 22, 2026

    @0disoft
    Contributor

    I split out the separate ocx restore --help side effect into #14. That PR only fixes the CLI help safety issue: help flags are handled before any restore/eject/uninstall/start-style command can mutate config.

    So the current mapping is:

  3. 0disoft commented on Jun 22, 2026

    @0disoft
    Contributor

    Additional Windows reproduction data:

    I reproduced the same sidebar behavior on Windows. After starting opencodex and restarting Codex App, the zerodi-wd1 project section showed no chats while opencodex was active. After stopping/restoring the proxy, the same project chats became visible again.

    Important detail: this happened with syncResumeHistory: false, so opencodex was not rewriting the old resume history rows in this run.

    Local data was still present after the UI hid the chats:

    platform: Microsoft Windows NT 10.0.26200.0
    PowerShell: 7.6.2
    opencodex: 2.1.3 dev checkout, started with `bun run src/cli.ts start`
    syncResumeHistory: false
    defaultProvider: umans
    configured providers: openai, umans, openrouter, opencode-go
    
    ~/.codex/state_5.sqlite integrity_check: ok
    threads_count: 252
    provider_count openai: 229
    provider_count opencode_go: 11
    provider_count openrouter: 6
    provider_count codexchange: 5
    provider_count probe: 1
    unarchived: 53
    
    zerodi-wd1 thread rows:
    openai archived=0: 13
    openai archived=1: 72
    opencode_go archived=0: 10
    openrouter archived=0: 5
    codexchange archived=0: 5
    probe archived=0: 1
    

    So this looks less like data deletion and more like Codex App filtering project threads based on the active root provider/catalog state. In this run, most existing project threads stayed as model_provider = openai, but they were hidden while the active root provider was opencodex.

    Current workaround is still ocx restore / stop proxy, then restart Codex App.

  4. 0disoft commented on Jun 22, 2026

    @0disoft
    Contributor

    Follow-up after the Windows repro: I think the framing should be slightly different.

    The resume-history remap is not just an unsafe mutation; it is also the practical compatibility mode that makes existing OpenAI-backed chats visible while opencodex is the active provider. From the user's point of view, preserving existing chats in the sidebar is the important behavior.

    So I updated #13 to frame syncResumeHistory as an explicit compatibility mode:

    • default off: do not mutate Codex's local thread index automatically;
    • opt-in on: remap old openai rows to opencodex so existing chats can appear while the proxy is active;
    • restore remains responsible for mapping remapped rows back to openai.

    That still leaves the underlying Codex App provider-filtering behavior unresolved, but it makes the opencodex-side tradeoff clearer.

  5. 0disoft commented on Jun 22, 2026

    @0disoft
    Contributor

    Confirmed on Windows: enabling the history compatibility remap makes the old project chats visible again while opencodex is active.

    Test result:

    syncResumeHistory: true
    opencodex proxy: healthy
    Codex App restarted with model_provider = opencodex
    Codex App sidebar: existing zerodi-wd1 project chats visible again
    Codex App model picker: opencodex models visible, including:
    - umans/umans-glm-5.2
    - umans/umans-kimi-k2.7
    - opencode-go/deepseek-v4-pro
    - opencode-go/deepseek-v4-flash
    - opencode-go/qwen3.7-plus
    

    Local state after the remap:

    all threads by provider:
    opencodex 217
    openai 12
    opencode_go 11
    openrouter 6
    codexchange 5
    probe 1
    
    zerodi-wd1 rows:
    opencodex archived=0: 12
    opencodex archived=1: 69
    openai archived=0: 1
    openai archived=1: 3
    opencode_go archived=0: 10
    openrouter archived=0: 5
    codexchange archived=0: 5
    probe archived=0: 1
    

    So the practical workaround for existing chat visibility is syncResumeHistory=true. Without the remap, the local data remains intact but Codex App hides most old OpenAI-backed project chats while opencodex is active.

  6. lidge-jun commented on Jun 22, 2026

    @lidge-jun
    Owner

    Investigation update: I am actively debugging this now from a more precise reproduction path.

    Current repro from the maintainer environment:

    1. The local opencodex (ocx) — Universal provider proxy for Codex

    Usage:
    ocx init Interactive setup (provider + Codex config injection)
    ocx start [--port ] Start the proxy server (auto-syncs models to Codex)
    ocx stop Stop the proxy AND restore native Codex (plain codex works again)
    ocx restore Restore native Codex without stopping (alias: eject)
    ocx uninstall Remove service/shim/config and restore native Codex
    ocx service Run as a background service (install|start|stop|status|uninstall)
    ocx codex-shim Auto-start proxy when codex launches (install|status|uninstall)
    ocx ensure Ensure the proxy is running and Codex config/cache are current
    ocx sync Fetch models from providers and inject into Codex config
    ocx sync-cache Refresh Codex's model cache from the active catalog
    ocx status Check proxy server status
    ocx login OAuth login (xai) — opens browser, stores token in ~/.opencodex/auth.json
    ocx logout Remove a stored OAuth login
    ocx update Update opencodex to the latest published version
    ocx help Show this help message

    Examples:
    ocx init Set up provider and inject into Codex
    ocx start Start on default port (10100)
    ocx start --port 8080 Start on custom port
    ocx sync Sync available models to Codex command is symlinked through opencodex (ocx) — Universal provider proxy for Codex

    Usage:
    ocx init Interactive setup (provider + Codex config injection)
    ocx start [--port ] Start the proxy server (auto-syncs models to Codex)
    ocx stop Stop the proxy AND restore native Codex (plain codex works again)
    ocx restore Restore native Codex without stopping (alias: eject)
    ocx uninstall Remove service/shim/config and restore native Codex
    ocx service Run as a background service (install|start|stop|status|uninstall)
    ocx codex-shim Auto-start proxy when codex launches (install|status|uninstall)
    ocx ensure Ensure the proxy is running and Codex config/cache are current
    ocx sync Fetch models from providers and inject into Codex config
    ocx sync-cache Refresh Codex's model cache from the active catalog
    ocx status Check proxy server status
    ocx login OAuth login (xai) — opens browser, stores token in ~/.opencodex/auth.json
    ocx logout Remove a stored OAuth login
    ocx update Update opencodex to the latest published version
    ocx help Show this help message

    Examples:
    ocx init Set up provider and inject into Codex
    ocx start Start on default port (10100)
    ocx start --port 8080 Start on custom port
    ocx sync Sync available models to Codex into the current dev checkout.
    2. makes the Codex App sidebar look empty, including older OpenAI-backed chats and chats created while opencodex was active.
    3. ✅ Proxy (PID 67578) stopped.
    ↩️ opencodex not present in Codex config./restore makes the older OpenAI-backed chats visible again, but chats created while opencodex was active still do not appear.

    Current evidence suggests there are two filters involved, not just one:

    • : when the active root provider is opencodex (ocx) — Universal provider proxy for Codex

    Usage:
    ocx init Interactive setup (provider + Codex config injection)
    ocx start [--port ] Start the proxy server (auto-syncs models to Codex)
    ocx stop Stop the proxy AND restore native Codex (plain codex works again)
    ocx restore Restore native Codex without stopping (alias: eject)
    ocx service Run as a background service (install|start|stop|status|uninstall)
    ocx sync Fetch models from providers and inject into Codex config
    ocx status Check proxy server status
    ocx login OAuth login (xai) — opens browser, stores token in ~/.opencodex/auth.json
    ocx logout Remove a stored OAuth login
    ocx update Update opencodex to the latest published version
    ocx help Show this help message

    Examples:
    ocx init Set up provider and inject into Codex
    ocx start Start on default port (10100)
    ocx start --port 8080 Start on custom port
    ocx sync Sync available models to Codex, existing rows can be hidden.

    • : many opencodex-created rows are stored as , while the current opencodex history remap code only treats and as resumable/project-sidebar candidates.

    I am digging into the Codex/codex-rs history semantics in parallel and working on an opencodex-side compatibility fix. I will keep #13 as related but not final until this provider+source behavior is accounted for.

  7. lidge-jun commented on Jun 22, 2026

    @lidge-jun
    Owner

    Correction / refined investigation update: the previous maintainer comment was partially corrupted by shell quoting. This is the accurate reproduction and current hypothesis.

    Maintainer repro:

    1. The local ocx command resolves to the development checkout: /Users/jun/.local/bin/ocx -> /Users/jun/Developer/new/700_projects/opencodex/dist/bin/ocx -> ../../src/cli.ts.
    2. ocx start makes all Codex App project history disappear from the sidebar, including old OpenAI chats and chats created while opencodex was active.
    3. ocx stop restores the old OpenAI-side chats.
    4. Chats created while opencodex was active remain hidden after ocx stop.

    Current local DB evidence suggests this is a two-axis visibility problem, not only a provider-label problem:

    • old visible rows are mostly model_provider = openai with source IN (cli, vscode);
    • opencodex-created project rows are mostly model_provider = opencodex with source = exec;
    • the current opencodex history compatibility helper only remaps provider for resumable sources (cli, vscode).

    So #13 is still useful as a safety change: it stops automatic mutation by default and makes the OpenAI->opencodex provider remap explicit via syncResumeHistory: true. But it is not the full fix for this issue because it does not address opencodex-created rows whose source is exec.

    I am investigating Codex App / codex-rs filtering semantics now and will patch opencodex only with a reversible, opt-in compatibility path. The working devlog is devlog/220_codex-app-history-visibility/00_plan.md.

  8. lidge-jun commented on Jun 22, 2026

    @lidge-jun
    Owner

    Update: pushed a follow-up fix to dev in 3244d28 (fix: eject opencodex history on native restore). This follow-up builds on @0disoft's PR #13 (Preserve Codex resume history by default) and the reproduction tracked here in #11.

    Local testing found one more native-restore failure mode: after ocx stop, ~/.codex/config.toml no longer contains [model_providers.opencodex], but existing Codex history rows / rollout session_meta could still have model_provider = "opencodex". Codex App then fails to resume with:

    Model provider `opencodex` not found
    

    The dev fix changes the invariant for native restore:

    • ocx stop / ocx restore restore backed-up OpenAI rows to openai;
    • any remaining opencodex user history rows are ejected to openai so native Codex can resume them after the proxy provider is removed;
    • opencodex-created exec rows are promoted to cli during native restore so they can appear in the App sidebar;
    • root provider-prefixed routed model ids such as model = "opencode-go/minimax-m3" are stripped when restoring native Codex.

    Verification on the local machine:

    • repaired the broken local state by recovering 218 user history rows to openai;
    • verified zero remaining user rows with model_provider = "opencodex" after ocx stop;
    • verified config.toml has no opencodex provider refs and no root provider-prefixed model;
    • bun run typecheck passed;
    • bun test tests passed: 142 pass, 0 fail.
  9. lidge-jun commented on Jun 22, 2026

    @lidge-jun
    Owner

    Released in v2.1.6 via #20. The Codex App history compatibility work is now on main, including reversible history sync, native restore cleanup, and explicit legacy recovery handling. npm latest is @bitkyc08/opencodex@2.1.6.

  10. lidge-jun commented on Jun 22, 2026

    @lidge-jun
    Owner

    This should be covered by v2.1.6, released via #20. The fix now includes reversible resume-history sync, native restore cleanup for opencodex-owned rows, and explicit legacy recovery handling. If any history/sidebar visibility problem remains after upgrading to @bitkyc08/opencodex@2.1.6, please open a new follow-up issue with the exact start/stop steps, Codex App behavior, and whether syncResumeHistory is enabled.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions