| name | codex |
| description | Get a second opinion from OpenAI Codex CLI on difficult debugging, code analysis, or architecture problems, run a code/diff review (finder or adversarial-refuter passes over a diff or working tree), run a security review/audit or verification of security-sensitive code (auth, input validation, crypto, secrets), diagnose a bug, fan a repetitive bounded sweep (N-unit migrations, test conversions, mechanical refactors) across parallel codex lanes (individual bounded changes and large net-new code stay on Claude โ opus, fable only when the surface is very sensitive or error-prone), generate images (logos, mascots, banners, illustrations) with Codex's $imagegen skill, or offload rote throwaway work (one-off scripts, data munging) where code quality doesn't matter and nothing can go wrong. Use when reviewing code or a diff for defects, when auditing or verifying security-sensitive code, when diagnosing a bug, when stuck after multiple attempts, for a sweep of fully specified edits, when asked to generate an image, or for disposable bulk work. Runs inline in the caller's context โ safe to invoke from the main conversation, subagents, and workflows alike; workflow stages that must route to codex by agent type spawn the codex-wrapper agent this plugin ships. |
| allowed-tools | Bash(cat:*, codex:*, codex-ask:*, echo:*, ls:*, ${CLAUDE_SKILL_DIR}/../../bin/codex-ask:*), Read, Grep, Glob |
| effort | medium |
Codex CLI
Get a second perspective from OpenAI's Codex CLI when stuck on difficult problems,
run a code/diff review, security review/audit, or bug diagnosis, fan a
repetitive bounded sweep across parallel lanes, use its built-in $imagegen
skill to generate images, or offload rote throwaway work.
Every codex call runs through codex-ask, the executable this plugin ships.
Invoke it by its plugin-root path โ "${CLAUDE_SKILL_DIR}/../../bin/codex-ask",
substituted to a real path in this skill's text. The plugin's bin/ also rides
the Bash tool's PATH, but bare codex-ask resolves by PATH order, where a
brew-installed binary can shadow the plugin's symlink. The
script owns every mechanic: it pins -c model=gpt-5.6-sol -c model_reasoning_effort=xhigh -c service_tier=fast, runs
--sandbox danger-full-access with --skip-git-repo-check (runs work from
any cwd, repo or not), feeds the plugin's AGENTS.md via
-c developer_instructions (browser rules, the ยง Replies reply contract, no
ccx/MCP inside lanes โ so every run arrives knowing the house reply shape),
disables
MCP server mounts on the exec line, unsets OPENAI_API_KEY so codex always
authenticates via the ChatGPT-plan OAuth login (the ambient key is
billing-capped and never mounts the hosted image_gen tool), and keeps every
run's state under one fixed per-user base โ ${XDG_CACHE_HOME:-~/.cache}/codex-ask/runs/ โ
where any session can rediscover it (see Run Inventory). The plugin also ships
a guard hook that blocks hand-rolled codex exec and backgrounded codex-ask
calls: dispatch is foreground-only, because background Bash completion never
wakes an in-process subagent (claude-code#78782) and the script already
survives a killed or timed-out foreground call.
The fast tier is mandatory on every variant; without it, xhigh prompts can run
10โ30+ minutes and get abandoned. Keep questions bounded and specific: a narrow
question returns in ~2 minutes, an open-ended design essay does not.
When to Use
- Code/diff review โ sweeping a diff or codebase for bugs, correctness issues, or
cleanups, including finder and adversarial-refuter passes. This is the review
lane per the Models table; the synthesis/accept-reject pass over findings stays
with the caller (fable).
- Security review/audit and verification of security-sensitive code โ auth, input
validation, file paths, crypto, secrets. The primary security-verification lane
per the Models table: implementing that code stays on fable, this lane checks
the result, and the synthesis/accept-reject pass over findings stays with the
caller (fable). Routing here also quarantines dual-use payloads (exploit code,
vuln PoCs, malware analysis) outside the Claude session entirely, so the root
orchestrator never carries material that could trip fable's dual-use screening
and downgrade the session.
- Bug diagnosis โ the first stop; escalate to fable only when Codex's answer
misses.
- After 2+ failed approaches to the same problem
- Debugging subtle bugs (off-by-one, race conditions, state corruption)
- Analyzing complex algorithms against specifications
- Understanding unfamiliar code patterns, protocols, or file formats
- When a fresh perspective would break a deadlock
- Generating images -- logos, mascots, banners, illustrations -- via
$imagegen
(see Generating Images below)
- Rote, throwaway work -- one-off scripts, scratch harnesses, bulk data munging --
where code quality doesn't matter and nothing can go wrong. Codex's flat-rate
plan makes this effectively free; keep the output out of production paths.
- Repetitive bounded sweeps at scale -- N-unit test conversions, migrations, and
mechanical refactor passes fanned out as parallel lanes, where sol's per-task
token efficiency multiplied across the sweep still beats opus. Bounded
terminal/shell-heavy execution fits here too. An individual bounded,
decision-light change (a scoped edit, a signature change, a well-specified
small feature) now defaults to Claude opus -- since Opus 5 the two are tied on
capability with opus output cheaper -- and large amounts of net-new code stay
on Claude (opus xhigh, fable only when the surface is very sensitive or
error-prone): sol is much stronger at modifying
existing code than at authoring a large new subsystem from scratch, and
ambiguous or exploratory builds and decision-dense refactors stay on opus
too, since sol drifts out of scope and fails to converge on open-ended work;
long agentic runs are fable's lane. Production sweep edits are in range at
xhigh; review the diff as you would any other contributor's.
Model variants: pass -m luna for the rote/bulk and recon lanes. Routing,
escalation, and when each variant applies live in the fleet Models table
(CLAUDE.md ยง Plan Execution & Orchestration) โ the script pins tier and effort
regardless of variant. Escalation is cross-model for implementation: a sol
miss retries on opus xhigh, an opus miss on sol xhigh, and fable comes only
after both.
Browser Access
The AGENTS.md fed as developer instructions bans raw browser launches and
routes all browser/DOM work through the agent-browser CLI in the codex
namespace; the daemon auto-starts from inside codex. Routing every call through
codex-ask is what keeps that feed and the sandbox pin in place.
--sandbox danger-full-access means codex-generated commands run unsandboxed
on this machine โ a standing, user-sanctioned choice for these lanes; don't
"harden" it back to workspace-write.
From Workflows and Subagents (the codex-wrapper agent)
This skill runs inline (no context: fork), so Skill(codex) works
identically from the main conversation, subagents, and workflow steps. The
model parameter on Agent/Task calls and workflow agent() steps takes
only Claude models, so a workflow stage that should BE a codex call spawns
agent type codex:codex-wrapper with the full self-contained question โ or
file/diff pointers plus the questions to answer โ as the prompt. The wrapper is
also the lane for keeping big context (a large diff, many files) out of your
own window: it forwards the pointers, Codex pulls the material itself inside
the repo, and the wrapper returns Codex's answer verbatim.
The fan-out shape: disk is the record
A delegated agent's final message is a lossy channel; the deliverable lives on
disk. codex-ask persists every run's meta (reply/log paths), status,
question, reply, and log per run dir โ mv-atomic, written before any narration
exists. A register outcome (the transcript-registration result) lands in the
same dir, but best-effort and only after status: the orphaned worker writes it
once the caller has already unblocked, so it can trail the narration or even a
--collect. Drive a codex fan-out off that record, not off what the agents say:
- Mint the root and the roster. Before the fan-out the orchestrator runs
ROOT=$("${CLAUDE_SKILL_DIR}/../../bin/codex-ask" --mint-root <lane> [<lane>...] | sed -n 's/^ROOT: //p')
(lane paths: sed -n 's/^LANE: //p'; the sed masks a mint failure, so
guard [ -n "$ROOT" ] before use) โ the root lands under the fixed runs
base with one lane dir pre-created per agent (a lane that never runs must
be a visible no-run, not absent). Never hand-mint scratch. Pass the
lane dirs through the workflow args.
- Each prompt carries its lane. Every wrapper prompt includes a literal
-s "$ROOT/<lane>", so its state lands in the caller-minted dir. -s
takes only a --mint-root lane โ never the working copy, checkout, or
clone under review; codex-ask refuses such in-repo lanes.
- End with a collect stage. The last deterministic step runs
"${CLAUDE_SKILL_DIR}/../../bin/codex-ask" --collect "$ROOT" (a cheap run-this-exact-command agent that
returns stdout verbatim). It walks the roster and classifies each lane from
disk alone โ no-run / pending / running / died / completed /
failed โ as one JSONL record per lane, never inlining reply contents. The
gate consumes that JSONL against the roster; skipping collect starves the
gate rather than passing it.
- Reconcile, then redo only what truly failed. A lane reported "failed"
whose record is
completed is a paperwork failure โ recover its
reply_file, never re-dispatch. A lane reported "succeeded" that reads
no-run never ran. Implementation lanes also diff the tree, scoped to the
lane's expected fileset โ a shared working copy makes the tree truth about
the world, not attribution. Redo only no-run, died, and
genuinely-failed lanes. Lanes end at the working tree โ codex edits, Claude
ships: the commit and push happen natively after reconciliation
(ccx vcs ship), never inside a lane.
Returns by lane kind. Verdict lanes enforce a shipped schema by name โ
codex-ask --schema verdict for the {status, summary} micro-verdict,
--schema findings for a finder pass, --schema refutations for a refuter
pass (โ codex --output-schema; a JSON Schema file path still works).
Implementation lanes return prose led by their REPLY_FILE: pointer line.
Async Dispatch (owner subagents and the steering channel)
Blocking foreground is the default because a backgrounded completion never
wakes an in-process subagent โ the harness gap the guard hook exists for.
--dispatch is the sanctioned async path: the call returns as soon as the
worker detaches, and completion wakes the waiting agent through the codex-ask
steering channel instead of a Bash return.
- Know your agent id. It arrives in your greeting directive, the first
steering-channel message you see. No greeting means no channel โ use the
blocking flow instead.
- Dispatch async.
"${CLAUDE_SKILL_DIR}/../../bin/codex-ask" --dispatch --owner <agent-id> - <<'QUESTION'
(--owner requires --dispatch; --dispatch alone is fire-and-forget,
recovered via its AWAIT: line). The usual
REPLY_FILE:/LOG_FILE:/AWAIT: lines print, then the call returns with
the run still going.
- Park on
await. Call the await tool with your agent_id, sizing
timeout_seconds to the run โ xhigh typically returns in ~2 minutes, a
review sweep can take 10โ30. Progress pings hold a parked call open. An
elapsed window returns a "no directive" notice, not an error: first read
the run dir's status file โ a terminal state means another delivery rung
already drained the directive, so read the reply; re-park only while the
run is still going.
- On wake, read the disk. The directive names the run's terminal status
and reply file; it never carries the reply. Read the
REPLY_FILE: path
and evaluate per Step 3 below.
- A missed wake costs nothing. The wake is fail-open: a dead daemon
means no directive, never a lost run โ the
AWAIT: line
(codex-ask --await <run-dir>) recovers from any session. An owner that
finished before the wake landed gets collected by the relay: its parent is
nudged to wake it, and that wake is authorized โ call await to collect.
The fan-out shape above composes unchanged: the parent mints the root, spawns
one owner subagent per lane, each owner dispatches --dispatch --owner into
its lane with -s and parks; the daemon wakes owners as their runs finish,
and the terminal --collect still gates.
Top-level sessions use Monitor + --watch, not the channel. From the main
conversation โ the one place Monitor wakes actually deliver โ dispatch with
--dispatch alone, then arm Monitor on
"${CLAUDE_SKILL_DIR}/../../bin/codex-ask" --watch <run-dir>...
(fan-out roots expand to their lanes; --watch --all covers every in-flight
run). The watch emits one JSONL record per run as it settles โ completed,
failed, or died, never silence โ and exits once all watched runs have
settled. Arm it after dispatching: a lane that hasn't dispatched yet reads
no-run and settles immediately. Placement rule: top-level async is
Monitor + --watch; an owner subagent parks on await (Monitor wakes are
dropped inside subagents); a workflow stage's own dispatch stays
script-driven and blocking, though a workflow may spawn owner subagents that
park; a plain subagent without the channel foreground-blocks as ever.
Workflow
Step 1: Compose the Context
Codex answers only as well as the question scopes it, and it pulls its own
context inside the repo with standard shell tools (rg, sed, git โ ccx and MCP
tooling are disabled in lanes) โ so precision beats volume. Every question
carries:
- A clear problem statement with the specific error or symptom
- Precise pointers: exact file paths with line ranges (or
path:line#hash
cites) and the diff ref under review โ ccx vcs diff output, or the
instruction to run git diff. Once the material is more than a screenful,
pointers beat pasted walls of text; small context still inlines complete
functions (never truncated snippets).
- The narrowest test command that answers the question, scoped to the
affected packages โ name the full suite only when the suite itself is the
question. An unscoped "run the tests" invites a ten-minute re-run of work
that is already done.
- What has already been tried and why it failed
- The specific questions to answer. The reply shape ships with the plugin โ
every run carries the ยง Replies contract (answer first, fixed severities,
an evidence cite per claim), and
--lane <name> sharpens it for a standing
lane โ so spell out a shape only when you need a non-default one: a bare
artifact ("reply with ONLY the edited function"), which the contract
defers to
- Never a ship instruction โ don't ask Codex to commit, push, or ship: a
lane's deliverable is edits in the working tree plus its reply file, and
the caller ships natively (codex edits, Claude ships)
Step 2: Ask via codex-ask
Pipe the question through codex-ask in a foreground Bash call with a
10-minute timeout (timeout: 600000) โ xhigh on the fast tier typically
returns in ~2 minutes but can run longer. The script mints the run dir under
the fixed base, prints the REPLY_FILE:/LOG_FILE:/AWAIT: lines up front,
runs the pinned exec detached from the calling shell, redirects the JSONL
event stream into the log, and blocks until the reply is complete โ plus a log
tail on failure. Because the paths print first and the run survives its
caller's death, a killed or timed-out Bash call loses nothing: rerun the
AWAIT: line (codex-ask --await <run-dir>) in a fresh foreground call,
repeatedly if needed, until it exits. Asking the question again pays for work
that is already finishing.
Two flags shape the reply, and they are orthogonal โ never auto-coupled.
--lane <name> appends the sharpened contract for one of the six standing
lanes (review, refute, security, diagnose, implement, recon) on
top of the ยง Replies shape every run already carries; it shapes prose.
--schema <name|file> resolves a shipped schema by name โ verdict,
findings, refutations โ or takes a JSON Schema file, and maps to codex
--output-schema, which constrains the final assistant message itself: the
reply becomes that JSON in place of prose, never a JSON block decorating it.
"${CLAUDE_SKILL_DIR}/../../bin/codex-ask" - <<'QUESTION'
I have a [component] that fails with [specific error].
Here is the full function:
[paste complete code]
Key observations:
1. [What works]
2. [What fails]
3. [When it fails]
What has been tried:
- [approach 1 and why it failed]
- [approach 2 and why it failed]
Questions:
1. [specific question]
2. [specific question]
QUESTION
In place of - (stdin), codex-ask also takes a file path or literal text,
so a short question can go inline:
"${CLAUDE_SKILL_DIR}/../../bin/codex-ask" "Explain the JPEG progressive AC refinement algorithm". Every form
writes the question file, so the exchange keeps a durable record either way.
A review pass carries no format instructions โ the lane contract already pins
the shape (verdict line, severity-ordered findings, a cite per claim):
"${CLAUDE_SKILL_DIR}/../../bin/codex-ask" --lane review - <<'QUESTION'
Review the uncommitted diff in internal/render/ (run `git diff -- internal/render`).
Scope: every hunk. Focus: error handling and resource lifetimes.
Out of scope: pre-existing debt outside the diff.
QUESTION
Step 3: Evaluate the Reply
Read the reply file printed on the REPLY_FILE: line; it persists as a
durable record of the exchange. If the reply file is empty or missing, read
the tail of the LOG_FILE: JSONL โ the failing event is in the last lines.
Evaluate suggestions critically and verify against authoritative sources
before applying.
The codex skill never absorbs a surprise. If the reply invalidates the premise
of your question or changes the task's shape -- the bug isn't where you said,
the spec means something else, the fix belongs in a different layer -- stop
rather than improvising a detour: surface the finding with 2-4 concrete options
and let the user (or the fable orchestrator that delegated to you) pick. See
AGENTS.md ยง Ask Before Assuming. The same stop rules ride into codex itself
via ยง Replies, so a surprise arrives flagged -- a wrong premise led with, a
shape-change returned as findings plus 2-4 options -- rather than buried in
an improvised detour.
Return the answer in the exact shape the caller asked for โ a bare artifact
(an edited function, a file path) stays bare, never wrapped in analysis
boilerplate.
Run Inventory and Recovery (--ps)
Every run โ ad-hoc or fan-out โ lives under
${XDG_CACHE_HOME:-~/.cache}/codex-ask/runs/ (override: CODEX_ASK_RUNS_DIR,
absolute and outside any repo). The filesystem is the registry:
"${CLAUDE_SKILL_DIR}/../../bin/codex-ask" --ps walks the base and prints one JSONL record per run โ state
(the collect classification), pid, start time, log age, cwd, session โ
pruning only long-terminal runs. A run whose caller died, compacted, or was
never woken is not lost: any session can find it here and recover with
"${CLAUDE_SKILL_DIR}/../../bin/codex-ask" --await <run-dir> (single run)
or "${CLAUDE_SKILL_DIR}/../../bin/codex-ask" --collect <root> (fan-out
root).
- Before re-dispatching anything that "seems dead", check
--ps first โ a
wedged run is visible (old log age, live pid) and killable; a completed one
has its reply on disk.
Generating Images ($imagegen)
Codex ships a built-in $imagegen skill backed by a hosted image_gen tool
(model gpt-image-2). Mentioning $imagegen anywhere in the prompt loads the
skill; it works with non-interactive codex exec.
Availability: the hosted tool mounts only when codex is signed in with a
ChatGPT plan -- check codex login status. With API-key auth it never mounts,
and codex will quietly fake the image by drawing it with PIL/ImageMagick instead.
codex-ask unsets OPENAI_API_KEY for exactly this reason, so the login
state from codex login status is what counts. Two defenses, use both:
- Pass
--image so codex cannot draw -- it adds --disable shell_tool,
and with no shell codex either calls image_gen or reports the tool
missing.
- Tell it to fail loudly: "If the image_gen tool is unavailable, reply
IMAGE_GEN_UNAVAILABLE and stop."
With the shell disabled, codex cannot write into your repo. Generations land in
$CODEX_HOME/generated_images/ (default ~/.codex/generated_images/); have the
reply list the saved paths, then copy and post-process the files yourself.
"${CLAUDE_SKILL_DIR}/../../bin/codex-ask" --image - <<'PROMPT'
Use $imagegen to create a square 1024x1024 logo for [project]: [subject], flat
illustration, bold clean shapes, on a solid bright-green background (it will be
chroma-keyed out locally). If the image_gen tool is unavailable, reply
IMAGE_GEN_UNAVAILABLE and stop. End your reply with the absolute path of the
saved file on its own line.
PROMPT
Then place and post-process yourself (read the path from the REPLY_FILE: line):
uv run --with pillow "${CODEX_HOME:-$HOME/.codex}/skills/.system/imagegen/scripts/remove_chroma_key.py" \
--input <saved path> --out assets/logo.png --auto-key border --soft-matte --despill
Confirm with ls, then view each file with Read (it renders images) and iterate
with a refined prompt if needed.
Model limits to design around:
- No native transparency -- gpt-image-2 always paints a background. Generate
on a solid chroma-key background and remove it locally with the bundled
remove_chroma_key.py helper (as above; it needs only Pillow, hence
uv run --with pillow).
- Fixed native sizes -- 1024x1024, 1536x1024 (landscape), 1024x1536
(portrait). For other ratios, ask for the content composed in a known band
and crop locally:
sips -c H W <src> --out <dst> on macOS, or ImageMagick
magick <src> -gravity center -crop WxH+0+0 +repage <dst>.
- Text renders accurately -- names and taglines inside images come out
right; quote the exact strings in the prompt.
- Style drifts across sessions -- generate related images in ONE codex
session so characters and palette stay consistent.
- Fallback CLI for API-key machines --
${CODEX_HOME:-$HOME/.codex}/skills/.system/imagegen/scripts/image_gen.py
(requires OPENAI_API_KEY) offers explicit sizes and
gpt-image-1.5 --background transparent for native transparency. Run it
directly; no codex session needed.
Common Issues
No output: read the tail of the LOG_FILE: JSONL โ the failing event is
in the last lines.
Call killed or timed out mid-run: the run is still alive โ codex-ask
detached it and printed the AWAIT: line before starting. Rerun that command
in a fresh foreground Bash call (same 10-minute timeout), repeating until it
exits.
Reported result doesn't match the tree: trust the disk, not the narration.
Run "${CLAUDE_SKILL_DIR}/../../bin/codex-ask" --collect over the lane root
(or --ps for ad-hoc runs). A
lane reported failed whose record says completed is a paperwork failure โ
recover the answer from its reply_file, don't re-dispatch. A lane reported
successful over an untouched, scoped tree diff never actually ran.
Timeout: exec mode never prompts and the fast tier is pinned, so a call
dragging past a few minutes means the question is unbounded โ broad open-ended
prompts are the usual cause.
Reply ignores the contract (buried verdict, missing severities, uncited
claims): every run carries AGENTS.md ยง Replies as developer instructions, and
the caller's requested shape wins over it โ so first check the prompt for a
stray shape instruction. When the run fits a standing lane, re-ask with
--lane <name>: the lane contract pins the shape harder than the house
default.
Asked for prose, got JSON (or wanted JSON, got prose): --schema maps to
codex --output-schema, which constrains the final assistant message โ the
reply is that JSON in place of prose, never alongside it. Drop --schema for
a narrative answer; add it for a machine-checkable one. --lane shapes prose
and never implies a schema.
Turn fails with "flagged for possible cybersecurity risk": OpenAI's content
filter killed the run, not codex-ask. It keys on offensive-security phrasing, so
a security review or adversarial-verification prompt written as an attack โ
"reproduce the exploit", "the kill sequence", stubs that trap signals โ can trip
it even when the intent is defensive. Reframe clinically ("verify the process
survives the harness's standard timeout-termination") and split a broad sweep
into per-topic calls so one hit loses less. Offensive-framed reviews belong on
the Claude lane, which has no such filter.
IMAGE_GEN_UNAVAILABLE: codex is signed in with an API key (codex login status), not a ChatGPT plan โ the hosted tool never mounts. Use the fallback
CLI from Generating Images instead.
Images not in the repo: expected โ with --disable shell_tool codex can't
write into the workspace; generations stay in $CODEX_HOME/generated_images/
and copying them in is your job.
Solid box behind a "transparent" logo: chroma-key removal was skipped --
gpt-image-2 has no native transparency; use the remove_chroma_key.py step.