Codex-W
Trigger: any message containing Codex-W (any casing), optionally with an engine
name — Codex-W Luna, Codex-W Sol, Codex-W DS, Codex-W GlmFlash, Codex-W Terra.
The legacy prefix Codex-First … means the same thing and still applies.
Claude Code sessions only. Codex/other harnesses: skip; never self-delegate.
Rationale: Claude (Fable/Opus) tokens metered + expensive; the Codex lanes are flat-rate. A current Codex engine (Luna / Sol / DS / GlmFlash / Terra — see below) is usually the better and faster model at writing/implementing code; Claude wins at ergonomics — judgment, design, spec-writing, review, orchestration. So Codex types, Claude thinks and verifies.
Route
Delegate to Codex (default for hands-on work):
- implementation from a frozen spec; refactors; mechanical migrations
- bug fixes with known repro; test writing; coverage fills
- CI fixes, dependency bumps, scripts/tooling
- bulk codebase exploration where raw reading ≫ the answer
Keep in Claude:
- design, API design, architecture, naming, UX judgment
- tasks where writing the spec IS the work (ambiguity = design)
- tiny edits (~<20 lines, single obvious change) — delegation overhead loses
- anything needing session tools: MCP (browser/computer-use/chronicle), 1Password, secrets
- destructive/irreversible ops, releases, pushes, GitHub mutations — Claude-side per git rules
- review of Codex output — never delegated, never skipped
Mixed task: Claude designs first, freezes spec, delegates build-out.
Heuristic: prompt reads as a work order → delegate; writing it forces decisions → design, Claude.
Portfolio/multi-repo work: $maintainer-orchestrator instead.
Two axes: Codex engine × Claude side
Independent choices. Engine = who types (the Codex CLI model). Claude side = who specs, reviews, verifies, and in fan-out plans.
Engine — "Codex-W Luna" / "Codex-W Sol" / "Codex-W DS" / "Codex-W GlmFlash" / "Codex-W Terra"
Codex always does the typing; which model does it is selectable. Pass the engine flags verbatim — never fall back to Codex's configured default.
Luna = OpenAI's Luna. Never a resold Luna. Only
-c model="gpt-5.6-luna"on the default provider counts as Luna. A Luna served by opencode Go or any other reseller lane (opencode-go/…,opencode-go-messages/…,commandcode-…,clinepass-…, anything reached viamodel_provider="codex-router") is a different model wearing the name — not permitted for this engine, not as a fallback, not "close enough". If OpenAI's Luna is unavailable, stop and ask; do not accept a routed substitute.
| Command | Engine flags | Effort | Only permitted fallback |
|---|---|---|---|
| Codex-W Luna (default) | -c model="gpt-5.6-luna" — no model_provider | max | xhigh |
| Codex-W Sol | -c model="gpt-5.6-sol" — no model_provider | high | none — see below |
| Codex-W DS | -c model_provider="codex-router" -c model="opencode-go/deepseek-v4-flash" | max | high — DS has no xhigh |
| Codex-W GlmFlash | -c model_provider="codex-router" -c model="opencode-go/glm-5.3-flash" | max | high — ladder is low|high|max |
| Codex-W Terra | -c model="gpt-5.6-terra" | max | xhigh |
Effort is per engine, not global. Luna, DS, GlmFlash and Terra run at max. Sol runs at high — that is the pin, not a starting point: do not raise it to xhigh/max to "try harder", and do not lower it to save money. Because high is already the pinned rung rather than a ceiling, Sol has no permitted fallback: if high is rejected, stop and ask rather than picking a neighbouring rung.
Pick per work order:
- Luna — house default. Fast, affordable, metered OpenAI usage. Take it unless a reason below applies.
Luna is the OpenAI lane, exclusively. It means OpenAI's own
gpt-5.6-luna(catalog entryowned_by: "openai"), reached over the default provider. Never route Luna throughmodel_provider="codex-router", and never substitute anyopencode-go/*oropencode-go-messages/*model for it — the opencode Go subscription is the DS lane and nothing else. Writing the id asopenai/gpt-5.6-lunais only how the lane is named in prose; that literal is not a valid slug (the catalog has no provider-prefixed Luna), so the flag stays the bare-c model="gpt-5.6-luna". - Sol — OpenAI's
gpt-5.6-solathigh, over the default provider. The reasoning lane: use it when the work order is settled but the implementation still needs real judgment — tricky root causes with a known repro, refactors whose contracts are subtle, migrations where the mechanical edit is easy and the edge cases are not. Cheaper than Terra and more deliberate than Luna at the same typing job. Same OpenAI-only rule as Luna: only the bare-c model="gpt-5.6-sol"on the default provider counts. A Sol reached throughmodel_provider="codex-router", a vendor-prefixed slug, or any reseller catalog entry is a different model wearing the name — stop and ask. Notegpt-5.6-sol-wmalso exists in the catalog. It is not this engine; the slug is exactlygpt-5.6-sol. Sol is separately the read-only oversight model in the Codex-sideds-workflow/lama-workflowprofiles (there atxhigh). Here it is a writer like any other engine, athigh— the two uses share a model, not a role. - DS — DeepSeek V4 Flash 0731 via the flat-rate opencode Go subscription, routed through the local
codex-routerprovider (defined in~/.codex/config.toml). Cheapest lane: bulk mechanical work, wide refactors, test/coverage fills, long exploration — volume over finesse. Reasoning ladder is shorter than the GPT lane (low | high | maxonly). - GlmFlash — GLM-5.3 Flash via the same flat-rate opencode Go subscription as DS, routed through
codex-router. The second bulk lane: reach for it when DS is saturated, when a job wants a different failure mode than DeepSeek's, or simply as the cheap default for high-volume mechanical work. Measured ladder:low | high | max— all three accepted,maxis the pin,highthe only downgrade. Like DS it is text-only and has no usable visual judgment — the read-only Terra companion below applies to it exactly as it does to DS. - Terra — strongest and priciest of the five. Hard cross-cutting reasoning, and the visual lane whenever DS is typing (below).
Rules:
-
The OpenAI lanes never touch opencode Go. The lanes are
luna= OpenAI,sol= OpenAI,ds= opencode Go,glmflash= opencode Go,terra= OpenAI; they never borrow each other's provider. Whichever way a routed Luna shows up — amodel_providerflag on the Luna line, a prefixed slug, a catalog entry named "Luna" or "GPT Luna" under an opencode/reseller vendor — it is not this engine. Stop and ask. -
Check before you dispatch if anything about the id differs from the exact bare
gpt-5.6-luna/gpt-5.6-sol. The lane is identified by the catalog entry, not by the word "luna" or "sol":curl -s "$(sed -n 's/^openai_base_url = "\(.*\)"/\1/p' ~/.codex/config.toml)/models" | grep -o '{[^}]*luna[^}]*}' curl -s "$(sed -n 's/^openai_base_url = "\(.*\)"/\1/p' ~/.codex/config.toml)/models" | grep -o '{[^}]*sol[^}]*}'must print exactly
{"id":"gpt-5.6-luna","object":"model","owned_by":"openai"}and, for Sol, an entry{"id":"gpt-5.6-sol","object":"model","owned_by":"openai"}(thesolgrep also matchesgpt-5.6-sol-wm— ignore that line). Any otherowned_by, or any id with a/or vendor prefix, is the wrong model. -
Never switch engines inside one work item.
resumedoes not inherit the engine — repeat the same flags as the original run. -
"Codex-W DS" is not the Codex-side
ds-workflowskill (~/.codex/skills/ds-workflow/SKILL.md, profiles~/.codex/agents/ds-*.toml). That one orchestrates inside Codex with a SOL root plus DeepSeek writer agents. Here Claude stays the orchestrator and only the typing model swaps. -
The opencode Go lanes need a running Codex Router and the model registered in it. A model new to the router is not routable until it is added and the routes are regenerated — otherwise the call falls through to the ChatGPT backend and dies with
"… model is not supported when using Codex with a ChatGPT account". That error means "not routed", not "wrong flags". Registration: drop a config underconfig/opencode/go/<model>.json, thenbin/refresh-catalogandbin/enable(refresh alone updates the catalog but not the gateway routes). -
If an engine is unavailable (router down, model absent from the catalog), stop and ask. Do not silently retarget another engine — the cost profile is the whole point of the choice.
Visual work: Terra rides along with the opencode Go lanes (DS, GlmFlash)
The opencode Go lanes cannot do visual judgment. With engine = ds or engine = glmflash, every visual decision and every visual QA pass belongs to a separate read-only Terra run; the opencode Go engine stays the only writer. (The catalog advertises image input for DS but not supports_image_detail_original — treat its visual verdicts as unusable regardless. GLM-5.3 Flash is registered text-only, so it has nothing to judge with.)
Luna, Sol and Terra are not restricted this way — they own their visual work themselves, no companion run.
Visual = layout, hierarchy, spacing, typography, color, motion, responsive/interaction states, accessibility presentation, consistency with the existing design language.
Loop (mirrors ds-workflow): Terra brief → DS/GlmFlash implements → rendered evidence → Terra QA → the same engine fixes → Claude verifies.
V=$(mktemp); cat >"$V" <<'EOF'
<brief request or QA request: exact files/routes, the design language to match, what to judge>
EOF
command codex exec -s read-only -C <repo> \
-c model="gpt-5.6-terra" -c model_reasoning_effort="max" \
-i <screenshot.png> \
-o /tmp/terra-visual.md - <"$V" 2>/dev/null
-s read-only, never the bypass flag: Terra directs and reviews, it never writes. One writer per item, and that is the opencode Go engine.-iattaches rendered evidence (repeatable); omit it for a pure up-front brief.- Terra's output is spec text for DS's next
resume— hand it over verbatim, don't let Terra produce the patch. - Nonvisual questions don't belong in the Terra run; they go back to Claude.
Claude side — "Codex-W Fable" / "Codex-W Opus"
The Claude side (spec, review, verify, and — in fan-out — planning) can run on Fable (cheap, default) or Opus (better decomposition/judgment on ambiguous or high-stakes goals). Pick by command:
- "Codex-W Fable" — default. Cheapest orchestration.
- "Codex-W Opus" — when the goal is ambiguous, cross-cutting, or the spec quality is the risk.
Default = the Claude Code harness/session model. Both surfaces follow the model you're already running (Opus now); a fable/opus command only pins an override.
- Single-session skill (this file): the Claude side is whatever model the current session runs. So it already tracks the harness model. "Codex-W Opus" ⇒ run codex-w from an Opus session; "…Fable" ⇒ from a Fable session. There is no per-call model switch inside one session.
- Fan-out (
codex-fanoutworkflow): the planner inherits the session model by default — justWorkflow({ name: 'codex-fanout', args: { goal } }). To pin it regardless of the session, passargs.model: 'opus'(or'fable'). Workers stay Codex; final integration/review runs in the calling session. - Engine in fan-out:
args.engine: 'luna' | 'sol' | 'ds' | 'glmflash' | 'terra'(default'luna') picks the Codex model every worker delegates to. Independent ofargs.model, e.g.{ goal, model: 'opus', engine: 'ds' }= Opus plans, DeepSeek types. Thelunaandsolentries incodex-fanout'sENGINESmap are the OpenAI lanes (-c model="gpt-5.6-luna"/-c model="gpt-5.6-sol", no provider) — same rule as above: onlydsandglmflashmay carry opencode Go. Each engine's effort travels with it in that map, sosolworkers run athighwhile the others run atmax.
Invoke
Prompt via temp file, never inline quoting:
P=$(mktemp); cat >"$P" <<'EOF'
<goal, repo + key paths, constraints ("don't touch X"), non-goals, proof expected, output shape>
EOF
# pick exactly ONE engine line — default Luna
ENGINE=(-c model="gpt-5.6-luna" -c model_reasoning_effort="max") # Luna — OpenAI lane, NO model_provider
ENGINE=(-c model="gpt-5.6-sol" -c model_reasoning_effort="high") # Sol — OpenAI lane, NO model_provider, effort HIGH (not max)
ENGINE=(-c model_provider="codex-router" -c model="opencode-go/deepseek-v4-flash" -c model_reasoning_effort="max") # DS
ENGINE=(-c model_provider="codex-router" -c model="opencode-go/glm-5.3-flash" -c model_reasoning_effort="max") # GlmFlash
ENGINE=(-c model="gpt-5.6-terra" -c model_reasoning_effort="max") # Terra
command codex exec --dangerously-bypass-approvals-and-sandbox -C <repo> "${ENGINE[@]}" \
-o /tmp/codex-last.md - <"$P" 2>/dev/null
- Always pass the engine flags from the table above; never rely on Codex's configured default model.
- The Luna and Sol lines carry no
model_providerand no provider-prefixed slug — either one diverts them off the OpenAI lane. Only the DS and GlmFlash lines namecodex-router/opencode-go/*. - Bash tool calls don't share shell state — define
ENGINEin the same call as thecodex execthat uses it (same for every resume). - Reasoning effort comes from the engine's row in the table —
maxfor Luna/DS/Terra,highfor Sol. Never copy one engine's effort onto another. If amaxrun errors becausemaxis unavailable, retry the same command with that engine's fallback (xhighfor Luna/Terra,highfor DS/GlmFlash) — that is the only permitted downgrade. Sol has no fallback:highis its pin, so a rejectedhighis a stop-and-ask, not a retry at another rung. --dangerously-bypass-approvals-and-sandboxis the house default; Codex may run commands/tests freely. Keep prompts scoped to the target repo.command codexbypasses the interactive zsh wrapper; if not on PATH:fnm exec --using default -- codex- stderr suppressed (thinking noise bloats context); drop
2>/dev/nullonly to debug a failing run - read
-ofile for the result; don't parse the JSONL stream - long runs: Bash run_in_background, read
-ofile on exit; don't kill quiet runs <30 min - parallel independent tasks OK: separate repos/dirs, separate
-ofiles - outside a git repo add
--skip-git-repo-check
Follow-up fixes — cheaper than fresh runs, keeps context. resume has no -C: run from the repo dir and keep the long bypass flag:
ENGINE=(-c model="gpt-5.6-luna" -c model_reasoning_effort="max") # SAME engine AND effort as the original run
(cd <repo> && command codex exec resume --last \
--dangerously-bypass-approvals-and-sandbox \
"${ENGINE[@]}" \
-o /tmp/codex-last.md - <"$P2" 2>/dev/null)
Prompt contract
Codex starts with zero session context. Every prompt: goal, exact repo/paths, constraints, non-goals, proof expected (exact test command), output shape ("report files changed + test output"). Spec quality decides success.
Verify (Claude, always)
git status -sb+ read the full diff; judge like a contributor PR- run focused tests yourself or demand proof output; Codex claims are advisory
- iterate via resume; after 2 failed rounds, take over and do it directly
- normal closeout still applies:
$autoreviewbefore ship
Economics
Win = generation + exploration tokens moved to Codex; Claude spends only on spec + diff review. Don't ping-pong trivia through delegation; don't re-read what Codex already summarized.