Skip to content

fix(exec): keep one Codex install behind every profile - #7

Merged
jiunbae merged 1 commit into
mainfrom
fix/codex-package-root
Sep 22, 2026
Merged

jiunbae merged 1 commit into
mainfrom
fix/codex-package-root

Conversation

@jiunbae

@jiunbae jiunbae commented Sep 22, 2026

Copy link
Copy Markdown
Member

The bug

Codex derives its package root from CODEX_HOME but writes the launcher to a fixed path (install.sh lines 16-19, 1049):

BIN_PATH="$BIN_DIR/codex"                                   # $HOME/.local/bin — fixed
CODEX_HOME_DIR="${CODEX_HOME:-$HOME/.codex}"
STANDALONE_ROOT="$CODEX_HOME_DIR/packages/standalone"       # follows CODEX_HOME
...
replace_path_with_symlink "$BIN_PATH" "$CURRENT_LINK/$codex_relative_path" "$tmp_link"

aas exec points CODEX_HOME at the profile home. Accept the update notice inside a session and the release unpacks into …/profiles/codex-<account>/packages/standalone/, while ~/.local/bin/codex — the launcher every other account shares, and the one aas shim install records — is repointed into that single account's profile.

Two consequences: profiles drift to whichever version each last updated itself to, and the shared launcher dangles as soon as that account is renamed or removed.

Found while tracking down why aas e chatgpt@codex --yolo kept running 0.152.0 on a host where 0.155.1 was available.

The fix

share::link_codex_package_root links a profile's packages to the native install's, so one install sits behind every profile and an in-session update moves them all together.

Not a shared-state category, deliberately. Sharing describes what a profile chooses to have in common with the system install — sessions, skills, settings — and an account that opts out of every category still runs the same binary as everyone else. Making the runtime's own package root opt-in would simply restore this bug for isolated profiles. It therefore runs unconditionally, next to seed_codex_hook_trust.

Conservative in both directions: it only mirrors a package root that already exists, and a real directory already in a profile — an update that landed there before this fix — is left alone rather than replaced.

Residual caveat (unchanged by this PR)

An in-session update still writes the profile's path into ~/.local/bin/codex. It resolves correctly through the link, but the string routes through a profile directory. Updating from a plain shell remains the tidier habit; this PR makes the in-session case correct rather than silently divergent.

Verification

  • Live: aas e chatgpt@codex -- --version creates …/profiles/codex-chatgpt_codex/packages -> ~/.codex/packages, resolving to the shared current (0.155.1).
  • share::tests::codex_package_root_is_linked_regardless_of_sharing covers the Some(&[]) (share nothing) case, the never-clobber case, and provider isolation.
  • 193 tests pass; clippy/fmt/rustdoc clean.

🤖 Generated with Claude Code

Codex derives where its standalone package lives from `CODEX_HOME`

  CODEX_HOME_DIR="${CODEX_HOME:-$HOME/.codex}"
  STANDALONE_ROOT="$CODEX_HOME_DIR/packages/standalone"

but writes the launcher to `$HOME/.local/bin/codex` regardless, pointing
it at `$STANDALONE_ROOT/current/bin/codex`. `aas exec` sets `CODEX_HOME`
to the profile home, so `codex update` accepted from the update notice
inside a session unpacked the release into that one account's profile
and repointed the launcher every other account shares into it. Profiles
then drifted to whichever version each had last updated itself to, and
the shared launcher dangled the moment that account was renamed or
removed.

Link the profile's package root to the native install's, so one install
sits behind every profile and an in-session update moves them together.

The link is deliberately not a shared-state category. Sharing describes
what a profile chooses to have in common with the system install —
sessions, skills, settings — and an account that opts out of all of it
still runs the same binary as everyone else. Making the runtime's own
package root opt-in would just restore the bug for isolated profiles.

Only ever mirrors a package root that exists, never invents one, and a
real directory already in a profile (an update that landed there before
this fix) is left alone rather than replaced.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create an environment for this repo.

@jiunbae
jiunbae merged commit 6a728f0 into main Sep 22, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant