This document describes the release pipeline defined in .github/workflows/rust-release.yml that builds, signs, and publishes Codex binaries for all supported platforms. The pipeline is triggered by pushing a version tag and orchestrates multi-platform builds, platform-specific code signing, artifact compression, GitHub release creation, and npm package publishing.
For information about continuous integration testing, see CI Pipeline. For details on distribution channels (GitHub Releases, npm, Homebrew), see Distribution Channels. For the separate shell-tool-mcp build process, see Shell Tool MCP Build System.
The release pipeline is triggered by pushing a Git tag that matches the pattern rust-v*.*.*:
The tag-check job validates that the tag format is correct and matches the version declared in codex-rs/Cargo.toml Accepted tag formats:
rust-v1.2.3rust-v1.2.3-alpha.N.github/workflows/rust-release.yml19-46 extracts the version from the tag, reads the version from Cargo.toml, and fails the workflow if they don't match. This prevents accidental releases with mismatched versions.
Sources: .github/workflows/rust-release.yml1-46
Diagram: Release Pipeline Job Graph
The pipeline uses concurrent builds for all platforms, then gates the final release assembly on all builds completing successfully. The npm publish job is conditional on version format (stable or alpha only).
Sources: .github/workflows/rust-release.yml48-635
The build job uses a matrix strategy to build binaries for 6 platform/libc combinations in parallel:
| Runner | Target | libc | LTO Mode |
|---|---|---|---|
macos-15-xlarge | aarch64-apple-darwin | system | Conditional |
macos-15-xlarge | x86_64-apple-darwin | system | Conditional |
ubuntu-24.04 | x86_64-unknown-linux-musl | musl | Conditional |
ubuntu-24.04 | x86_64-unknown-linux-gnu | glibc | Conditional |
ubuntu-24.04-arm | aarch64-unknown-linux-musl | musl | Conditional |
ubuntu-24.04-arm | aarch64-unknown-linux-gnu | glibc | Conditional |
Windows builds are handled by a separate reusable workflow .github/workflows/rust-release-windows.yml that builds 2 targets (x86_64-pc-windows-msvc, aarch64-pc-windows-msvc).
.github/workflows/rust-release.yml60 sets CARGO_PROFILE_RELEASE_LTO based on whether the tag contains -alpha: alpha releases use thin LTO for faster builds, while stable releases use fat LTO for maximum optimization.
Sources: .github/workflows/rust-release.yml48-92 .github/workflows/rust-release.yml358-363
Diagram: macOS Release Build Flow
The macOS build process is notable for its two-stage signing:
Binary Signing .github/workflows/rust-release.yml224-235: Uses the macos-code-sign action to sign and notarize codex and codex-responses-api-proxy binaries individually. This requires Apple Developer ID certificates and notarization credentials.
DMG Creation .github/workflows/rust-release.yml237-281: After signing, hdiutil create packages the already-signed binaries into a DMG volume with volume name Codex (target).
DMG Signing .github/workflows/rust-release.yml283-294: The DMG itself is then signed and notarized. This double-signing ensures both the binaries inside and the DMG container are trusted.
The macOS builds run on macos-15-xlarge runners for both aarch64-apple-darwin and x86_64-apple-darwin targets.
Sources: .github/workflows/rust-release.yml66-69 .github/workflows/rust-release.yml224-294
Linux builds produce both musl and glibc variants for x64 and arm64 architectures. The musl builds require special toolchain setup:
musl Build Configuration .github/workflows/rust-release.yml130-204:
$GITHUB_WORKSPACE/.cargo-home to avoid host toolchain pollutionlibubsan.so.1 for undefined behavior sanitizationThe glibc builds run directly on ubuntu-24.04 or ubuntu-24.04-arm runners without special toolchain configuration.
Linux binaries are signed using Cosign with keyless signing .github/workflows/rust-release.yml217-222:
This produces .sigstore bundles alongside each binary containing the signature and certificate chain. The bundles can be verified using cosign verify-blob.
Sources: .github/workflows/rust-release.yml110-222 .github/scripts/install-musl-build-tools.sh
Windows builds are delegated to .github/workflows/rust-release-windows.yml a reusable workflow that:
Splits Build Phases .github/workflows/rust-release-windows.yml24-120:
build-windows-binaries job: Compiles binaries in two bundles:
primary: codex.exe, codex-responses-api-proxy.exehelpers: codex-windows-sandbox-setup.exe, codex-command-runner.exeRecombines for Signing .github/workflows/rust-release-windows.yml121-183:
build-windows job downloads both bundlesAzure Trusted Signing .github/actions/windows-code-sign/action.yml:
azure/trusted-signing-action@v0codex.exe, codex-responses-api-proxy.exe, codex-windows-sandbox-setup.exe, codex-command-runner.exeBundle Creation .github/workflows/rust-release-windows.yml236-250:
codex-*.exe that includes sandbox helper binariesSources: .github/workflows/rust-release-windows.yml .github/actions/windows-code-sign/action.yml
After building and signing, each platform-specific build job stages and compresses artifacts:
Diagram: Artifact Staging Process
.github/workflows/rust-release.yml296-356 implements the staging process:
Staging Directory: Copies binaries to dist/$TARGET/ with target-suffixed names
codex-aarch64-apple-darwin, codex-responses-api-proxy-x86_64-unknown-linux-musl.sigstore signature bundles.dmg filesDual Compression: Creates both .tar.gz and .zst archives
.tar.gz: For environments without zstd tool.zst: Smaller size, faster decompression (level 19, multi-threaded with -T0)--rm flag deletes original uncompressed binaries after creating .zstWindows Differences: Uses 7z for .zip creation and keeps .exe files uncompressed alongside archives
The compression step ensures artifacts uploaded to GitHub Actions are small while providing multiple format options for downstream users.
Sources: .github/workflows/rust-release.yml296-356
The release job waits for all build jobs to complete, then assembles the final release:
Release Assembly Steps .github/workflows/rust-release.yml374-521:
Artifact Download: Uses actions/download-artifact@v7 to pull all platform artifacts into dist/
Cleanup: Removes temporary artifacts not intended for release:
shell-tool-mcp* directories (published separately as npm package)windows-binaries* directories (intermediate build artifacts)cargo-timing.html files from multiple targets (would conflict with duplicate names)Config Schema: Copies codex-rs/core/config.schema.json to dist/config-schema.json for download
Version Extraction: Strips rust-v prefix from tag name to get version string
npm Settings Determination .github/workflows/rust-release.yml447-464:
1.2.3): should_publish=true, npm_tag= (default latest)1.2.3-alpha.N): should_publish=true, npm_tag=alphashould_publish=falsenpm Package Staging: Runs scripts/stage_npm_packages.py to:
@openai/codex-linux-x64)@openai/codex with platform detectionGitHub Release Creation .github/workflows/rust-release.yml491-507:
softprops/action-gh-release@v2rust-v prefixdist/**prerelease: true if version contains - suffixDotSlash Publishing: Uses facebook/dotslash-publish-release@v2 to update DotSlash config for binary discovery
Developer Website Deploy .github/workflows/rust-release.yml509-520: Triggers a Vercel deploy webhook for developers.openai.com to pick up the new config schema (stable releases only)
Sources: .github/workflows/rust-release.yml374-521
The publish-npm job conditionally publishes to the npm registry using OpenID Connect (OIDC) authentication:
npm OIDC Publishing Flow .github/workflows/rust-release.yml522-615:
Key aspects of the npm publishing process:
OIDC Prerequisites:
permissions.id-token: write in job definitionnpm login --auth-type=oidc)NODE_AUTH_TOKEN secret requiredTarball Download .github/workflows/rust-release.yml547-568:
gh release downloadcodex-npm-${version}.tgz, codex-npm-{linux,darwin,win32}-*-${version}.tgz, codex-responses-api-proxy-npm-${version}.tgz, codex-sdk-npm-${version}.tgzTag Selection .github/workflows/rust-release.yml571-615:
npm_tag (empty for stable → latest, "alpha" for pre-releases)alpha-linux-x64, alpha-darwin-arm64, etc.Publishing Loop: Publishes each tarball with appropriate --tag flag
This OIDC-based publishing eliminates the need for long-lived npm tokens and provides per-publish audit trails via OpenID Connect identity tokens.
Sources: .github/workflows/rust-release.yml522-615
The update-branch job force-updates the latest-alpha-cli branch to point at the release commit .github/workflows/rust-release.yml617-634:
This branch serves as a stable pointer for canary/development builds and can be used by automated deployment systems or testing infrastructure to track the latest released alpha version.
Sources: .github/workflows/rust-release.yml617-634
The shell-tool-mcp job runs concurrently with platform builds by invoking the reusable .github/workflows/shell-tool-mcp.yml workflow .github/workflows/rust-release.yml365-372:
This workflow builds patched Bash and Zsh shells across 12 Linux container + 2 macOS configurations, along with the Rust codex-exec-mcp-server and codex-execve-wrapper binaries. The resulting npm package (@openai/codex-shell-tool-mcp) is uploaded as a release artifact and conditionally published to npm.
For full details on the shell-tool-mcp build process, see Shell Tool MCP Build System.
Sources: .github/workflows/rust-release.yml365-372
| Platform | Signing Method | Artifacts | Verification |
|---|---|---|---|
| macOS | Apple Developer ID + Notarization | codex, codex-responses-api-proxy, .dmg | spctl --assess --verbose |
| Linux | Cosign keyless signing | .sigstore bundles | cosign verify-blob |
| Windows | Azure Trusted Signing (Authenticode) | codex.exe, codex-responses-api-proxy.exe, codex-windows-sandbox-setup.exe, codex-command-runner.exe | signtool verify |
All signing processes use OIDC/ephemeral credentials to avoid storing long-lived secrets in GitHub Actions.
Sources: .github/workflows/rust-release.yml217-294 .github/workflows/rust-release-windows.yml173-182 .github/actions/windows-code-sign/action.yml
Unlike the CI pipeline which uses sccache and cargo home caching, the release pipeline does not use GitHub Actions cache to ensure reproducible builds from clean state. However, it does optimize build times through:
thin LTO instead of fat LTO for ~30% faster compile timescargo-timing.html reports for post-mortem analysis.github/workflows/rust-release.yml208-214 shows the build command:
The --timings flag generates HTML reports showing dependency build order and duration, which are uploaded as artifacts for debugging slow builds.
Sources: .github/workflows/rust-release.yml60 .github/workflows/rust-release.yml205-215
Refresh this wiki