You need:
python3,7zor7zz,curl,unzip,tar,make,g++- Rust toolchain with
cargoforcodex-update-manager,codex-computer-use-linux, the Chrome extension host binary, and optional Rust-backed features such as Read Aloud MCP and Record & Replay
The installer downloads a managed Linux Node.js runtime into
codex-app/resources/node-runtime and uses it for node, npm, and npx
during the build. Existing nvm, asdf, Volta, NodeSource, or nodejs.org
installs are fine, but no longer required for the generated app build. The
dependency helper may still install or validate a distro Node.js toolchain on
some bootstrap paths.
Bootstrap dependencies:
bash scripts/install-deps.shIt detects apt, dnf5, dnf, pacman, or zypper, installs system
packages, and bootstraps Rust through rustup when needed.
# Fedora 41+
sudo dnf install python3 7zip curl unzip tar rpm-build make gcc-c++ @development-tools
# Fedora < 41
sudo dnf install python3 p7zip p7zip-plugins curl unzip tar rpm-build make gcc-c++
sudo dnf groupinstall 'Development Tools'
# openSUSE
sudo zypper install python3 p7zip-full curl unzip tar
sudo zypper install -t pattern devel_basis
# Arch / Manjaro
sudo pacman -S --needed python p7zip curl unzip tar zstd base-devel
# Rust toolchain
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shOn apt-based systems, scripts/install-deps.sh can still bootstrap optional
NodeSource Node.js for users who want a system Node.js toolchain:
bash scripts/install-deps.sh
NODEJS_MAJOR=24 bash scripts/install-deps.shUbuntu-family p7zip-full can be too old for newer APFS DMGs, so
install-deps.sh bootstraps 7zz into ~/.local/bin by default.
make build-app
make build-app-fresh
make build-app DMG=/path/to/Codex.dmgEquivalent direct commands:
./install.sh
./install.sh /path/to/Codex.dmg
./install.sh --freshThe default path stores upstream DMG headers, plus a hash of the upstream URL,
next to Codex.dmg and refreshes the cached file when that upstream fingerprint
changes. Every command builds a sibling candidate and runs the shared
upstream DMG acceptance profile before replacing
codex-app/. A rejected or inconclusive candidate leaves the working app
unchanged. Acceptance checks only configured Linux Features and rejects drift
in any enabled feature; disable that feature before retrying if necessary.
Replacing an existing app uses an atomic directory exchange plus a recovery
journal, so interruption cannot leave the canonical install path missing. If
the filesystem does not support atomic exchange, promotion stops without
changing the working app.
--fresh still forces a cache removal before rebuilding, and an
explicit DMG=/path/to/Codex.dmg uses that file exactly.
Native install shortcuts use --fresh --reuse-dmg, so they build a clean
candidate while still reusing the cached DMG when upstream metadata matches.
For deterministic test rounds, set CODEX_DMG_REFRESH_MODE=pinned. Pinned mode
reuses the existing cached Codex.dmg verbatim, skips upstream metadata checks,
and fails instead of downloading when no cached DMG or explicit DMG=... path is
available. This also keeps --fresh from deleting the cached DMG.
Before accepting a fast-moving upstream DMG, run the report-only intelligence lane to inventory protected Sky/Chronicle/Skysight/Computer Use/Record & Replay surfaces:
make inspect-upstream DMG=/path/to/Codex.dmg
make inspect-upstream-intel-devcontainerThe devcontainer intelligence target downloads the current upstream DMG into
reports/upstream-dmg/downloads/ when DMG=... is omitted and automatically
compares it against repo ./Codex.dmg when that cached baseline exists.
For an already downloaded candidate, pass only that one path:
make inspect-upstream-intel-devcontainer DMG=/path/to/new/Codex.dmgSee docs/upstream-dmg-intelligence.md for the protected-surface registry,
JSON/Markdown report outputs, and fixture-based test strategy.
Run the generated app:
make run-app
./codex-app/start.shBy default, second launches reuse the running app through the Linux warm-start handoff.
Open an independent app process:
./codex-app/start.sh --new-instanceConfigure the port range or make every launch use multi-instance mode:
CODEX_MULTI_LAUNCH_PORT_RANGE=5175-5199 ./codex-app/start.sh --new-instance
CODEX_MULTI_LAUNCH=1 CODEX_MULTI_LAUNCH_PORT_RANGE=5175-5199 ./codex-app/start.shAfter make build-app or make build-app-fresh, build a package from
codex-app/:
| Format | Build command | Output | Install |
|---|---|---|---|
| Debian | make deb |
dist/codex-desktop_*.deb |
sudo dpkg -i dist/codex-desktop_*.deb |
| RPM | make rpm |
dist/codex-desktop-*.x86_64.rpm |
sudo dnf install dist/codex-desktop-*.rpm or sudo zypper install dist/codex-desktop-*.rpm |
| Arch | make pacman |
dist/codex-desktop-*.pkg.tar.zst |
sudo pacman -U dist/codex-desktop-*.pkg.tar.zst |
| AppImage | make appimage |
dist/codex-desktop-*.AppImage |
Run directly |
| Auto-detect | make package && make install |
matches host distro | handled by make install |
Override package version:
PACKAGE_VERSION=2026.03.24.220723+88f07cd3 make debThe packaging scripts only repackage what is already in codex-app/; they do
not download or extract the DMG.
make build-app
make appimage
./dist/codex-desktop-*.AppImageThe AppImage flow does not include codex-update-manager, the systemd user
service, polkit policy, or the native-package update builder.
To make a local AppImage self-contained, install the CLI with its optional Linux package and pass the package directory to the AppImage build:
cli_prefix="$HOME/.cache/codex-desktop-linux/appimage-cli"
npm install --prefix "$cli_prefix" --include=optional @openai/codex
CODEX_CLI_BUNDLE_SOURCE="$cli_prefix/node_modules/@openai/codex" make appimageThe build copies only @openai/codex and the matching Linux architecture
package on x86-64 and ARM64. It does not fetch packages itself. The bundled CLI
is used when CODEX_CLI_PATH is unset and takes precedence over a host
installation. This adds the native CLI payload to the AppImage, which is several
hundred MiB for current releases. Rebuild the AppImage when you want to update
the embedded CLI.
When upstream ChatGPT Desktop changes:
git pull --ff-only
make build-app-fresh
make appimageAppImage builds require appimagetool on PATH, or:
APPIMAGETOOL=/path/to/appimagetool make appimageIf runtime downloads from GitHub are slow or blocked:
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ make build-appELECTRON_HEADERS_URL is passed to @electron/rebuild --dist-url and must
provide both node-v<version>-headers.tar.gz and the matching SHASUMS256.txt.
MAX_BUILD_THREADS=8 make build-app-fresh
MAX_BUILD_THREADS=8 make package
MAX_BUILD_THREADS=8 make install-nativeMAX_BUILD_THREADS=0 is the default and preserves each tool's automatic
behavior. A nonzero value controls Cargo jobs, native module rebuild jobs,
Debian package compression, pacman package compression, and RPM zstd payload
compression.
Run:
make helpCommon targets:
make check
make test
make build-updater
make build-app
make build-app-fresh
make bootstrap-native
make install-native
make update-native
make run-app
make build-dev-app
make run-dev-app
make deb
make rpm
make pacman
make appimage
make package
make install
make service-enable
make service-status
make clean-dist
make clean-state