Files
codex/scripts/codex_package/README.md
Michael Bolin c7bcb90f9b package: include zsh fork in Codex package (#23756)
## Why

The package layout gives Codex a stable place for runtime helpers that
should travel with the entrypoint. `shell_zsh_fork` still required users
to configure `zsh_path` manually, even though we already publish
prebuilt zsh fork artifacts.

This PR builds on #24129 and uses the shared DotSlash artifact fetcher
to include the zsh fork in Codex packages when a matching target
artifact exists. Packaged Codex builds can then discover the bundled
fork automatically; the user/profile `zsh_path` override is removed so
the feature uses the package-managed artifact instead of a legacy path
knob.

## What Changed

- Added `scripts/codex_package/codex-zsh`, a checked-in DotSlash
manifest for the current macOS arm64 and Linux zsh fork artifacts.
- Taught `scripts/build_codex_package.py` to fetch the matching zsh fork
artifact and install it at `codex-resources/zsh/bin/zsh` when available
for the selected target.
- Added package layout validation for the optional bundled zsh resource.
- Added `InstallContext::bundled_zsh_path()` and
`InstallContext::bundled_zsh_bin_dir()` for package-layout resource
discovery.
- Threaded the packaged zsh path through config loading as the runtime
`zsh_path` for packaged installs, and removed the config/profile/CLI
override path.
- Kept the packaged default zsh override typed as `AbsolutePathBuf`
until the existing runtime `Config::zsh_path` boundary.
- Updated app-server zsh-fork integration tests to spawn
`codex-app-server` from a temporary package layout with
`codex-resources/zsh/bin/zsh`, matching the new packaged discovery path
instead of setting `zsh_path` in config.
- Switched package executable copying from metadata-preserving `copy2()`
to `copyfile()` plus explicit executable bits, which avoids macOS
file-flag failures when local smoke tests use system binaries as inputs.

## Testing

To verify that the `zsh` executable from the Codex package is picked up
correctly, first I ran:

```shell
./scripts/build_codex_package.py
```

which created:

```
/private/var/folders/vw/x2knqmks50sfhfpy27nftl900000gp/T/codex-package-pms94kdp/
```

so then I ran:

```
/private/var/folders/vw/x2knqmks50sfhfpy27nftl900000gp/T/codex-package-pms94kdp/bin/codex exec --enable shell_zsh_fork 'run `echo $0`'
```

which reported the following, as expected:

```
/private/var/folders/vw/x2knqmks50sfhfpy27nftl900000gp/T/codex-package-pms94kdp/codex-resources/zsh/bin/zsh
```



---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/23756).
* #23768
* __->__ #23756
2026-05-22 17:54:07 -07:00

3.6 KiB

Codex package builder

This package contains the implementation behind scripts/build_codex_package.py. The top-level script is the stable executable entry point; these modules keep the package-building logic split by responsibility.

The builder creates a canonical Codex package directory:

.
├── codex-package.json
├── bin
│   └── <entrypoint>[.exe]
├── codex-resources
│   ├── bwrap                             # Linux only
│   ├── zsh/bin/zsh                       # supported Unix targets only
│   ├── codex-command-runner.exe          # Windows only
│   └── codex-windows-sandbox-setup.exe   # Windows only
└── codex-path
    └── rg[.exe]

The package directory is the primary artifact. Archive formats such as .tar.gz, .tar.zst, and .zip are serializations of that directory.

If --target is omitted, the builder uses the release target for the current host platform. On Linux, that default is a musl target to match Codex release artifacts; pass a GNU Linux target explicitly for native glibc local builds. If --package-dir is omitted, the builder creates a new temporary directory and prints its path after the package is built.

The --variant flag selects the package entrypoint. Supported variants are codex and codex-app-server. The version field in codex-package.json is read from [workspace.package].version in codex-rs/Cargo.toml.

Source-built artifacts

Artifacts built from this repository are built by the package builder in one grouped cargo build command per package when they are needed and no prebuilt override was provided:

  • all targets: the selected entrypoint, unless --entrypoint-bin is provided
  • Linux targets: bwrap, unless --bwrap-bin is provided
  • Windows targets: codex-command-runner and codex-windows-sandbox-setup, unless the corresponding prebuilt helper flags are provided

The default cargo profile is dev-small because local iteration should favor fast, small builds. Release jobs should pass --cargo-profile release and an explicit target. Release jobs that already built and signed/notarized the entrypoint should pass --entrypoint-bin so the package contains that exact binary instead of rebuilding it.

Release jobs that already built package resource binaries should also pass the corresponding resource flags: --bwrap-bin for Linux packages, and --codex-command-runner-bin plus --codex-windows-sandbox-setup-bin for Windows packages. This keeps package archive creation as a pure staging step after signing instead of rebuilding resources.

When the builder source-builds an entrypoint for a Darwin or Linux target, it downloads and verifies the matching Codex-built V8 release pair before invoking Cargo and sets RUSTY_V8_ARCHIVE plus RUSTY_V8_SRC_BINDING_PATH for that build. Windows targets keep Cargo's release-build MSVC artifact path. Explicit overrides remain authoritative when both variables are already set. Set V8_FROM_SOURCE=1 to leave the build with the v8 crate source-build path.

rg is not built from this repository, so the builder fetches it from the DotSlash manifest at scripts/codex_package/rg. Downloaded archives are cached under $TMPDIR/codex-package/<target>-rg and are reused only after the recorded size and SHA-256 digest have been verified. Pass --rg-bin to use a local ripgrep executable instead.

The patched zsh fork used by shell_zsh_fork is fetched from the DotSlash manifest at scripts/codex_package/codex-zsh when the selected target has a matching prebuilt artifact. Downloaded archives are cached under $TMPDIR/codex-package/<target>-zsh and installed at codex-resources/zsh/bin/zsh.