Skip to content

feat(launch): let a codex wrapper sit behind cue's profile picker - #143

Merged
NagyVikt merged 1 commit into
mainfrom
feat/codex-picker-behind-wrapper
Aug 11, 2026
Merged

feat(launch): let a codex wrapper sit behind cue's profile picker#143
NagyVikt merged 1 commit into
mainfrom
feat/codex-picker-behind-wrapper

Conversation

@NagyVikt

Copy link
Copy Markdown
Contributor

Problem

A wrapper like oh-my-codex could only be reached by shadowing codex in the shell — a fish function, an alias. That wins the name outright, so cue launch codex never ran and the profile picker never appeared. claude got a picker; codex got nothing, with the wrapper silently passing whatever cue current had already resolved.

Change

$CUE_REAL_CODEX tells cue launch codex to exec the wrapper in place of the codex binary, so cue resolves the profile and materializes the runtime first and the wrapper inherits both. Unlike $CUE_REAL_CLAUDE, which the launch path deliberately ignores, this one is honored there — the point is dispatch, not discovery.

The override is held to the same bar as a PATH candidate (real, executable file), so a stale value falls back to the PATH walk instead of failing as an unexplained exit 127.

The loop this had to avoid

Wrappers spawn codex by bare name. With cue's shim dir still on PATH that spawn lands right back in cue launch — cue → wrapper → cue → wrapper, something MAX_LAUNCH_DEPTH can only abort with an error, never fix. stripShimDirFromPath drops the dir for the child's process tree and the override is unset alongside it.

Trade-off worth knowing: this takes cue's claude shim out of that process tree too.

Bundled fix

CUE_SMART_SUBSET folded the entire passthrough argv into the skill classifier, flags included. codex --madmax measured as:

smart-subset: 4/21 skills kept — "--madmax" likely refers to a cue profile

That gutted the profile the user had just picked. passthroughPrompt folds only the prose. Latent for claude --resume too, so this changes behavior for all flag-bearing launches, not just codex. Both remaining imprecisions (a flag's value folds in; a prompt opening with - drops out) fail toward loading more skills, never fewer.

Verification

All three exec sites (CUE_BYPASS fast path, help passthrough, full launch), against a real wrapper:

WRAPPER-ARGV: --madmax
WRAPPER-CUE_PROFILE: core
WRAPPER-CODEX_HOME: ~/.config/cue/runtime/core/codex
WRAPPER-CUE_REAL_CODEX: <unset>          ← no re-dispatch
WRAPPER-shim-on-PATH: 0                  ← loop broken
WRAPPER-bare-codex-resolves-to: ~/.local/bin/codex   ← real binary

Subset fix both directions: --madmax alone → 23 skills (full profile); -p "fix the medusa checkout bug" → still classifies, now on the prose.

Check Result
Typecheck Pass
Lint Pass (same 6 warnings as base, none in touched files)
Tests 3177 pass / 10 fail — failing set byte-identical to origin/main, measured in a separate base worktree
New tests +17

The 10 failures are MCP-catalog artifacts of the test worktree and are present on an untouched origin/main checkout too.

Review

Self-reviewed: 0 CRITICAL, 0 HIGH, 2 MEDIUM (both fixed before this PR — dead findRealCodexBin removed, exec guard added), 4 LOW documented in code comments.

🤖 Generated with Claude Code

A wrapper like oh-my-codex could only be reached by shadowing `codex` in the
shell — a fish function, an alias — which meant it won the name outright and
cue's picker never ran. Users got a profile picker on `claude` and nothing on
`codex`, with the wrapper silently passing whatever `cue current` had already
resolved.

$CUE_REAL_CODEX inverts that. It tells `cue launch codex` to exec the wrapper in
place of the codex binary, so cue resolves the profile and materializes the
runtime FIRST and the wrapper inherits both. Unlike $CUE_REAL_CLAUDE, which the
launch path deliberately ignores, this one is honored there: the point is
dispatch, not discovery. The override is held to the same bar as a PATH
candidate — a real, executable file — so a stale or misaimed value falls back to
the PATH walk instead of failing as an unexplained exit 127.

Wrapper execs get a sanitized env, or the handoff loops. Wrappers spawn `codex`
by bare name, so with cue's shim dir still on PATH that spawn lands right back
in `cue launch` — cue → wrapper → cue → wrapper, something MAX_LAUNCH_DEPTH can
only abort with an error, never fix. `stripShimDirFromPath` drops the dir for
the child's process tree and the override is unset alongside it, so the wrapper
reaches the real CLI and cue runs exactly once per launch. Note this takes cue's
`claude` shim out of that process tree too, which is the price of the handoff.

Also fixes a fold that made this unusable: CUE_SMART_SUBSET pushed the entire
passthrough argv at the skill classifier, flags included. `codex --madmax`
measured as

  smart-subset: 4/21 skills kept — "--madmax" likely refers to a cue profile

which gutted the profile the user had just picked. `passthroughPrompt` folds
only the prose, so a flag-only launch leaves the subset unset and the full
profile loads. This was latent for `claude --resume` too. Both remaining
imprecisions (a flag's value folds in, a prompt opening with `-` drops out) fail
toward loading MORE skills, never fewer.

Verified against all three exec sites (CUE_BYPASS fast path, help passthrough,
full launch): wrapper receives its args, CUE_PROFILE and CODEX_HOME point at the
cue runtime, shim dir is off the child PATH, and a bare `codex` inside the
wrapper resolves to the real binary.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@NagyVikt
NagyVikt merged commit b9f43b1 into main Aug 11, 2026
5 of 6 checks passed
@NagyVikt
NagyVikt deleted the feat/codex-picker-behind-wrapper branch August 11, 2026 22:46
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