Client or integration
Codex App (and Codex CLI)
Version
2.21.0 (npm, @bitkyc08/opencodex)
Operating system
macOS 15.7.9 (build 24G830), Apple Silicon (arm64); Codex desktop app 151.0.7922.137
Area
Service lifecycle (ocx stop / ocx restore), Catalog / models
Summary
ocx stop (and ocx restore) leave the injected routing in place when the Codex app rewrote ~/.codex/config.toml after injection: the root key openai_base_url = "http://127.0.0.1:10100/v1" and [features] fast_mode = true stay in the config, and the proxy-routed models_cache.json is not restored. Result: plain Codex keeps sending every request to a dead 127.0.0.1:10100 and all messages fail with connection refused, while the model picker still lists proxy-routed models (e.g. opencode-go/deepseek-v4-flash, qwen-cloud/...) and gpt-5.3-codex is replaced by gpt-5.3-codex-spark.
Expected: ocx stop / ocx restore remove all injected routing (including an unmarked root openai_base_url) and restore the native models_cache.json from the catalog backup, so plain Codex works with no manual cleanup.
Reproduction
Environment: macOS (darwin arm64), opencodex 2.21.0 (npm), Codex desktop app 151.0.7922.137. Loopback routing (Design B: built-in openai_base_url override).
ocx start → ~/.codex/config.toml gets openai_base_url = "http://127.0.0.1:10100/v1" (root) and [features] fast_mode = true. ~/.codex/opencodex-journal.json records originalConfig + injectedConfigHash.
- Open the Codex desktop app and change the model (or any setting). The app rewrites
~/.codex/config.toml, so sha256(config.toml) no longer equals injectedConfigHash and the model value differs from the injected snapshot.
- Run
ocx stop. The service/proxy stop cleanly, but the config and cache are left injected:
restoreJournalState() skips the journal restore because the config changed since injection (configUnchanged is false).
- The fallback
removeCodexConfig() reports "opencodex not present in Codex config." and removes nothing, because hasInjectedOpenaiBaseUrl() (injected-marker.ts) only detects openai_base_url when the line directly above it contains the # Auto-injected by opencodex marker — in this state the key is unmarked.
ocx restore behaves identically: prints ✅ opencodex not present in Codex config. / Codex integration is OFF..., but neither removes the routing line nor restores models_cache.json.
- Result:
curl http://127.0.0.1:10100/v1/models → connection refused; every Codex message fails.
Logs or error output
$ ocx restore
✅ opencodex not present in Codex config.
Codex integration is OFF and plain `codex` now runs natively. Switch back with: ocx restore back
$ curl -s -m 3 -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:10100/v1/models
HTTP 000
# models_cache.json after restore (still proxy-written; metadata untouched):
client_version: 0.0.0 fetched_at: 2000-01-01T00:00:00Z
models: gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-5.4-mini,
gpt-5.3-codex-spark, alibaba-token-plan-intl/deepseek-v4-flash-0731,
alibaba-token-plan-intl/qwen3.8-max, nous-portal/qwen-qwen3.8-27b,
opencode-free/deepseek-v4-flash-free, opencode-go/deepseek-v4-flash,
opencode-go/glm-5.3, opencode-go/grok-4.6, qwen-cloud/deepseek-v4-flash-0731,
qwen-cloud/deepseek-v4-pro-0813
Observations / possible causes
- The journal restore only fires when the config is byte-identical to the injected snapshot; a normal app rewrite defeats it. Consider stripping known injected root keys (
openai_base_url, model_catalog_json, and fast_mode under [features]) even without the marker comment, or always writing the marker line on inject.
- The catalog restore (
restoreCodexCatalogArtifact → restoreCodexCatalogWithPermit → readCatalogBackup) was a no-op here: the hash-named backup for models_cache.json (~/.opencodex/catalog-backup-<sha256(path)>.json) does not exist, and the legacy ~/.opencodex/catalog-backup.json was not applied. Observed behavior: models_cache.json untouched after ocx restore. I could not determine from outside whether the catalog step resolved a different path or was skipped; models_cache.json was restored manually from the legacy backup.
- Related:
ocx stop leaves the Codex CLI autostart shim installed; the next codex CLI invocation runs ocx ensure, which restarts the proxy and re-injects. If that is intended, a warning would help, since ocx stop's contract is "plain codex works again".
Workaround applied
Manually removed openai_base_url and [features] fast_mode from ~/.codex/config.toml, restored ~/.codex/models_cache.json from ~/.opencodex/catalog-backup.json, ran ocx codex-shim uninstall, and restarted the Codex app. Verified working afterward.
Checks
Client or integration
Codex App (and Codex CLI)
Version
2.21.0 (npm, @bitkyc08/opencodex)
Operating system
macOS 15.7.9 (build 24G830), Apple Silicon (arm64); Codex desktop app 151.0.7922.137
Area
Service lifecycle (
ocx stop/ocx restore), Catalog / modelsSummary
ocx stop(andocx restore) leave the injected routing in place when the Codex app rewrote~/.codex/config.tomlafter injection: the root keyopenai_base_url = "http://127.0.0.1:10100/v1"and[features] fast_mode = truestay in the config, and the proxy-routedmodels_cache.jsonis not restored. Result: plain Codex keeps sending every request to a dead127.0.0.1:10100and all messages fail with connection refused, while the model picker still lists proxy-routed models (e.g.opencode-go/deepseek-v4-flash,qwen-cloud/...) andgpt-5.3-codexis replaced bygpt-5.3-codex-spark.Expected:
ocx stop/ocx restoreremove all injected routing (including an unmarked rootopenai_base_url) and restore the nativemodels_cache.jsonfrom the catalog backup, so plain Codex works with no manual cleanup.Reproduction
Environment: macOS (darwin arm64), opencodex 2.21.0 (npm), Codex desktop app 151.0.7922.137. Loopback routing (Design B: built-in
openai_base_urloverride).ocx start→~/.codex/config.tomlgetsopenai_base_url = "http://127.0.0.1:10100/v1"(root) and[features] fast_mode = true.~/.codex/opencodex-journal.jsonrecordsoriginalConfig+injectedConfigHash.~/.codex/config.toml, sosha256(config.toml)no longer equalsinjectedConfigHashand themodelvalue differs from the injected snapshot.ocx stop. The service/proxy stop cleanly, but the config and cache are left injected:restoreJournalState()skips the journal restore because the config changed since injection (configUnchangedis false).removeCodexConfig()reports "opencodex not present in Codex config." and removes nothing, becausehasInjectedOpenaiBaseUrl()(injected-marker.ts) only detectsopenai_base_urlwhen the line directly above it contains the# Auto-injected by opencodexmarker — in this state the key is unmarked.ocx restorebehaves identically: prints✅ opencodex not present in Codex config./Codex integration is OFF..., but neither removes the routing line nor restoresmodels_cache.json.curl http://127.0.0.1:10100/v1/models→ connection refused; every Codex message fails.Logs or error output
Observations / possible causes
openai_base_url,model_catalog_json, andfast_modeunder[features]) even without the marker comment, or always writing the marker line on inject.restoreCodexCatalogArtifact→restoreCodexCatalogWithPermit→readCatalogBackup) was a no-op here: the hash-named backup formodels_cache.json(~/.opencodex/catalog-backup-<sha256(path)>.json) does not exist, and the legacy~/.opencodex/catalog-backup.jsonwas not applied. Observed behavior:models_cache.jsonuntouched afterocx restore. I could not determine from outside whether the catalog step resolved a different path or was skipped;models_cache.jsonwas restored manually from the legacy backup.ocx stopleaves the Codex CLI autostart shim installed; the nextcodexCLI invocation runsocx ensure, which restarts the proxy and re-injects. If that is intended, a warning would help, sinceocx stop's contract is "plain codex works again".Workaround applied
Manually removed
openai_base_urland[features] fast_modefrom~/.codex/config.toml, restored~/.codex/models_cache.jsonfrom~/.opencodex/catalog-backup.json, ranocx codex-shim uninstall, and restarted the Codex app. Verified working afterward.Checks