Summary
ensureFirstRunSetup can bind the real ~/.codex/config.toml to the runtime proxy (model_provider = "codex-multi-auth-runtime-proxy" + a [model_providers.codex-multi-auth-runtime-proxy] block) and then end up in a state where the app-bind state/backup files no longer exist. When that happens:
- The config is left pointing at a runtime-proxy
base_url (e.g. http://127.0.0.1:51758) with no router running, so the official codex CLI/Desktop is routed to a dead port.
codex-multi-auth rotation unbind-app reports "Codex app bind was not configured" and does nothing, because unbindCodexAppRuntimeRotationLocked keys restoration off app-bind/runtime-rotation-app-bind.json / codex-config-backup.json, which are gone.
rotation status reports "Codex app bind: not configured" and "Runtime rotation proxy: disabled", even though the real config is still bound — so the user gets no signal that their config is broken, and no automated way to fix it.
Net effect: the user's normal Codex usage breaks (wrong provider, dead port), and ironically codex resume history is hidden under the proxy provider — the exact symptom #612 was about. The only recovery is hand-editing config.toml.
Observed on
codex-multi-auth@2.3.1 (global install), Windows 11, Node 24.
- Reproduced incidentally while exercising the CLI: a first CLI invocation against a machine whose
first-run-setup.json marker was not yet set triggered the lazy bind; the app-bind state dir (~/.codex/multi-auth/app-bind/) contained only an empty runtime-rotation-app-router.log — no runtime-rotation-app-bind.json / codex-config-backup.json.
Resulting real config (abridged):
model_provider = "codex-multi-auth-runtime-proxy"
...
[model_providers.codex-multi-auth-runtime-proxy]
name = "codex-multi-auth"
base_url = "http://127.0.0.1:51758"
requires_openai_auth = false
experimental_bearer_token = "…"
wire_api = "responses"
rotation status simultaneously: Runtime rotation proxy: disabled / Codex app bind: not configured.
Why it's a gap
There are two independent robustness problems, either of which alone would prevent silent breakage:
-
No restorable backup guarantee. bindCodexAppRuntimeRotationLocked writes backupPath before rewriting config.toml, but the backup and state can later be removed (cleanup, partial unbind, manual deletion, crash) while the rewritten config persists. There is no "the config is bound" fact stored in a place that survives state-file loss.
-
Status/unbind trust the state files, not the config. Both getAppBindStatus and unbind-app infer "bound" purely from app-bind/*.json. When those are missing they conclude "not configured" even though config.toml literally contains the runtime-proxy model_provider + provider block. So the one command meant to fix it is a no-op exactly when it's needed.
Suggested fixes (pick some)
- Self-healing unbind: if
config.toml's top-level model_provider === codex-multi-auth-runtime-proxy (or the proxy [model_providers.…] block is present), unbind-app should restore it even with no backup — restoreConfigTomlFromRuntimeRotationProvider can already strip the block; for the top-level provider, fall back to "openai" (or a configurable default) when no backup line exists.
- Status truth from config:
getAppBindStatus / rotation status should detect a bound config directly (scan config.toml) and report "bound but unmanaged (no state/backup)" instead of "not configured", so the breakage is visible.
doctor check + fix: add a doctor probe that flags "config.toml points at runtime proxy but no router/state" and offers --fix to unbind.
- Harden bind durability: treat a successful bind as not-complete until the backup is fsynced and re-readable; consider an idempotent marker in
config.toml (a comment sentinel) so even total state loss is recoverable.
Workaround (for affected users today)
Manually edit ~/.codex/config.toml: set model_provider = "openai" and delete the [model_providers.codex-multi-auth-runtime-proxy] block. (Back up the file first.)
Notes
Summary
ensureFirstRunSetupcan bind the real~/.codex/config.tomlto the runtime proxy (model_provider = "codex-multi-auth-runtime-proxy"+ a[model_providers.codex-multi-auth-runtime-proxy]block) and then end up in a state where the app-bind state/backup files no longer exist. When that happens:base_url(e.g.http://127.0.0.1:51758) with no router running, so the officialcodexCLI/Desktop is routed to a dead port.codex-multi-auth rotation unbind-appreports "Codex app bind was not configured" and does nothing, becauseunbindCodexAppRuntimeRotationLockedkeys restoration offapp-bind/runtime-rotation-app-bind.json/codex-config-backup.json, which are gone.rotation statusreports "Codex app bind: not configured" and "Runtime rotation proxy: disabled", even though the real config is still bound — so the user gets no signal that their config is broken, and no automated way to fix it.Net effect: the user's normal Codex usage breaks (wrong provider, dead port), and ironically
codex resumehistory is hidden under the proxy provider — the exact symptom #612 was about. The only recovery is hand-editingconfig.toml.Observed on
codex-multi-auth@2.3.1(global install), Windows 11, Node 24.first-run-setup.jsonmarker was not yet set triggered the lazy bind; the app-bind state dir (~/.codex/multi-auth/app-bind/) contained only an emptyruntime-rotation-app-router.log— noruntime-rotation-app-bind.json/codex-config-backup.json.Resulting real config (abridged):
rotation statussimultaneously:Runtime rotation proxy: disabled/Codex app bind: not configured.Why it's a gap
There are two independent robustness problems, either of which alone would prevent silent breakage:
No restorable backup guarantee.
bindCodexAppRuntimeRotationLockedwritesbackupPathbefore rewritingconfig.toml, but the backup and state can later be removed (cleanup, partial unbind, manual deletion, crash) while the rewritten config persists. There is no "the config is bound" fact stored in a place that survives state-file loss.Status/unbind trust the state files, not the config. Both
getAppBindStatusandunbind-appinfer "bound" purely fromapp-bind/*.json. When those are missing they conclude "not configured" even thoughconfig.tomlliterally contains the runtime-proxymodel_provider+ provider block. So the one command meant to fix it is a no-op exactly when it's needed.Suggested fixes (pick some)
config.toml's top-levelmodel_provider === codex-multi-auth-runtime-proxy(or the proxy[model_providers.…]block is present),unbind-appshould restore it even with no backup —restoreConfigTomlFromRuntimeRotationProvidercan already strip the block; for the top-level provider, fall back to"openai"(or a configurable default) when no backup line exists.getAppBindStatus/rotation statusshould detect a bound config directly (scanconfig.toml) and report "bound but unmanaged (no state/backup)" instead of "not configured", so the breakage is visible.doctorcheck + fix: add a doctor probe that flags "config.toml points at runtime proxy but no router/state" and offers--fixto unbind.config.toml(a comment sentinel) so even total state loss is recoverable.Workaround (for affected users today)
Manually edit
~/.codex/config.toml: setmodel_provider = "openai"and delete the[model_providers.codex-multi-auth-runtime-proxy]block. (Back up the file first.)Notes
historycommand (feat(history): add provider-agnostic local session browser (#612) #613) — that command is read-only. This is in the first-run / app-bind path.docs/troubleshooting.mdrow "Codex history disappears after app bind" assumesunbind-app/disablework; they don't in this no-backup state.