Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Dual-AI code analysis pairing OpenAI Codex with Claude code-searcher — the lightest consult variant, two citation-verified perspectives. Use for a quick second opinion on a code question.
.claude/skills/centminmod-consult-codex/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-09 | ✗→✓ | ▲ Improved | 260% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 289% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 302% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 347% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 239% | 0% |
You orchestrate consultation between OpenAI's Codex and Claude's code-searcher to provide comprehensive analysis with comparison.
High value queries:
Lower value (single AI may suffice):
When the user asks a code question:
Problem-restate pre-flight (non-blocking). Before building the prompt, emit ONE line restating the code question you are about to dispatch (and, only if genuinely ambiguous, the alternative reading), then proceed:
> Reading this as: «one-line restatement» (alt: «other reading», if any) — proceeding to consult; interrupt now to correct the framing.
Emit-and-proceed — do not ask-and-wait (the orchestrator can't reliably detect its own misframing). One line, and it guards the whole dispatch against a wrong-framing run.
Wrap the user's question with structured output requirements:
`[USER_QUESTION] === Analysis Guidelines === **Structure your response with:** 1. **Summary:** 2-3 sentence overview 2. **Key Findings:** bullet points of discoveries 3. **Evidence:** file paths with line numbers (format: `file:line` or `file:start-end`) 4. **Confidence:** High/Medium/Low with reasoning 5. **Limitations:** what couldn't be determined **Line Number Requirements:** - ALWAYS include specific line numbers when referencing code - Use format: `path/to/file.ext:42` or `path/to/file.ext:42-58` - For multiple references: list each on a SEPARATE line with its own file path (avoid comma-separated multi-citation like `file.ts:45, 67, 98`) - Include brief code snippets for key findings **Examples of good citations:** - "The authentication check at `src/auth/validate.ts:127-134`" - "Configuration loaded from `config/settings.json:15`" - "Error handling in `lib/errors.ts:45`, `lib/errors.ts:67-72`, and `lib/errors.ts:98`" **Citations Index (required):** end your response with a fenced block, one line per Key Finding (repeat each block entry's `file:line` inline in the finding as usual):
<finding #> — path/to/file.ext:LINE-END]
Severity / no-manufacture block — ORCHESTRATOR-GATED. Append the block below to both agents' prompts identically ONLY when the query is a defect hunt / code review (bug, security audit, "what's wrong with…", "review this"). OMIT it for explanatory / "how does X work" questions, where "found nothing" is not meaningful. The orchestrator — which knows the query type — makes this include/omit decision once, BEFORE writing the prompt files; do not leave it to each agent to self-classify. When included, append exactly these two bullets (the text only — no leading marker):
Setup (run first). $CLAUDE_PROJECT_DIR is not always exported into the Bash tool shell, so resolve it with a $PWD fallback and ensure the tmp dir exists. Substitute the resolved literal path for $PROJECT_DIR, and a freshly generated RUN_ID (seconds-resolution + 4-char nonce, e.g. run-2026-05-25-143052-a7f3), into every command below. The RUN_ID in temp filenames prevents collisions between two concurrent invocations sharing $PROJECT_DIR/tmp.
bashPROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD}" # Validate BEFORE creating tmp — `mkdir -p` would otherwise make the check pass even # for a bad path (it creates the dir, then `[ -d ]` always succeeds). [ -d "$PROJECT_DIR" ] || { echo "ERROR: PROJECT_DIR '$PROJECT_DIR' is not a directory" >&2; exit 1; } mkdir -p "$PROJECT_DIR/tmp" # Pre-flight (fail fast, not after a 10-min hang). jq is a HARD dependency — output # parsing needs it — so abort now rather than warn-and-continue into opaque failures. command -v jq >/dev/null 2>&1 || { echo "ERROR: 'jq' not found — required for output parsing; aborting" >&2; exit 1; } # codex is a soft dependency — the CODEX_BIN resilience block below resolves or SKIPs it. command -v codex >/dev/null 2>&1 || \ zsh -i -c "type codex" >/dev/null 2>&1 || \ bash -i -c "type codex" >/dev/null 2>&1 || \ echo "WARNING: 'codex' not found — will attempt nvm resolution below, else SKIP" # Sweep stale orphans (>60 min) from crashed prior runs (best-effort, age-based — # can theoretically delete a live run's files if it paused >60 min; acceptable). find "$PROJECT_DIR/tmp" -maxdepth 1 -name '*-prompt-*.txt' -mmin +60 -delete 2>/dev/null find "$PROJECT_DIR/tmp" -maxdepth 1 -name '*-output-*.jsonl' -mmin +60 -delete 2>/dev/null
Codex binary resilience (run once, before dispatch). An nvm-managed codex can be a symlink whose @openai/codex install is broken (deleted vendor binary → spawn ... ENOENT), and a broken version can sit EARLIER on PATH than a working one. command -v / zsh -i return the broken path, so detect by RUNNING the binary. If the PATH-resolved codex fails, hunt all nvm node installs for one whose --version succeeds and emit its absolute path. Emit CODEX_BIN=SKIP if none work.
bashCODEX_BIN=""; INTERACTIVE_SHELL=zsh # Capture WHICH interactive shell resolves codex (nvm may be in only one of # ~/.zshrc / ~/.bashrc). The dispatch below uses $INTERACTIVE_SHELL so a # .bashrc-only setup on macOS still works (prior bug: probe accepted bash, # dispatch hardcoded zsh). if zsh -i -c 'codex --version' >/dev/null 2>&1; then CODEX_BIN="codex"; INTERACTIVE_SHELL=zsh # codex resolves via zsh elif bash -i -c 'codex --version' >/dev/null 2>&1; then CODEX_BIN="codex"; INTERACTIVE_SHELL=bash # codex resolves via bash else # Match symlinks too (-type l): nvm/npm install codex as a bin/ symlink, which -type f misses. CODEX_BIN=$(find "$HOME/.nvm/versions/node" -maxdepth 5 -name codex \( -type f -o -type l \) 2>/dev/null | while IFS= read -r p; do "$p" --version >/dev/null 2>&1 && { printf '%s\n' "$p"; break; } done) [ -z "$CODEX_BIN" ] && CODEX_BIN="SKIP" fi echo "CODEX_BIN=$CODEX_BIN" # MUST echo: shell vars don't persist across Bash tool calls echo "INTERACTIVE_SHELL=$INTERACTIVE_SHELL" # the interactive shell that resolves codex; substitute into the dispatch below # Resolve the timeout binary used to wrap the Codex gen dispatch (§Step 2 below) so a # hung CLI is bounded rather than running unbounded — the harness may auto-background # the dispatch, letting it escape the Bash tool's own timeout. Probe BOTH names: # Homebrew coreutils installs GNU timeout as `gtimeout`; plain `timeout` exists only # when the coreutils gnubin PATH is on. If neither exists, TIMEOUT_CMD stays empty and # the dispatch runs UNWRAPPED (best-effort Bash-tool timeout; `brew install coreutils` # restores the hard guard). TIMEOUT_CMD="" if command -v timeout >/dev/null 2>&1; then TIMEOUT_CMD="timeout" elif command -v gtimeout >/dev/null 2>&1; then TIMEOUT_CMD="gtimeout" fi echo "TIMEOUT_CMD=$TIMEOUT_CMD" # substitute into the §Step-2 Codex dispatch (when empty: omit the wrap)
Two-phase dispatch (required). Tool calls in one message run concurrently, so emitting the Codex prompt-file Write and the Codex dispatch together races the dispatch ahead of the file (Codex errors on a missing prompt file). Use two messages: message 1 writes the Codex prompt file (Step 1 below); message 2 issues the Codex dispatch (Step 2) and the Code-Searcher Agent call in parallel:
Gen-dispatch timeout watchdog (GEN_TIMEOUT=1200). Each $TIMEOUT_CMD -k 10 1200-prefixed CLI gen below — SIGTERM at 1200s (20 min), SIGKILL 10s later (-k 10, which also reaps orphaned Node/MCP children) — is bounded against a hung provider CLI that would otherwise run unbounded (the harness may auto-background the dispatch, so the Bash tool's own timeout is not a reliable cap). When TIMEOUT_CMD is empty (no timeout/gtimeout): omit the $TIMEOUT_CMD -k 10 1200 prefix and dispatch unwrapped (the existing §Setup fallback) — set the Bash tool's own timeout parameter to 1300000 ms as a best-effort cap, and brew install coreutils to restore the hard guard. On a timed-out gen (exit 124 = SIGTERM, 137 = SIGKILL): the output file is empty/truncated, so the existing [ -z … ] parse guard already drops the agent — additionally surface Agent X timed out after 1200s (distinct from an auth failure, which leaves non-empty stderr) and re-count against the §Setup minimum-agent guard. Do not retry. Code-Searcher (Agent tool) carries no $TIMEOUT_CMD -k 10 1200 prefix — it is bounded by its own mechanism, not this watchdog.
Model ownership — the model is CONFIG-OWNED, never named by this skill. Do not pass -m: inherit the model and reasoning effort from Codex configuration (~/.codex/config.toml — this installation is configured for gpt-5.6-sol, high effort). Report the agent as plain "Codex" everywhere in the report; never a hardcoded version string. A hardcoded label silently misreports the model the moment the config changes: this skill advertised GPT-5.6-terra in seven places while every dispatch had been running gpt-5.6-sol, because the dispatch carries no -m and never did (corrected 2026-08-01).
Step 1: Write the enhanced prompt to a temp file using the Write tool: Write to $PROJECT_DIR/tmp/codex-prompt-RUN_ID.txt with the ENHANCED_PROMPT content
Step 2: Execute Codex (allow ~10 min; Codex can be slow). Pipe the prompt via stdin and capture the JSONL event stream to a file.
Pick the form based on CODEX_BIN from Setup:
CODEX_BIN=codex → use the interactive-shell form below ($INTERACTIVE_SHELL resolved in Setup).CODEX_BIN is an absolute path → use the absolute-path form (calls thebinary directly so PATH ordering can't shadow it again).
CODEX_BIN=SKIP → no working codex; skip this dispatch, present only theCode-Searcher response. Label the report a degraded single-AI run — Code-Searcher is the sole agent, so there is no cross-comparison — and note that a direct Read or a lighter path would have been cheaper. Record the skip in §4 (error handling) / §5 (comparison report).
macOS/Linux (CODEX_BIN=codex; $INTERACTIVE_SHELL = the zsh|bash literal resolved in Setup): bash cat "$PROJECT_DIR/tmp/codex-prompt-RUN_ID.txt" \ | $TIMEOUT_CMD -k 10 1200 $INTERACTIVE_SHELL -i -c "codex exec -s read-only --json -C '$PROJECT_DIR' 2>&1" \ > "$PROJECT_DIR/tmp/codex-output-RUN_ID.jsonl"
Absolute-path (CODEX_BIN resolved to a path — macOS & Linux): substitute the literal absolute path for CODEX_BIN_LITERAL; no shell wrapper needed. bash cat "$PROJECT_DIR/tmp/codex-prompt-RUN_ID.txt" \ | $TIMEOUT_CMD -k 10 1200 CODEX_BIN_LITERAL exec -s read-only --json -C "$PROJECT_DIR" \ > "$PROJECT_DIR/tmp/codex-output-RUN_ID.jsonl" 2>&1
Why this exact form (each piece prevents a failure seen in practice):
-s read-only is the portable Codex sandbox flag — it needs no~/.codex/config.toml [profiles.readonly] entry, unlike -p readonly (which silently misbehaves when that profile is absent).
cat … | …) instead of "$(cat …)" avoids theReading additional input from stdin... hang (Codex waits on stdin when the prompt is passed as a positional) and ARG_MAX limits on large prompts.
-C '$PROJECT_DIR' — outer-shell single-quote expansion of an absolutepath — gives Codex project context. Do NOT pass the dir via an inner-shell positional (-C "$0"/literal placeholders): besides being fragile, a skill loaded WITH user arguments has its $0/$1/$2 rewritten by Claude Code's argument substitution, so a wrong-bound $0 produces a cryptic Error: No such file or directory (os error 2).
Parse $PROJECT_DIR/tmp/codex-output-RUN_ID.jsonl with the §2a recipes.
subagent_type: "code-searcher" with the same enhanced prompt (plus the orchestrator-gated Severity block above on defect-hunt runs)code-searcher, Explore, general-purpose, or any other subagent; use Read/Grep/Glob/Bash directly, however many calls that takes." Code-searcher runs with all tools and fans out unprompted on Sonnet 5 (reported live 2026-08-01); a sub-agent inherits none of this run's constraints, and the Agent-tool call carries no dispatch watchdog — a stalled fan-out underneath it stalls the whole consult. (consult-panel §1d carries the full form of this guard.)This parallel execution significantly improves response time.
--json Output Files (jq Recipes)Codex CLI with --json typically emits newline-delimited JSON events (JSONL). Some environments may prefix lines with terminal escape sequences; these recipes strip everything before the first { and then fromjson? safely.
Set a variable first:
bashFILE="$PROJECT_DIR/tmp/codex-output-RUN_ID.jsonl" # the file the §2 dispatch redirected to
List event types (top-level .type)
bashjq -Rr 'sub("^[^{]*";"") | fromjson? | .type // empty' "$FILE" | sort | uniq -c | sort -nr
List item types (nested .item.type on item.completed)
bashjq -Rr 'sub("^[^{]*";"") | fromjson? | select(.type=="item.completed") | .item.type? // empty' "$FILE" | sort | uniq -c | sort -nr
Extract only “reasoning” and “agent_message” text (human-readable)
bashjq -Rr ' sub("^[^{]*";"") | fromjson? | select(.type=="item.completed" and (.item.type? | IN("reasoning","agent_message"))) | "===== \(.item.type) \(.item.id) =====\n\(.item.text // "")\n" ' "$FILE"
Extract ALL agent_message events (Codex frequently emits multiple; extracting only the last would truncate the answer)
bashout=$(jq -Rr ' sub("^[^{]*";"") | fromjson? | select(.type=="item.completed" and .item.type?=="agent_message") | .item.text // empty ' "$FILE") [ -z "$out" ] && echo "ERROR: Codex produced no agent_message events — check the raw output for errors" >&2 printf '%s\n' "$out"
Build a clean JSON array for downstream tools
bashjq -Rn ' [inputs | sub("^[^{]*";"") | fromjson? | select(.type=="item.completed" and (.item.type? | IN("reasoning","agent_message"))) | {type:.item.type, id:.item.id, text:(.item.text // "")} ] ' "$FILE"
Extract command executions (command + exit code), avoiding huge stdout/stderr
Codex JSON schemas vary slightly; this tries multiple common field names.
bashjq -Rr ' sub("^[^{]*";"") | fromjson? | select(.type=="item.completed" and .item.type?=="command_execution") | [ (.item.id // ""), (.item.command // .item.cmd // .item.command_line // "<no command field>"), (.item.exit_code // .item.exitCode // "<no exit>") ] | @tsv ' "$FILE"
Discover actual fields present in command_execution for your environment
bashjq -Rr ' sub("^[^{]*";"") | fromjson? | select(.type=="item.completed" and .item.type?=="command_execution") | (.item | keys | @json) ' "$FILE" | head -n 5
After processing the Codex response (success or failure), clean up the temp files:
bashrm -f "$PROJECT_DIR/tmp/codex-prompt-RUN_ID.txt" "$PROJECT_DIR/tmp/codex-output-RUN_ID.jsonl"
This prevents stale prompts from accumulating and avoids potential confusion in future runs.
Use this exact format:
Raw output from codex-cli agent]
Raw output from code-searcher agent]
(MANDATORY — always render this table on a multi-agent run; it is the at-a-glance visual diff readers rely on, so never skip it. Omit only in a degraded single-AI run, where there is nothing to compare.)
| Aspect | Codex | Code-Searcher (Claude) | |--------|-----------------|------------------------| | File paths | Specific/Generic/None] | Specific/Generic/None] | | Line numbers | Provided/Missing] | Provided/Missing] | | Code snippets | Yes/No + details] | Yes/No + details] | | Unique findings | List any] | List any] | | Accuracy | Note discrepancies] | Note discrepancies] | | Strengths | Summary] | Summary] |
State which level applies and explain]
Bucket each distinct finding by how many agents independently reached it:
dual has no citation-verification stage, so it is agreement, not verified correctness.
(Cluster findings across agents by their claim + file:line — the Citations Index blocks make this pairing mechanical. On a defect-hunt run, tag each listed finding with its agent-assigned Severity — Critical/Warning/Info.)
Combine the best insights from both sources into unified analysis. Prioritize findings that are:
Which source was more helpful for this specific query and why. Consider:
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-08 | fail→fail | 9,991 | 7,496 | -25% | 1 | 1 | 0% | 1,823 | 6,496 | +256% | 0 | 0 | — |
case-01 | fail→fail | 26,798 | 8,756 | -67% | 1 | 1 | 0% | 4,754 | 6,928 | +46% | 0 | 0 | — |
case-02 | fail→fail | 25,128 | 6,115 | -76% | 1 | 1 | 0% | 5,040 | 6,262 | +24% | 0 | 0 | — |
case-09 | fail→pass | 13,311 | 11,249 | -15% | 1 | 1 | 0% | 2,129 | 7,662 | +260% | 0 | 0 | — |
case-03 | fail→fail | 11,048 | 22,341 | +102% | 1 | 1 | 0% | 1,252 | 6,301 | +403% | 0 | 0 | — |
case-04 | pass→fail | 7,790 | 10,121 | +30% | 1 | 1 | 0% | 1,454 | 7,151 | +392% | 0 | 0 | — |
case-05 | fail→fail | 5,302 | 8,619 | +63% | 1 | 1 | 0% | 816 | 6,868 | +742% | 0 | 0 | — |
case-06 | pass→pass | 7,662 | 4,836 | -37% | 1 | 1 | 0% | 1,271 | 6,168 | +385% | 0 | 0 | — |
case-07 | fail→fail | 23,034 | 6,791 | -71% | 1 | 1 | 0% | 4,302 | 6,475 | +51% | 0 | 0 | — |
case-10 | fail→pass | 11,327 | 14,091 | +24% | 1 | 1 | 0% | 2,026 | 7,890 | +289% | 0 | 0 | — |
case-11 | fail→pass | 10,494 | 11,613 | +11% | 1 | 1 | 0% | 1,901 | 7,649 | +302% | 0 | 0 | — |
case-12 | fail→pass | 8,241 | 8,730 | +6% | 1 | 1 | 0% | 1,564 | 6,986 | +347% | 0 | 0 | — |
case-13 | fail→fail | 18,251 | 3,086 | -83% | 1 | 1 | 0% | 1,863 | 6,010 | +223% | 0 | 0 | — |
case-14 | fail→pass | 11,377 | 7,532 | -34% | 1 | 1 | 0% | 2,049 | 6,946 | +239% | 0 | 0 | — |
case-15 | fail→pass | 14,311 | 7,783 | -46% | 1 | 1 | 0% | 2,424 | 6,799 | +180% | 0 | 0 | — |
case-16 | fail→pass | 9,573 | 4,687 | -51% | 1 | 1 | 0% | 1,302 | 6,394 | +391% | 0 | 0 | — |
case-17 | pass→pass | 6,621 | 3,210 | -52% | 1 | 1 | 0% | 1,075 | 6,015 | +460% | 0 | 0 | — |
case-18 | pass→pass | 6,871 | 5,904 | -14% | 1 | 1 | 0% | 1,230 | 6,375 | +418% | 0 | 0 | — |
case-19 | fail→pass | 8,327 | 4,348 | -48% | 1 | 1 | 0% | 1,591 | 6,214 | +291% | 0 | 0 | — |
case-20 | fail→pass | 10,410 | 5,647 | -46% | 1 | 1 | 0% | 1,778 | 6,368 | +258% | 0 | 0 | — |
case-21 | fail→fail | 13,336 | 7,364 | -45% | 1 | 1 | 0% | 2,284 | 6,493 | +184% | 0 | 0 | — |
case-22 | fail→fail | 13,123 | 8,216 | -37% | 1 | 1 | 0% | 2,314 | 6,483 | +180% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +27 percentage points is the difference between those two pass rates over the 22 comparable cases. 4 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.