feat(launch): let a codex wrapper sit behind cue's profile picker - #143
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A wrapper like oh-my-codex could only be reached by shadowing
codexin the shell — a fish function, an alias. That wins the name outright, socue launch codexnever ran and the profile picker never appeared.claudegot a picker;codexgot nothing, with the wrapper silently passing whatevercue currenthad already resolved.Change
$CUE_REAL_CODEXtellscue launch codexto 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
codexby bare name. With cue's shim dir still on PATH that spawn lands right back incue launch— cue → wrapper → cue → wrapper, somethingMAX_LAUNCH_DEPTHcan only abort with an error, never fix.stripShimDirFromPathdrops the dir for the child's process tree and the override is unset alongside it.Trade-off worth knowing: this takes cue's
claudeshim out of that process tree too.Bundled fix
CUE_SMART_SUBSETfolded the entire passthrough argv into the skill classifier, flags included.codex --madmaxmeasured as:That gutted the profile the user had just picked.
passthroughPromptfolds only the prose. Latent forclaude --resumetoo, 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:
Subset fix both directions:
--madmaxalone → 23 skills (full profile);-p "fix the medusa checkout bug"→ still classifies, now on the prose.origin/main, measured in a separate base worktreeThe 10 failures are MCP-catalog artifacts of the test worktree and are present on an untouched
origin/maincheckout too.Review
Self-reviewed: 0 CRITICAL, 0 HIGH, 2 MEDIUM (both fixed before this PR — dead
findRealCodexBinremoved, exec guard added), 4 LOW documented in code comments.🤖 Generated with Claude Code