Client or integration
Codex CLI
Area
Installation or packaging
Summary
The Codex autostart shim can turn a dynamic mise launcher into an infinite exec recursion. installCodexShim() accepts the first non-OpenCodex codex file on PATH, renames it to codex.opencodex-real, and writes the OpenCodex shim at the original path. That is safe for a concrete executable or symlink, but not for a launcher whose implementation is effectively:
#!/bin/zsh
exec "$HOME/.local/bin/mise" exec -- codex "$@"
After the rename, the backed-up launcher asks mise to resolve codex again. When the active mise toolset has no separate concrete codex binary, resolution returns to the newly installed OpenCodex shim:
codex
-> codex.opencodex-real
-> mise exec -- codex
-> codex
-> ...
The loop keeps the same PID while repeatedly replacing its process image, so ordinary %CPU snapshots can misleadingly show 0.0 even while CPU time rises continuously. On the affected macOS host, one orphaned codex --help invocation survived for approximately 3 days 22 hours, accumulated about 31 hours of CPU time, and consumed about 71% of one core during a two-second CPU-time observation.
Expected behavior: OpenCodex must not install a shim whose saved launcher resolves back to the shim. The installer should either resolve a stable concrete target, refuse the installation with an actionable message, or roll the transaction back. A generated shim should also fail fast if recursive re-entry still occurs.
The same OpenCodex version on Linux does not reproduce this because the saved launcher is a direct symlink to @openai/codex/bin/codex.js, rather than a version-manager trampoline. The OpenCodex service itself is not launched through mise on each request; both launchd and systemd execute the bundled Bun runtime by absolute path.
Reproduction
-
On macOS, expose a codex launcher on PATH whose contents delegate by command name:
#!/bin/zsh
exec "$HOME/.local/bin/mise" exec -- codex "$@"
-
Ensure the active mise toolset does not expose a distinct concrete codex binary, so mise exec -- codex falls through to the launcher above.
-
Enable codexAutoStart and let OpenCodex install its Codex shim.
-
Observe that OpenCodex renames the launcher to codex.opencodex-real and writes the autostart shim at the original codex path.
-
Run a bypassed command such as codex --help.
-
Observe the same PID alternate between the OpenCodex shell shim, codex.opencodex-real, and mise exec -- codex, without reaching the real Codex CLI or exiting.
Current source path on main (6d881db206c6a74da6b64fa22b6980faf05d0122):
src/codex/shim.ts:281-314: findCodexOnPath() accepts any existing non-OpenCodex file and does not distinguish a dynamic version-manager launcher from a stable target.
src/codex/shim.ts:1052-1066: installCodexShimInternal() renames that launcher to the backup path and makes the new shim execute the backup.
tests/codex-shim.test.ts: direct shell launchers and platform wrappers are covered, but there is no regression case where the saved launcher resolves codex by name back through PATH.
The issue remains present in current main; searching existing issues for mise, shim recursion, and mise exec -- codex found no matching report. #322 covers subcommand parsing in generated shims, and #606 covers repeated codex --version probes, not recursive saved-launcher resolution.
Version
Observed on @bitkyc08/opencodex 2.10.1; source behavior confirmed on main commit 6d881db206c6a74da6b64fa22b6980faf05d0122 / release 2.12.0.
Operating system
macOS 26.5.2, Apple Silicon arm64. Control host: Ubuntu 22.04 arm64 using a direct npm codex.js symlink.
Provider and model
Not provider-specific. The failure occurs before Codex reaches any provider.
Logs or error output
# The command name alternates while the PID remains unchanged.
PID ELAPSED TIME COMMAND
28394 03-22:24:39 1880:15.89 /bin/zsh ~/.local/bin/codex.opencodex-real --help
28394 03-22:24:41 1880:17.31 /usr/bin/env sh ~/.local/bin/codex --help
# 1.42 CPU seconds accumulated during 2 seconds of wall time.
# ps %CPU displayed 0.0 because repeated exec replaces the sampled image.
No OpenCodex shutdown, crash, or provider error caused this process. A host reboot removed the orphaned process, but the launcher and shim files remain capable of reproducing it on the next PATH-based Codex invocation.
Screenshots and supporting files
No screenshot is needed. The process snapshots, launcher contents, launchd service definition, and Linux control-host symlink were inspected directly. Usernames, credentials, tokens, and private request data have been omitted.
Redacted configuration
{
"codexAutoStart": true,
"port": 10100
}
Suggested direction
Keep the normal direct-executable and direct-symlink path unchanged, but make shim installation safe for dynamic launchers:
- detect or resolve version-manager trampolines before committing the rename-and-wrap transaction;
- validate the staged saved-launcher path with a bounded process-group probe and roll back if it re-enters the generated shim or times out;
- add a generated-shim recursion guard so an unexpected dynamic launcher fails with an actionable error instead of consuming CPU indefinitely;
- add a Unix regression test with a fake mise-style launcher that resolves
codex through PATH.
Content-only detection of the exact mise exec -- codex spelling would address this report but may miss equivalent asdf/rtx/custom launchers, so a bounded behavioral guard would provide a stronger invariant.
Acceptance criteria
- Installing the Codex autostart shim cannot leave a
codex -> saved launcher -> command-name resolution -> codex cycle.
- The mise-style reproduction exits or is rejected within a bounded time and does not leave a spinning child process.
- A failed safety check preserves or restores the original launcher and does not overwrite an existing backup.
- Existing direct executable, symlink, Unix shim, Windows launcher, auto-restore, uninstall, and internal-command bypass behavior remains covered and passing.
- Focused shim tests,
bun run typecheck, and the full bun run test suite pass on the contributor branch.
Checks
Client or integration
Codex CLI
Area
Installation or packaging
Summary
The Codex autostart shim can turn a dynamic
miselauncher into an infiniteexecrecursion.installCodexShim()accepts the first non-OpenCodexcodexfile onPATH, renames it tocodex.opencodex-real, and writes the OpenCodex shim at the original path. That is safe for a concrete executable or symlink, but not for a launcher whose implementation is effectively:After the rename, the backed-up launcher asks
miseto resolvecodexagain. When the active mise toolset has no separate concretecodexbinary, resolution returns to the newly installed OpenCodex shim:The loop keeps the same PID while repeatedly replacing its process image, so ordinary
%CPUsnapshots can misleadingly show0.0even while CPU time rises continuously. On the affected macOS host, one orphanedcodex --helpinvocation survived for approximately 3 days 22 hours, accumulated about 31 hours of CPU time, and consumed about 71% of one core during a two-second CPU-time observation.Expected behavior: OpenCodex must not install a shim whose saved launcher resolves back to the shim. The installer should either resolve a stable concrete target, refuse the installation with an actionable message, or roll the transaction back. A generated shim should also fail fast if recursive re-entry still occurs.
The same OpenCodex version on Linux does not reproduce this because the saved launcher is a direct symlink to
@openai/codex/bin/codex.js, rather than a version-manager trampoline. The OpenCodex service itself is not launched through mise on each request; both launchd and systemd execute the bundled Bun runtime by absolute path.Reproduction
On macOS, expose a
codexlauncher onPATHwhose contents delegate by command name:Ensure the active mise toolset does not expose a distinct concrete
codexbinary, somise exec -- codexfalls through to the launcher above.Enable
codexAutoStartand let OpenCodex install its Codex shim.Observe that OpenCodex renames the launcher to
codex.opencodex-realand writes the autostart shim at the originalcodexpath.Run a bypassed command such as
codex --help.Observe the same PID alternate between the OpenCodex shell shim,
codex.opencodex-real, andmise exec -- codex, without reaching the real Codex CLI or exiting.Current source path on
main(6d881db206c6a74da6b64fa22b6980faf05d0122):src/codex/shim.ts:281-314:findCodexOnPath()accepts any existing non-OpenCodex file and does not distinguish a dynamic version-manager launcher from a stable target.src/codex/shim.ts:1052-1066:installCodexShimInternal()renames that launcher to the backup path and makes the new shim execute the backup.tests/codex-shim.test.ts: direct shell launchers and platform wrappers are covered, but there is no regression case where the saved launcher resolvescodexby name back throughPATH.The issue remains present in current
main; searching existing issues formise, shim recursion, andmise exec -- codexfound no matching report. #322 covers subcommand parsing in generated shims, and #606 covers repeatedcodex --versionprobes, not recursive saved-launcher resolution.Version
Observed on
@bitkyc08/opencodex2.10.1; source behavior confirmed onmaincommit6d881db206c6a74da6b64fa22b6980faf05d0122/ release 2.12.0.Operating system
macOS 26.5.2, Apple Silicon arm64. Control host: Ubuntu 22.04 arm64 using a direct npm
codex.jssymlink.Provider and model
Not provider-specific. The failure occurs before Codex reaches any provider.
Logs or error output
No OpenCodex shutdown, crash, or provider error caused this process. A host reboot removed the orphaned process, but the launcher and shim files remain capable of reproducing it on the next PATH-based Codex invocation.
Screenshots and supporting files
No screenshot is needed. The process snapshots, launcher contents, launchd service definition, and Linux control-host symlink were inspected directly. Usernames, credentials, tokens, and private request data have been omitted.
Redacted configuration
{ "codexAutoStart": true, "port": 10100 }Suggested direction
Keep the normal direct-executable and direct-symlink path unchanged, but make shim installation safe for dynamic launchers:
codexthroughPATH.Content-only detection of the exact
mise exec -- codexspelling would address this report but may miss equivalent asdf/rtx/custom launchers, so a bounded behavioral guard would provide a stronger invariant.Acceptance criteria
codex -> saved launcher -> command-name resolution -> codexcycle.bun run typecheck, and the fullbun run testsuite pass on the contributor branch.Checks