Tools: Latest: How I repackaged the official Windows Codex MSIX into a working Linux .deb

Tools: Latest: How I repackaged the official Windows Codex MSIX into a working Linux .deb

The Goal

What I started with

The obvious approach

Problem 1: the Windows bundle was not actually Linux-ready

Problem 2: getting the app to "launch" was not the same as getting it to work

Problem 3: Electron GPU startup was fatal on Linux

The pivot: stop trying to preserve the original runtime shell

What the final wrapper does

Packaging details that mattered

1. The app had to present itself as Codex

2. Desktop entry details mattered

3. Old install leftovers had to be cleaned up explicitly

Making the build self-contained

The build flow now

The result

What I learned

If you want to try it

Closing thought

If you want to try it

Closing thought I wanted a real Linux desktop app for Codex. At first, this looked like it should be straightforward: take the official Windows package, unpack it, swap in Linux Electron, rebuild whatever was platform-specific, and turn it into a .deb. That is not what happened. What actually worked was more pragmatic: preserve the official Codex payload, branding, and resources from the Windows MSIX, but replace the runtime shell with a small Linux Electron wrapper that opens Codex in its own desktop window. This post is the write-up I wish I had before I started. The target was simple: I already had something similar working for ChatGPT, so I assumed Codex would follow the same path. That assumption was wrong. The source payload was the official Windows MSIX: The repo I ended up with is here: The main build script is: The first plan was the normal "repackage the Electron app" playbook: In theory, that should have produced a Linux .deb built directly from the original app bundle. In practice, it failed in multiple different ways. The Codex payload included resources and binaries that looked promising, but the packaged app still carried Windows assumptions. The biggest issue was native modules. At one point I confirmed the app was dying because a native dependency was still Windows-built: That is the classic sign that Linux is trying to load a binary module compiled for the wrong platform. So the next move was to rebuild native modules for Linux and wire them back into the extracted app. That still did not get me to a usable app window. I got as far as installing the package cleanly and starting Electron on Linux. That was progress, but not enough. The app process would launch and then exit without showing a window, or fail during startup after getting past the first set of issues. This is one of the most annoying parts of Electron packaging work: "the binary started" sounds good, but it does not mean the app is actually viable. Once I simplified the runtime enough to observe the real failure clearly, the next blocker showed up: That changed the direction of the fix immediately. Instead of trying to preserve every part of the original desktop behavior, I needed a Linux-friendly launcher path that was stable in the actual Ubuntu session I was using. The fix was to disable GPU at both levels: The final launcher executes Electron like this: That was not elegant, but it was effective. This was the real turning point. Instead of continuing to patch the original Windows desktop runtime deeper and deeper, I switched to a simpler architecture: That approach still let me build from the official Windows MSIX, but it stopped me from getting trapped in the least portable parts of the original runtime. The generated wrapper app is very small. The wrapper also supports overriding the URL with an environment variable: That is useful if the endpoint ever changes or if you want a staging/test flow. There were a few packaging details that turned out to be more important than I expected. I renamed the Linux Electron binary from electron to Codex so the app identity looked correct on Linux. That helped with launcher behavior and window class handling. The .desktop file sets: Without that, you can end up with weird launcher grouping or desktop integration issues. Earlier experiments left behind app.asar.unpacked content from previous versions. Even after the packaging approach changed, those leftovers could survive upgrades and create confusing behavior. So I added a preinst cleanup step to the package: That made upgrades deterministic again. At first I was borrowing tools from another workspace, which worked but was brittle. I cleaned that up by making the project self-contained with local dev dependencies: That way the repo can be built with: instead of depending on some other directory on disk having the right binaries in it. The working build pipeline looks like this: The helper script for rebuild and reinstall is: The final output is a package like this: And the user-facing launch command is simply: Most importantly: it actually opens, stays up, and works as a desktop app on Ubuntu. The biggest lesson from this project is that "porting" is sometimes the wrong framing. I went in thinking I needed to preserve the original Windows desktop runtime as faithfully as possible. What I really needed was: Once I optimized for that instead of purity, the solution got much simpler. That tradeoff is worth stating directly: the final app is absolutely built from the official Windows MSIX, but it is not a perfect binary carryover of the original runtime. It is a Linux-native wrapper around the official Codex experience, using the original payload where it helps and replacing the parts that did not survive the platform jump well. That was the right call. A lot of cross-platform packaging work looks like a debugging problem, but the real work is architectural judgment. You have to decide when to keep forcing the original design, and when to admit that a thinner, more native solution is the thing that will actually ship. This project only started working once I made that call. Once I optimized for that instead of purity, the solution got much simpler. That tradeoff is worth stating directly: the final app is absolutely built from the official Windows MSIX, but it is not a perfect binary carryover of the original runtime. It is a Linux-native wrapper around the official Codex experience, using the original payload where it helps and replacing the parts that did not survive the platform jump well. That was the right call. A lot of cross-platform packaging work looks like a debugging problem, but the real work is architectural judgment. You have to decide when to keep forcing the original design, and when to admit that a thinner, more native solution is the thing that will actually ship. This project only started working once I made that call. Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Code Block

Copy

OpenAI.Codex_26.313.5234.0_x64__2p2nqsd0c76g0.Msix OpenAI.Codex_26.313.5234.0_x64__2p2nqsd0c76g0.Msix OpenAI.Codex_26.313.5234.0_x64__2p2nqsd0c76g0.Msix [email protected]:johnohhh1/codex-ubuntu.git [email protected]:johnohhh1/codex-ubuntu.git [email protected]:johnohhh1/codex-ubuntu.git ./build-codex-native-deb.sh ./build-codex-native-deb.sh ./build-codex-native-deb.sh invalid ELF header invalid ELF header invalid ELF header FATAL: GPU process isn't usable. Goodbye. FATAL: GPU process isn't usable. Goodbye. FATAL: GPU process isn't usable. Goodbye. exec /opt/codex-desktop-native/electron/Codex \ --no-sandbox \ --disable-setuid-sandbox \ --disable-gpu \ --disable-gpu-compositing "$@" exec /opt/codex-desktop-native/electron/Codex \ --no-sandbox \ --disable-setuid-sandbox \ --disable-gpu \ --disable-gpu-compositing "$@" exec /opt/codex-desktop-native/electron/Codex \ --no-sandbox \ --disable-setuid-sandbox \ --disable-gpu \ --disable-gpu-compositing "$@" CODEX_WEB_URL=https://chatgpt.com/codex codex-desktop-native CODEX_WEB_URL=https://chatgpt.com/codex codex-desktop-native CODEX_WEB_URL=https://chatgpt.com/codex codex-desktop-native rm -rf "/opt/codex-desktop-native/electron/resources/app.asar.unpacked" rm -rf "/opt/codex-desktop-native/electron/resources/app.asar.unpacked" rm -rf "/opt/codex-desktop-native/electron/resources/app.asar.unpacked" { "devDependencies": { "asar": "^3.2.0", "electron": "^40.0.0" } } { "devDependencies": { "asar": "^3.2.0", "electron": "^40.0.0" } } { "devDependencies": { "asar": "^3.2.0", "electron": "^40.0.0" } } npm install ./rebuild-install.sh npm install ./rebuild-install.sh npm install ./rebuild-install.sh ./rebuild-install.sh ./rebuild-install.sh ./rebuild-install.sh dist/codex-desktop-native_26.313.5234.0_amd64.deb dist/codex-desktop-native_26.313.5234.0_amd64.deb dist/codex-desktop-native_26.313.5234.0_amd64.deb codex-desktop-native codex-desktop-native codex-desktop-native [email protected]:johnohhh1/codex-ubuntu.git [email protected]:johnohhh1/codex-ubuntu.git [email protected]:johnohhh1/codex-ubuntu.git git clone [email protected]:johnohhh1/codex-ubuntu.git cd codex-ubuntu npm install ./rebuild-install.sh codex-desktop-native git clone [email protected]:johnohhh1/codex-ubuntu.git cd codex-ubuntu npm install ./rebuild-install.sh codex-desktop-native git clone [email protected]:johnohhh1/codex-ubuntu.git cd codex-ubuntu npm install ./rebuild-install.sh codex-desktop-native [email protected]:johnohhh1/codex-ubuntu.git [email protected]:johnohhh1/codex-ubuntu.git [email protected]:johnohhh1/codex-ubuntu.git git clone [email protected]:johnohhh1/codex-ubuntu.git cd codex-ubuntu npm install ./rebuild-install.sh codex-desktop-native git clone [email protected]:johnohhh1/codex-ubuntu.git cd codex-ubuntu npm install ./rebuild-install.sh codex-desktop-native git clone [email protected]:johnohhh1/codex-ubuntu.git cd codex-ubuntu npm install ./rebuild-install.sh codex-desktop-native - install Codex on Ubuntu as a .deb - get a desktop launcher and icon - make it feel like a native app - avoid relying on a browser tab - keep the build repeatable - Extract the MSIX. - Grab the bundled app.asar. - Swap the Windows Electron runtime for Linux Electron. - Rebuild or replace native modules. - Repackage everything into a .deb. - in the Electron app itself with command-line switches - in the launcher wrapper used by the packaged .deb - use Linux Electron as the runtime - keep the official Codex assets from the MSIX - build a tiny Linux wrapper app - load https://chatgpt.com/codex inside a dedicated desktop window - creates a BrowserWindow - hides the menu bar - uses a Codex title and icon - opens external popups in the default browser - allows normal http and https navigation - forces the window to show even if page paint is slow - points at https://chatgpt.com/codex by default - Exec=codex-desktop-native - Icon=codex-desktop-native - StartupWMClass=Codex - X-GNOME-WMClass=Codex - Validate the MSIX input. - Extract the package and detect its version from AppxManifest.xml. - Copy the official assets into a staging directory. - Copy in Linux Electron. - Replace the original runtime shell with a generated Linux wrapper app.asar. - Build a .deb with the desktop entry, icon, launcher script, and package hooks. - a reliable Linux package - a clean desktop launcher - Codex in its own app window - a build process I could rerun later - a build process I could rerun later