Image: AI-generated illustration
Why does Codex CLI fail inside Shelly on Android, and what made it run? Shelly replaced the upstream musl binary with an Android-native build from the codex-termux fork, and paired it with a bundled Mozilla CA bundle and the fork's full TUI binary. The sections below cover where and why the upstream binary breaks, how the replacement is wired in, and which versions and limits apply.
Where does the upstream binary break, and why?
Codex CLI is a coding agent from OpenAI that runs locally on your computer [1]. It is written in Rust [3]. For Linux arm64, the GitHub Release asset is codex-aarch64-unknown-linux-musl.tar.gz. Each archive contains a single entry with the platform baked into the name, so the binary usually needs renaming to codex after extraction. The documented installation commands cover Mac or Linux and Windows [1]. As of July 2026, Codex CLI had builds for macOS, Linux and Windows, but not natively for Android [4].
That Linux build is where Android stops it. The upstream codex binary is ET_EXEC (musl, static), which cannot run on Android 14+ due to SELinux. Shelly's earlier proot approach failed. The working fix therefore swapped the binary itself rather than adding another layer around it, as the next section shows.
How does Shelly run the termux fork instead?
Commit 6ba1419a5, dated 2026-04-17 and filed under bug #76, downloads codex-termux's Android-native binary during the CI build. The source is github.com/DioNanos/codex-termux at v0.121.0-termux. At 110MB, the binary is fetched at build time rather than committed to git. On the device, LibExtractor extracts it to termux-libs/codex_exec. The shell setup changed in the same commit, with BASHRC_VERSION bumped to 24.
HTTPS was the second gap. Commit 6f0b4e164 on 2026-04-19 fixed "a class of silent HTTPS failures across every bundled TLS client". Its Mozilla cacert.pem is a 2026-02 snapshot that ships as an APK asset. The exported CA variables reach curl, node (fetch, undici, https), codex_exec rustls and python requests.
Login arrived with that same TLS change. Commit 6f0b4e164 also added codex-login device-auth, which unlocks Codex native on-device login. Upstream, running codex lets a user select Sign in with ChatGPT, and an API key works with additional setup [1]. For headless automation, an API key can be exported as OPENAI_API_KEY [2].
Interactive mode was the third gap. Running codex starts an interactive session, and a prompt can also be passed directly, as in codex "Explain the structure of this project". A third-party GitHub Actions example uses codex exec --full-auto "Update CHANGELOG for next release" [2]. On Shelly, bug #114 tracked the missing interactive mode, and acd13d5e6 fixed it on 2026-04-20. The codex-termux tarball holds codex-exec.bin (~106 MB), a 1-shot runner for exec/resume/review, and codex.bin (~154 MB). CI had copied only codex-exec.bin into jniLibs, so on-device codex was limited to 1-shot mode (codex exec "foo"). The fix changed .github/workflows/build-android.yml so that codex.bin is packaged as well.
The three fixes compare as follows:
| Aspect | Before | After |
|---|---|---|
| Binary type | ET_EXEC (musl, static) | ET_DYN, bionic-linked |
| Runtime layer | proot + libtalloc bundled in jniLibs | codex-termux binary placed as libcodex_exec.so in jniLibs |
| Launch path | ~/bin/proot wrapper for codex.js spawn() compatibility | sed patch replaces upstream binaryPath with linker64 + codex_exec |
Interactive codex | Bare codex or codex "prompt" would either fail or silently run exec mode | codex.bin provides the full ratatui TUI for the interactive REPL |
| TLS trust | Silent HTTPS failures across bundled TLS clients | Mozilla cacert.pem extracted to ~/.shelly-ssl/ca-certificates.crt on every launch |
Which versions and limits apply?
Shelly v5.0.0 dates from 2026-04-18, and v5.1.0 is the semver minor release on top of it. Build 769 (615dbed9) passed CI build run 25092606578. Installation and verification took place on a Galaxy Z Fold6 running Android 16.
The verified Codex commands in build 769 were a version check and a single prompt. codex --version returned codex-cli 0.125.0-termux. A one-prompt run, codex -m gpt-5.5 "Say OK", returned OK.
Hardware scope is narrow. All of Shelly's bundled native binaries are arm64-only. Commit 39dc291a1 on 2026-04-27 restricted the build to the arm64 ABI, noting that the 32-bit slice "wouldn't have worked anyway".
The 0.125.0-termux runtime arrives through a new npm-pack asset layout. Release ingestion accepts mmmbuto-codex-cli-termux-<version>.tgz and verifies it against npm dist.integrity before bundling or promoting. Runtime and npm updates are staged, integrity-checked, smoke-tested on-device, and promoted only after PASS. Under v5.1.0, a per-launch verified-latest update path means users no longer wait up to 24 h before a fix lands on their device.
Upstream releases move on a separate track. A third-party Codex CLI changelog lists v0.167.0, dated 2026-11-06, as the latest release [3]. Standalone installers download from https://releases.openai.com/codex by default and fall back to GitHub Releases if a metadata or asset download is unavailable. Setting CODEX_INSTALLER_USE_RELEASES_OPENAI_COM to false forces GitHub Releases, with 0 and no also accepted. The package-manager routes are npm install -g @openai/codex and brew install --cask codex [1].
Other approaches
Both alternatives below are compared on the same two points: where the binary runs, and whether the on-device compatibility problem goes away.
Cloud container. A cloud Linux container such as Cosyra pre-installs the CLI. Because the binary runs in that container, users reach it without on-device compatibility concerns. The work draws on cloud resources rather than a local runtime [4].
Upstream package under proot. Shelly's 2026-04-11 design in commit 9c68f866c shipped the @openai/codex package with a proot-patched codex.js on the phone itself. In that design, claude/gemini/codex updated daily in the background, with a fallback to the bundled versions. The compatibility problem stayed unsolved on the device: "Previous proot approach failed".
What to check
- Is a musl static Codex binary being launched on Android 14 or later? SELinux blocks it there, and Shelly's fix replaced it with codex-termux's Android-native build linked through linker64.
- Does bare
codexfail or quietly behave likecodex exec? Confirm that codex.bin is in the package, because with only codex-exec.bin copied into jniLibs, on-devicecodexstays in 1-shot mode. - Do curl, node fetch/undici or codex_exec rustls requests fail HTTPS silently? Check the CA configuration: Shelly exported SSL_CERT_FILE / SSL_CERT_DIR / CURL_CA_BUNDLE / NODE_EXTRA_CA_CERTS / REQUESTS_CA_BUNDLE alongside its bundled Mozilla cacert.pem.
- Is the device or APK slice 32-bit? Shelly's bundled native binaries, including the Codex runtime, target arm64 only.
- Is a downloaded Codex runtime promoted before it is verified? Shelly's ingestion checks the npm-pack tarball against npm
dist.integrityand smoke-tests on-device before promotion. - Do several panes or fast relaunches download Codex twice? Serialize runtime updates with a lock such as
~/.shelly-runtime/.update.lock. In a three-way forced updater test, one real updater ran and two exited immediately withdone (skipped, locked).
Sources
- [1] github.com
- [2] dev.to
- [3] ppcbasic.com
- [4] cosyra.com
- The author's own notes
AI disclosure: this post was researched, written and reviewed by AI tools.
Publishing: a post that passes automated checks may be published automatically, before the author reads it.


