Videos
I got the macOS Codex desktop app (.dmg) running on Ubuntu Linux — here’s the full technical breakdown
I recently experimented with running the macOS-only Codex desktop app on Ubuntu.
Since .dmg isn’t a native Linux package, there’s no direct install path — so I approached this as a cross-platform packaging, runtime, and deep debugging problem.
The core idea
Instead of trying to “install” the DMG, I built a bridge layer:
-
Extract the macOS Electron payload
-
Rebuild Linux-compatible native modules
-
Launch the UI on Linux
-
Correctly wire it to the modern Codex CLI backend
So the final architecture became:
-
UI runtime: Electron app from extracted
asar-unpacked -
Backend agent:
codex app-server(CLI) -
Bridge launcher: Linux script that sets env + connects UI → CLI
-
Config state:
~/.codex/config.tomlcontrolling default model + migrations
Step 1 — Preparing a runnable Linux payload
From the DMG:
-
Extracted the application bundle
-
Unpacked
app.asar→asar-unpacked -
Rebuilt required native Node modules for Linux ABI, notably:
-
better-sqlite3 -
node-pty
-
Without this rebuild, Electron crashed immediately on Ubuntu.
Step 2 — Creating a real Linux launcher
I created:
-
~/.local/bin/codex-dmg-linux→ launcher script -
Desktop entry under
~/.local/share/applications/
The launcher:
-
Reads payload location via
CODEX_DMG_WORKDIR -
Optionally overrides CLI via
CODEX_CLI_PATH -
Sets required env:
-
BUILD_FLAVOR=prod -
NODE_ENV=production -
renderer URL → local webview
-
-
Starts Electron with Linux-safe flags.
At this point, the UI launched successfully on Ubuntu.
Step 3 — The real failure: messages silently didn’t send
No UI errors.
But backend turns failed with:
model_not_found
So this became a runtime / backend investigation, not a UI issue.
Root cause — hidden CLI version skew
I discovered two Codex CLI installations:
-
New CLI → 0.98.0 (supports
gpt-5.3-codex) -
Old CLI → 0.94.0 (pulled in via extension / launcher path)
The desktop app was invoking the old CLI,
so the requested model didn’t exist → model_not_found.
Classic path-resolution / version-skew bug that looks like an account or server issue.
Final fix
-
Patched launcher to use the modern Linuxbrew CLI explicitly
-
/home/linuxbrew/.linuxbrew/bin/codex
-
-
Restored default model:
-
model = "gpt-5.3-codex"
-
-
Removed a migration rule that downgraded 5.3 → 5.2
Verification (end-to-end)
Confirmed correctness at multiple layers:
-
model/listshows gpt-5.3-codex -
Direct inference:codex exec --model gpt-5.3-codex "Reply with one word: ok" → returns
ok -
thread/startvia app-server reports:-
model = gpt-5.3-codex
-
cliVersion = 0.98.0
-
-
Running process confirmed from Linuxbrew path.
Warnings observed but non-blocking:
-
DBus UnitExists
-
Node
url.parsedeprecation -
MCP context provider failure
None affected chat functionality.
Open-source bridge (no proprietary binaries)
Repo:
https://github.com/Mina-Sayed/codex-dmg-linux-bridge
Includes:
-
Launcher script
-
Setup + troubleshooting docs
-
No DMG or proprietary binaries (downloaded separately from official source for licensing reasons).
Engineering time
Total time: ~1 hour 10 minutes.
What used to take days of low-level debugging
can now be compressed into minutes —
if you know how to properly drive AI agents and verify the system end-to-end.
Happy to answer questions or discuss Electron cross-platform quirks,
native module rebuilding, or Codex CLI runtime behavior.
I create a droplet with a ubuntu vps and terminal in for my normal claude code projects. I want to give Codex a try but can't seem to activate it without a browser as, unlike claude code, you can't paste in the activation code. Has anyone gotten around this? I don't want to use the API route, I want to use my ChatGPT account which appears to require a browser to do it.