Symptom
After running ucode codex (or ucode configure) on a machine where an earlier ucode version had deep-merged its provider into the shared ~/.codex/config.toml, every bare codex invocation — including the Codex desktop app, which only reads ~/.codex/config.toml — dies immediately with:
Error: Model provider `ucode-databricks` not found
Root cause
The modern-layout migration removes ucode's provider block from the shared config but leaves the top-level model_provider key that points at it:
_remove_legacy_ucode_profile() fires whenever _has_legacy_ucode_entries sees [model_providers.ucode-databricks] in ~/.codex/config.toml.
_strip_legacy_ucode_entries() pops profile, profiles.ucode, and model_providers.ucode-databricks — but not the top-level model_provider = "ucode-databricks" selector.
The model_provider key at top level is exactly what older ucode wrote via MANAGED_KEYS (codex.py#L46-L51 — note ["model_provider"] is the first managed key), and it's also what the Codex desktop app persists when the user has been routing through the gateway. After the strip, the config references a provider that no longer exists, and codex refuses to start rather than falling back.
Repro
- Start with a
~/.codex/config.toml containing (modern shape, no profile selector — this is what a desktop-app user routing through the gateway has):
model_provider = "ucode-databricks"
model = "gpt-5.6-sol"
[model_providers.ucode-databricks]
name = "Databricks AI Gateway"
base_url = "https://<workspace>.cloud.databricks.com/ai-gateway/codex/v1"
wire_api = "responses"
[model_providers.ucode-databricks.auth]
command = "/Users/<user>/.local/bin/ucode"
args = ["auth-token", "--host", "https://<workspace>.cloud.databricks.com", "--profile", "DEFAULT"]
codex exec "say hi" works.
- Run
ucode codex -- exec "say hi" — works (uses ~/.codex/ucode.config.toml), but as a side effect strips [model_providers.ucode-databricks] from ~/.codex/config.toml, leaving model_provider = "ucode-databricks" dangling.
- Run bare
codex exec "say hi" again → Error: Model provider 'ucode-databricks' not found. The desktop app is equally broken until the block is re-added by hand.
Observed with ucode v0.1.0 (installed 2026-07-12 from this repo) and Codex 0.143.0-alpha.33 / 0.144.2 on macOS.
Suggested fix
In _strip_legacy_ucode_entries, also pop the top-level selector when it points at the stripped provider:
if doc.get("model_provider") == CODEX_MODEL_PROVIDER_NAME:
doc.pop("model_provider", None)
changed = True
(and probably the managed model key alongside it, mirroring MANAGED_KEYS). Alternatively, skip the strip entirely when the file has no profile/profiles.ucode selector — a top-level model_provider + provider block is a working modern config the user may be relying on for the desktop app, not legacy cruft.
Related: #148 covers ucode revert not undoing the legacy in-place edits; this is the inverse problem — the automatic cleanup undoing them partially and leaving the config broken.
Symptom
After running
ucode codex(orucode configure) on a machine where an earlier ucode version had deep-merged its provider into the shared~/.codex/config.toml, every barecodexinvocation — including the Codex desktop app, which only reads~/.codex/config.toml— dies immediately with:Root cause
The modern-layout migration removes ucode's provider block from the shared config but leaves the top-level
model_providerkey that points at it:_remove_legacy_ucode_profile()fires whenever_has_legacy_ucode_entriessees[model_providers.ucode-databricks]in~/.codex/config.toml._strip_legacy_ucode_entries()popsprofile,profiles.ucode, andmodel_providers.ucode-databricks— but not the top-levelmodel_provider = "ucode-databricks"selector.The
model_providerkey at top level is exactly what older ucode wrote viaMANAGED_KEYS(codex.py#L46-L51 — note["model_provider"]is the first managed key), and it's also what the Codex desktop app persists when the user has been routing through the gateway. After the strip, the config references a provider that no longer exists, and codex refuses to start rather than falling back.Repro
~/.codex/config.tomlcontaining (modern shape, noprofileselector — this is what a desktop-app user routing through the gateway has):codex exec "say hi"works.ucode codex -- exec "say hi"— works (uses~/.codex/ucode.config.toml), but as a side effect strips[model_providers.ucode-databricks]from~/.codex/config.toml, leavingmodel_provider = "ucode-databricks"dangling.codex exec "say hi"again →Error: Model provider 'ucode-databricks' not found. The desktop app is equally broken until the block is re-added by hand.Observed with ucode v0.1.0 (installed 2026-07-12 from this repo) and Codex 0.143.0-alpha.33 / 0.144.2 on macOS.
Suggested fix
In
_strip_legacy_ucode_entries, also pop the top-level selector when it points at the stripped provider:(and probably the managed
modelkey alongside it, mirroringMANAGED_KEYS). Alternatively, skip the strip entirely when the file has noprofile/profiles.ucodeselector — a top-levelmodel_provider+ provider block is a working modern config the user may be relying on for the desktop app, not legacy cruft.Related: #148 covers
ucode revertnot undoing the legacy in-place edits; this is the inverse problem — the automatic cleanup undoing them partially and leaving the config broken.