Imported from Lucklyric/super-tmux (
plugins/tmux-agent/skills/codex/SKILL.md). Install upstream withnpx skills add Lucklyric/super-tmux --skill codex. Copyright stays with the author.
name: codex description: This skill should be used whenever the user names codex as the actor for ANY task, regardless of verb or phrasing — "use codex" / "using codex", "ask codex", "run codex", "call codex", "have/let/tell/get codex do X", "delegate this to codex", "with/via codex", "codex cli", "codex: ", or bare imperatives like "codex review/fix/implement …" — or explicitly asks to delegate work to a frontier reasoning model (e.g., "have GPT-5 review this", "get the OpenAI reasoning model to design X", "ask the high-reasoning model"). Also triggers on "continue codex" / "resume the codex session" for iterative development, and on "have codex review this PR / branch / diff / my changes" for delegated code review. Do NOT trigger when codex / GPT-5 is merely a discussion topic rather than the requested actor.
Codex: High-Reasoning AI Assistant for Claude Code
Use OpenAI's Codex CLI (GPT-5.6 series — default gpt-5.6-sol, xhigh reasoning) for complex coding, architecture, and review work that benefits from a frontier reasoning model. Pick the 5.6 model + effort by task (see "Model and reasoning effort"). Requires codex CLI ≥ 0.144.0 for the 5.6 series.
Default mode is tmux. Codex runs in a long-lived attachable tmux pane/window — a co-worker at the user's side — so the user can watch, intervene, and iterate. The helper script handles the whole loop: lifecycle (pane / panes / bind / new / ls / kill) and the driving verbs (prompt / wait / read --delta / cancel) — send, settle-detection, and delta extraction are script commands with clean exit codes, not hand-rolled tmux loops. A codex exec escape hatch exists but is gated: use it only when the user explicitly asked for headless, or after confirming (see "Codex is a co-worker in a pane").
One codex pane in your current window by default. When Claude is running inside tmux, codex runs as a PANE split into your CURRENT tmux window — right next to Claude — so you can watch progress live with NO separate attach. In the normal case there is one codex pane per Claude session, reused for every task (call pane first; it is idempotent). (A duplicate pane can occur if the Claude session id rolls — recover with kill %id, or kill --mine then re-resolve.) When Claude is NOT inside tmux, it falls back to a dedicated reused window codex-<claude6> in the cc-codex session (call bind). Only spawn an extra pane when the user explicitly asks for a parallel task (pane --topic <slug> — still in the current window; see "Detecting & orchestrating multiple codex panes"), and an extra window (new) only when the user explicitly asks for a separate window. The generic agentic-tmux concepts behind this (identity & naming patterns, send/capture/idle-detect, sync/locking, lifecycle) live in the tmux-agent skill (this plugin); this skill links to it and keeps only codex-specifics. Daily tmux fundamentals (session/window/pane model, layouts, copy-mode) live in the tmux skill of the tmux-core plugin, declared as a dependency so it auto-installs.
Agent-session isolation (hard rule). Codex is bound to THIS agent's
claude6. Every operation the skill performs — resolve/reuse, relocate (join-pane), spawn, and cleanup viakill --mine/kill %id— touches ONLY this session's own codex pane/window, identified by the@cc_codex_claude6marker. Never move, kill, reuse, or otherwise disturb a tmux pane or window belonging to another agent (a differentclaude6) or one you did not create. In particular, do not runkill --orphanedas part of normal work — it is a global, cross-agent housekeeping command that reaps every agent's dead codex, and is appropriate only when the user explicitly asks to clean up everything.
Codex is a co-worker in a pane — when (if ever) to use exec
Mental model: codex is a co-worker sitting in a pane at the user's side. Every codex task goes to that ONE visible, reused pane by default: if the co-worker pane exists, hand the task to it; if not, spawn it. The user watches codex work — a headless codex is a surprise, never a convenience. Task shape (short, review-like, parallel, "one-shot-ish") is not a reason to go headless.
| Situation | Route |
|---|---|
| Any codex task, unless a row below says otherwise | THE reused co-worker pane (resolve-target snippet below). |
| Multiple codex workers ("two reviewers", "in parallel", "another codex for X") | One pane --topic <slug> per worker, all in the current window — NOT multiple exec one-shots. |
| User explicitly asks for headless: "headless", "no pane", "exec", "fire and forget", "don't spawn" | exec one-shot. |
User explicitly invokes codex review / codex apply on a diff / branch / commit / PR and wants the report, not to watch |
codex review one-shot (see "Delegating a code review"). |
| A hook or automation calls codex (no user watching) | exec one-shot. |
| You think headless would fit better, but the user did not ask for it | Confirm first — e.g. "Run this as a quick headless one-shot, or in your codex pane as usual?" If you don't ask, use the pane. |
Reuse before spawn; fresh only on request. The co-worker keeps its conversation context across tasks — that is the point. Do not restart or replace it because a new task feels unrelated. Only when the user explicitly says "new pane", "fresh codex", "new context", "fresh context", "start over" do you reset: kill "$TARGET" + re-resolve (fresh codex in the same slot), or pane --topic <slug> if they want an ADDITIONAL worker alongside the current one.
Default workflow: codex pane in the current window
By default, resolve THE codex target for this Claude session, then drive ALL interaction against it. When Claude is inside tmux the target is a PANE split into the current window (visible right next to Claude); when Claude is not inside tmux it is a dedicated cc-codex window. This snippet is the canonical opening of every codex interaction:
# Helper path. The CLAUDE_PLUGIN_ROOT placeholder (braces form) is replaced with
# this plugin's absolute install path when the skill is loaded via the Skill
# tool, so the next line already reads as a literal path — copy it verbatim at
# the top of EVERY Bash call (each call is a fresh shell; nothing is exported).
CODEX="${CLAUDE_PLUGIN_ROOT}/scripts/codex-tmux.sh"
# Resolve THE codex target. Default: a pane in the current window. bind (a
# cc-codex window) is ONLY for exit 3 (not inside tmux) and exit 4 (codex died
# at launch, after one auto-retry). Anything else — 127 wrong path, 2 bad flag —
# means STOP and surface it; never fall through to bind.
if [[ -n "${TMUX:-}" ]]; then _out=$("$CODEX" pane --cwd "$PWD"); _rc=$?; else _rc=3; fi
case $_rc in
0) TARGET=$(printf '%s\n' "$_out" | head -n1) ;; # pane id, e.g. %53
3|4) TARGET="cc-codex:$("$CODEX" bind --cwd "$PWD" | head -n1)" ;; # fallback window
*) unset TARGET; echo "codex-tmux.sh pane failed (exit $_rc; 127 = wrong helper path → re-invoke the tmux-agent:codex skill) — NOT falling back to bind" >&2 ;;
esac
# Now drive "$TARGET" with the verbs (prompt --wait → read --delta).
Capture pane's output to a variable first and branch on its real exit code (do not pipe straight into head — that masks the exit code and yields an empty TARGET). Only exit 3 ("not inside tmux") and exit 4 (codex died on launch, after one auto-retry) route to the bind fallback; a re-run also recovers exit 4. Any other failure — above all exit 127 / "No such file or directory", which means the helper path is wrong — must stop the flow and be surfaced, never routed to bind. A bare pane || bind guard is exactly how a session running inside tmux ends up with a stray cc-codex window instead of a pane.
The CODEX= line above is a literal absolute path once this skill is loaded: the Skill tool substitutes the braces placeholder. It is not an exported environment variable — bare $CLAUDE_PLUGIN_ROOT is empty inside the Bash tool, so never type that form into a command. Re-state the literal CODEX= line at the top of every Bash call (each call is a fresh shell), and if the path ever fails, re-invoke the skill rather than guessing.
$TARGET is target-agnostic — it is a pane id (e.g. %53) inside tmux, or cc-codex:<window> in the fallback. The driving verbs default to this session's main pane, so inside tmux you rarely pass it; in the fallback (or for explicit addressing) pass --target "$TARGET". Both pane and bind are idempotent: they reuse the live codex if alive, relaunch codex inside the kept shell if it exited (see below), and respawn if dead — so follow-ups, continuations, and new sub-tasks all land in the same pane/window. You do not need find or a topic slug for the normal case. Pass --full-auto on the first pane/bind call for write mode (default is --read-only); the sandbox is fixed while codex runs (a relaunch after codex exited applies the newly requested sandbox).
When codex exits, the pane stays (keep-shell default). Exiting codex (the user quits the TUI, or it crashes) does NOT close the pane: it drops into an interactive shell in the same pane — scrollback intact, usable manually (e.g. the user can run
codex resume --lastto continue the conversation by hand, or any other command). Typingexitin that shell closes the pane.panes/lsreport such a target as stateshell, and the nextpane/bindcall relaunches codex inside it (same pane, no new split). SetCC_CODEX_KEEP_SHELL=0for the legacy behavior (codex exit closes the pane perCC_CODEX_REMAIN_ON_EXIT).
Spawn an EXTRA codex ONLY when the user explicitly asks for a genuinely separate or parallel codex. Route the phrasing: "in parallel", "a second codex", "also start another", "keep this one running and…", "don't interrupt the current task", "spin up another" → an extra PANE in the CURRENT window via pane --topic <slug> (see "Detecting & orchestrating multiple codex panes"). "separate window" / "new window" → an extra WINDOW via new <topic>. A new tmux session is created only ever on an explicit user request. For everything else, the single reused pane/window is the answer.
"Side panel" / "side by side" / "beside me" / "next to me" / "in a pane" is the DEFAULT — NOT an extra window. Those phrases describe the in-current-window pane that
panealready produces (codex sits right next to Claude in the same window). Resolve$TARGETnormally (→pane); do not interpret them as a request for a separatecc-codexwindow vianew. Only the explicit separate-window phrasing above warrantsnew; genuinely-parallel phrasing warrantspane --topic <slug>in the current window.
Placement — codex stays with the agent. The codex pane always lives in Claude's current session and window: pane splits into the current window, and if a prior codex pane exists in another window it is relocated here (join-pane), never duplicated. A new window or a new tmux session is used only when the user explicitly asks for one.
Announce before spawning. When you first open (or relocate) codex, briefly tell the user where — e.g. "I'll open codex as a pane in your current window (research:4)." — so a split or move is never a surprise.
Detecting & orchestrating multiple codex panes
The multi-pane model: the default codex is the topic-main pane; parallel tasks get EXTRA topic-named panes in the SAME current window. Each codex pane carries @cc_codex_claude6 (identity) and @cc_codex_topic (main for the primary pane, a topic slug for extras; legacy panes without the option count as main). Pane titles: codex-<claude6> when the topic is main, else codex-<topic>-<claude6>.
Detect: panes
panes is the read-only detection command — run it to see every codex pane you own and where it is (e.g. at the start of a conversation, or before deciding to spawn):
"$CODEX" panes # this agent's codex panes
"$CODEX" panes --all # every agent's (diagnostics only)
Output: one TSV line per pane —
| Column | Meaning |
|---|---|
pane_id |
e.g. %53 — usable directly as a $TARGET |
topic |
main for the primary pane, else the topic slug |
state |
alive (codex running) / shell (codex exited; pane kept at an interactive shell, relaunchable) / dead |
session:window_index |
where the pane lives |
cwd |
the pane's recorded working directory (- if unknown) |
Exit 0 if at least one pane printed, exit 1 if none. Every field is guaranteed non-empty (unknown values print -), so tab-splitting the output is safe. panes never creates anything — not even the cc-codex session — so it is always safe to run.
Spawn: pane --topic <slug> (parallel task requested)
When the user requests a parallel task, spawn/reuse the EXTRA pane for that topic IN THE CURRENT WINDOW. Capture-and-check like the resolve snippet — do not pipe into head unchecked (exit 4 = codex died at launch would yield an empty id):
if _eout=$("$CODEX" pane --topic tests --cwd "$PWD"); then
EXTRA=$(printf '%s\n' "$_eout" | head -n1)
fi # nonzero exit: surface stderr; never drive an empty target
All the default pane semantics apply per-topic: reuse-if-alive, relaunch-in-kept-shell if codex exited, relocate into the current window if it drifted to another one (join-pane, never duplicated), respawn-if-dead, width floor, liveness check with one auto-retry (exit 4), sandbox-mismatch warning. Plain pane is exactly pane --topic main (the primary pane; behavior unchanged). Announce before spawning, e.g. "I'll open a second codex pane (topic: tests) in your current window."
Address: one target per pane, one driver per pane
Each pane is addressed by its topic (--topic <slug>; omit for the main pane). The verbs keep a PER-PANE baseline automatically — each prompt records its own pane's anchor, so nothing is shared across panes. One driver (this Claude) per pane; you may drive several panes concurrently:
# $CODEX = the literal helper path from "Default workflow"; re-state it in each Bash call.
$CODEX prompt -- "task A" # main pane
$CODEX prompt --topic tests -- "task B" # extra pane, own baseline
$CODEX wait && $CODEX read --delta # A settled → A's delta
$CODEX wait --topic tests && $CODEX read --delta --topic tests # B independently
Separate window: new <topic> (explicit request only)
new <topic> is ONLY for an explicitly requested SEPARATE WINDOW ("separate window", "new window") — it is NOT the parallel default; parallel work goes into pane --topic panes in the current window. (One exception: outside tmux, where pane is unavailable — exit 3 — a parallel task falls back to new <topic>; see references/tmux-mode.md.) Cleanup is unchanged: kill --mine removes ALL of this agent's codex panes regardless of topic (plus its windows); kill %id removes one specific pane.
Topic naming protocol (extra pane / extra window only)
Only needed when the user explicitly asked for a parallel task (
pane --topic) or a separate window (new). For the default single codex pane/window you do not derive a topic —panereuses the topic-mainpane in the current window, andbindnames the fallback windowcodex-<claude6>automatically.
Every pane --topic / new call needs a 2–15 char slug ([a-z0-9-]; note main passes the regex but is reserved for the primary pane — pane --topic main is just the default pane). Derive the slug from the user's request:
- Identify the primary content noun or verb (e.g.,
auth,refactor,tests,migration). - Lowercase it; strip non-
[a-z0-9-]characters. - Truncate to 15 chars.
- If shorter than 2 chars or no content word is identifiable, default to
task.
Examples:
- "refactor the queue in parallel" →
pane --topic refactor - "review the test suite, don't touch the current one" →
pane --topic tests - "spin up another codex" →
pane --topic task - "analyze auth.ts in a separate window" →
new auth
Extra-pane titles become codex-<topic>-<claude6> (the primary pane's title stays codex-<claude6>); extra-window names become codex-<topic>-<claude6>-<rand2> (e.g., codex-auth-0d61e6-x7). The fallback bound window stays codex-<claude6>. Full naming rules: references/tmux-mode.md.
Lifecycle one-liners (helper script)
The helper script ($CODEX, the literal path set in "Default workflow") handles lifecycle (this section) and interaction (the driving verbs, next section).
# DEFAULT entry point (inside tmux): get/create THE codex pane in the CURRENT
# window. Idempotent — reuse if alive, relaunch codex in the kept shell if it
# exited, respawn if dead. Prints a pane id (e.g.
# %53) on line 1. Exits 3 (with a hint to use `bind`) when NOT inside tmux;
# exits 4 when codex dies immediately at launch (after one auto-retry — codex's
# last output goes to stderr). Auto-switches a too-narrow horizontal split to a
# vertical (full-width) split so codex keeps ≥80 cols.
# Optional: --horizontal|--vertical (default horizontal), --size PCT (10–90,
# default 45; out-of-range → exit 2); --topic <slug> (default "main" = the
# primary pane; a slug resolves the EXTRA pane for that topic, same per-topic
# semantics).
TARGET=$("$CODEX" pane --cwd "$PWD" | head -n1)
# See the resolve-$TARGET snippet above for the full inside-tmux-vs-fallback guard
# (it checks pane's exit code, so exit 3/4 fall through to the bind fallback).
# DETECT (read-only): list this agent's codex panes server-wide. One TSV line
# per pane: pane_id<TAB>topic<TAB>state<TAB>session:window_index<TAB>cwd
# (state = alive|shell|dead; shell = codex exited, pane kept at an
# interactive shell). Exit 0 if ≥1 pane printed, else 1. Never creates
# anything. --all = every agent's panes (diagnostics only).
"$CODEX" panes
# PARALLEL task (user explicitly asked): spawn/reuse the EXTRA topic pane
# IN THE CURRENT WINDOW. Announce before spawning; capture-and-check the exit
# code (see "Detecting & orchestrating multiple codex panes").
if _eout=$("$CODEX" pane --topic <slug> --cwd "$PWD"); then
EXTRA=$(printf '%s\n' "$_eout" | head -n1)
fi
# FALLBACK entry point (NOT inside tmux): get/create THE single bound window
# (codex-<claude6>) in the cc-codex session. Idempotent. Line 1 = window name;
# line 2 = attach hint. Drive it as TARGET="cc-codex:$WIN".
# Exits 7 if this session already owns a live/kept-shell codex PANE — drive
# that pane instead (--force overrides). Nothing is created on a refusal.
WIN=$("$CODEX" bind --cwd "$PWD" | head -n1)
# Spawn an EXTRA window — ONLY when the user explicitly asked for a SEPARATE
# WINDOW (parallel tasks in the current window use `pane --topic` above).
# Needs a topic slug. Returns immediately — does not wait for codex to be ready.
WIN=$("$CODEX" new <topic> --cwd "$PWD" | head -n1)
# List this conversation's windows (bound + any extras).
"$CODEX" ls --mine
# Look up an extra window by topic (rarely needed; pane/bind handle the default).
"$CODEX" find <topic> --cwd "$PWD"
# Exit 0 + one line per match (tab-separated: window, state, cwd).
# Exit 1 + no output → no match.
# Print attach command for the user.
"$CODEX" attach "$WIN"
# Rename an extra window's topic; preserves claude6+rand2 suffix.
"$CODEX" rename "$WIN" "newtopic"
# Kill a specific codex pane/window (kill accepts a pane id like %53) or all of
# THIS Claude session's codex (ALL panes regardless of topic + windows). Both are
# claude6-scoped and pane-aware — they only ever touch this agent's own codex.
"$CODEX" kill "$TARGET" # pane id (%53) OR window
"$CODEX" kill --mine
# kill --orphaned exists too but is GLOBAL/cross-agent (reaps every agent's dead
# codex) — do NOT use it in normal flow; only on explicit "clean up everything".
# One-shot escape hatch (no tmux).
"$CODEX" exec "<prompt>"
The script keeps send and capture as recognized keywords ONLY to print a migration error pointing at the driving verbs below. Drive interaction via the verbs — raw tmux send-keys/capture-pane remains for calibration, debugging, and unexpected TUI states only.
Driving verbs (the interaction surface)
The whole loop — baseline, atomic send, two-phase settle detection, delta extraction — is script commands. Calibration (the gpt-5\.[0-9].*· idle regex, bottom-of-pane anchoring, deadlines) lives inside the verbs via the codex profile; you don't hand-roll it.
# $CODEX = the literal helper path from "Default workflow"; re-state it in each Bash call.
# Send a prompt and block until the turn settles (the default move).
# Atomic send: literal keys, short pause, Enter as its own event. Records the
# baseline that wait/read anchor to. Long or multi-line text goes via a tmp
# file automatically ("Read @file ..."); or pass a file you wrote with the
# Write tool explicitly:
$CODEX prompt --wait -- "<prompt>"
$CODEX prompt --wait --file "$PROMPT_FILE"
# Split form — send now, settle later (e.g. while driving another pane):
$CODEX prompt -- "<prompt>"
$CODEX wait --timeout 900 # xhigh can think for minutes; be generous
# wait exit codes — handle each distinctly:
# 0 idle (turn finished) 5 timeout (still running — wait again or read)
# 6 no target 8 stalled (send never started a turn — retry prompt)
# 9 codex exited (pane kept at shell — next `pane` relaunches it)
# Standalone `wait` = "is it idle right now?" (also the readiness check after `new`).
# Read ONLY what codex emitted since the last prompt:
$CODEX read --delta
$CODEX read --lines 1000 # more scrollback for a long response
# Cancel an in-flight turn (user said "stop / ask it X instead"):
$CODEX cancel && $CODEX wait # Escape, then settle before the next prompt
# Targeting: default = this session's main pane. --topic <slug> = that extra
# pane. --target "$TARGET" = explicit pane id / cc-codex:window (fallback mode).
Expecting a long or structured deliverable (review, report, plan)? Use the file handoff: put an output path in the prompt itself — "write the full report to /tmp/codex-out.md, reply DONE" — then wait and Read the file. Lossless; no scrollback/redraw damage (tmux-agent skill § Adaptive I/O).
First-ever codex run only: a "Hooks need review" gate appears before codex accepts work — dismiss with raw keys: tmux send-keys -t "$TARGET" "2" Enter ("Trust all and continue"). Other unexpected TUI prompts (approvals, auth): read the pane and see handle-interruption in references/tmux-mode.md.
See references/tmux-mode.md for codex-specific calibration and the raw recipe forms behind the verbs; the generic rationale (why two-phase, delta semantics, copy-mode) is the tmux-agent skill's references/interaction-recipes.md.
Choosing the right move
| Situation | Move |
|---|---|
| Any prompt, any size | prompt --wait (tmp-file handoff is automatic for long/multi-line) |
| Send now, collect later / drive panes in parallel | prompt, then wait (+ --topic per pane) |
| Need to know "is codex done" | wait — 0 idle / 5 timeout / 8 stalled / 9 exited |
| Reading the latest response | read --delta |
| Response > ~200 lines | read --lines 1000 |
| Structured deliverable expected (review/report/plan) | File handoff: output path in the prompt, wait, Read the file |
Response > tmux history-limit (~2000 lines) |
copy-mode-navigation (tmux-agent skill; rare — prefer file handoff up front) |
| User says "stop / cancel / never mind" mid-response | cancel, then wait |
| Codex shows a non-response prompt (hooks/approval/auth) | read, then handle-interruption (raw keys; references/tmux-mode.md) |
| Resuming after the session id rolled or windows were killed | reuse-existing-window (references/tmux-mode.md) |
Choosing the right window — mandatory pre-spawn workflow
By default there is exactly one codex target: a pane in your current window (inside tmux) or the bound codex-<claude6> window (fallback). Run the resolve-target snippet — pane when inside tmux, bind otherwise — and drive $TARGET. You do not need find, a topic slug, or a reuse-vs-spawn decision for normal work — both pane and bind are idempotent and always resolve to the same pane/window for this Claude session.
| Situation | Action |
|---|---|
| Any task (analysis, design, implementation, follow-up, new sub-task) | Run the resolve-target snippet (pane inside tmux, else bind), then drive "$TARGET". |
| Need to see which codex panes you already own (start of conversation, after interruptions) | codex-tmux.sh panes — read-only TSV listing (pane id, topic, state, location, cwd). |
| User explicitly wants a parallel task ("in parallel", "a second codex", "also start another", "keep this one and also…", "don't interrupt the current task") | Derive a topic slug, resolve the extra pane with pane --topic <slug> (capture output, check exit code — as in the resolve snippet), drive that extra pane in the CURRENT window (per-pane baseline + idle loop). |
| User explicitly wants a SEPARATE WINDOW ("separate window", "new window") | Derive a topic slug, WIN=$(codex-tmux.sh new <topic> --cwd "$PWD" | head -n1), drive that extra window. A new tmux session only ever on explicit request. |
Codex exited (pane/window now at the kept shell, state shell) |
Nothing special — pane/bind relaunches codex inside the SAME pane/window (no new split; the newly requested sandbox/model/effort apply since it is a fresh start). The user may also continue manually there (codex resume --last). |
The pane/window's root process died (state dead) |
Nothing special — pane/bind respawns it automatically. Salvage prior context only if the user wants continuity (see reuse-existing-window). |
| User asks to start over from scratch ("reset codex", "fresh codex") | codex-tmux.sh kill "$TARGET" (pane id or window) then resolve the target again. |
--full-auto requested but the pane/window is read-only (or vice-versa) |
The script warns on stderr and reuses the existing pane/window. Surface the warning; only kill + re-resolve if the user wants the other sandbox. |
Both pane and bind already filter by claude6 (the pane is also marked so it is normally reused, not duplicated — though a duplicate can occur if the session id rolls, recovered via kill %id / kill --mine, both claude6-scoped), so cwd/topic matching that find used to do is unnecessary for the default flow. Reach for pane --topic/find/new/--any-session only in the explicit parallel/extra-window or cross-session cases below.
Extra panes / extra windows
Only when the user explicitly asked. Parallel task → derive a topic slug (see "Topic naming protocol") and pane --topic <slug> (extra pane in the CURRENT window — idempotent per topic, so re-running it reuses/relocates/respawns the same pane); separate window → new <topic>. Before re-spawning the same extra window topic later, you may find <topic> --cwd "$PWD" to reuse it; for panes, panes shows what already exists. Generic reuse-vs-spawn theory lives in the tmux-agent skill's references/sync-and-lifecycle.md.
Cross-session references
If the user references a window from a prior Claude conversation ("go back to yesterday's auth window"), pane/bind/find won't return it (different claude6 token). Use find <topic> --any-session to widen the search, then confirm with the user before resuming. Full recipe in tmux-mode.md § reuse-existing-window.
End-of-conversation cleanup
Cleanup is simple under the pane default: normally there is just the one codex pane in your current window (or the one bound window in the fallback). At natural breakpoints — user says "we're done", "thanks that's it", "wrap up", or the codex task is clearly complete:
# What codex do I own? Panes (main + any topic extras) via panes; windows via ls.
"$CODEX" panes
"$CODEX" ls --mine
| Situation | Offer the user |
|---|---|
| Just the one codex pane / bound window, still useful | Leave it. It's reused next time you resolve the target, and resumable via find --any-session. |
| Main pane + extra topic panes / extra windows no longer needed | "Want me to kill --mine (clears this session's codex — ALL panes regardless of topic, plus windows), or just kill "$TARGET" for the one?" |
| Some of THIS session's panes/windows dead | "Want me to clear them — kill %id for a specific dead pane, or kill --mine for all of this session's codex?" (both claude6-scoped — they never touch another agent's codex) |
A pane/window in state shell (codex exited, kept shell) |
Usually leave it — the user may be using it manually, and the next resolve relaunches codex there. Note that kill --mine removes kept-shell panes too (they still carry the claude6 marker). |
| User explicitly says "clean up" / "kill all" | Run kill --mine (removes only THIS session's codex panes and windows) and report what was removed. Use the global kill --orphaned only if the user explicitly asks to clear every agent's dead codex. |
Never kill silently. Always tell the user which pane/windows you're about to remove and wait for confirmation, unless they explicitly said "kill all of them". Killing destroys scrollback irreversibly. Leaving the codex pane/window alive is the friendly default — the next resolve-target call reuses it instead of spawning a fresh one.
Cleanup commands reference
| Goal | Command |
|---|---|
Remove a specific codex pane (pane id like %53) or one window |
codex-tmux.sh kill "$TARGET" (or kill <%pane-id>) |
| Remove this Claude session's codex — ALL panes (every topic) AND bound/extra windows (alive or dead) | codex-tmux.sh kill --mine |
| GLOBAL / cross-agent — dead codex of EVERY agent (any session) | codex-tmux.sh kill --orphaned — escape hatch; use ONLY on explicit "clean up everything", never in normal flow |
Note: kill --mine is claude6-scoped (touches only THIS agent's codex) and pane-aware — it removes this session's codex PANES (all topics: main and extras alike) as well as its cc-codex windows, recognizing both the exact bound name codex-<claude6> and the extra-window pattern codex-<topic>-<claude6>-<rand2>. kill <%pane-id> (e.g. kill %53) removes one specific codex pane. kill --orphaned is the one non-scoped command — it reaps dead codex across ALL agents, so do not use it as part of normal cleanup.
Sandbox and approval policy
| User intent | Flags |
|---|---|
| Default (read-only analysis), inside tmux | pane --cwd "$PWD" (uses --read-only, approval_policy=on-request) |
| Default (read-only analysis), fallback | bind --cwd "$PWD" (uses --read-only, approval_policy=on-request) |
| Explicit edit request, inside tmux | pane --cwd "$PWD" --full-auto (uses workspace-write + on-request) |
| Explicit edit request, fallback | bind --cwd "$PWD" --full-auto (uses workspace-write + on-request; user approves writes via attach) |
| Edit in an explicit extra topic pane | pane --topic <slug> --cwd "$PWD" --full-auto (sandbox fixed per pane on first creation) |
| Edit in an explicit extra window | new <topic> --cwd "$PWD" --full-auto |
| One-shot edit (no tmux) | exec -s workspace-write -c sandbox_workspace_write.network_access=true "<prompt>" |
The skill still defaults to read-only sandbox; switch to --full-auto only when the user explicitly says "edit", "modify", "save", "fix", "refactor", etc. The sandbox is fixed while codex runs. If you pass --full-auto but the pane/window is running read-only codex (or vice-versa), the script warns on stderr and reuses it; surface the warning and kill + re-resolve only if the user wants the other sandbox. Exception: when codex has exited and the pane sits at the kept shell (state shell), the next pane/bind call relaunches codex fresh — the newly requested sandbox applies with no warning needed.
Model and reasoning effort
Defaults: model gpt-5.6-sol, reasoning effort xhigh. The script pins BOTH at every codex it starts — pane/bind/new spawns and exec one-shots all pass -m gpt-5.6-sol -c model_reasoning_effort=xhigh (this changed in v3.7.0: spawns used to inherit the model from your codex config; they now pin it). Override via env: CC_CODEX_MODEL and CC_CODEX_EFFORT (e.g. CC_CODEX_MODEL=gpt-5.5 on a codex CLI older than 0.144.0, which cannot run the 5.6 series). The one exception is codex review, which bypasses the helper (see "Delegating a code review").
The GPT-5.6 series (requires codex CLI ≥ 0.144.0)
| Model | Role | Effort ladder | When |
|---|---|---|---|
gpt-5.6-sol (default) |
Frontier agentic coding | low · medium · high · xhigh · max · ultra | Hard reasoning, architecture, deep debugging, tricky refactors. |
gpt-5.6-terra |
Balanced everyday | low · medium · high · xhigh · max · ultra | Standard coding/review at lower cost than sol. |
gpt-5.6-luna |
Fast & affordable | low · medium · high · xhigh · max | Quick edits, simple lookups, high-volume/cheap work (no ultra). |
Reasoning effort ladder: low < medium < high < xhigh < max < ultra. xhigh is the default strong setting; max = "maximum reasoning depth for the hardest problems", ultra = "maximum reasoning with automatic task delegation" (sol/terra only). max/ultra are slower and costlier — escalate to them deliberately, don't default there.
Pick the model + effort by task
Choose a 5.6-series combination that fits the task instead of always using the default:
| Task | Suggested combination |
|---|---|
| Default / anything unclear | gpt-5.6-sol + xhigh |
| The hardest problems (gnarly architecture, deep multi-file debugging) | gpt-5.6-sol + max, or ultra for the very hardest |
| Everyday coding, moderate reviews (cost-aware) | gpt-5.6-terra + high/xhigh |
| Quick edits, simple questions, high volume | gpt-5.6-luna + medium/high |
| User explicitly asks for speed ("fast", "quick") | drop the effort (high/medium) and/or use gpt-5.6-luna; the -fast service tier (gpt-5.6-sol-fast) needs API-key auth |
To use a non-default combination for a task, set the env vars when resolving the target, e.g.:
CC_CODEX_EFFORT=max "$CODEX" pane --cwd "$PWD" # sol + max
CC_CODEX_MODEL=gpt-5.6-luna CC_CODEX_EFFORT=medium \
"$CODEX" exec "quick one-off question"
When selection applies. Model and effort are fixed when a codex process STARTS: (a) the first pane/bind/new call that actually spawns codex, (b) every exec one-shot (the cheapest way to run a different combo per task), (c) a new --topic pane, and (d) a relaunch into the kept shell after codex exited (state shell) — a relaunch is a fresh start, so env overrides DO apply there. A pane/window with codex still RUNNING keeps whatever it was started with — an env override on a live reuse does nothing, and the script warns on stderr (… do NOT apply to a reused pane); surface that warning. To switch the main pane's model/effort, kill "$TARGET" and re-resolve with the new env — that destroys codex's conversation context, so confirm with the user first (see "Never kill silently"). For a one-off harder/cheaper task mid-conversation, prefer an exec one-shot or a new --topic pane over killing the main pane.
Auth note: ChatGPT-account auth now runs the base 5.6 slugs (gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna) and gpt-5.5. The -fast service-tier variants (e.g. gpt-5.6-sol-fast) require API-key auth — under a ChatGPT account they return HTTP 400 "not supported".
Fallback chain: model gpt-5.6-sol → gpt-5.6-terra/gpt-5.6-luna → gpt-5.5 (older CLI); effort xhigh → high → medium.
Delegating a code review (codex review)
codex review is a dedicated top-level subcommand that runs non-interactively — safe in Claude Code's non-TTY bash (the "always use codex exec" rule applies to plain codex, not to codex review). Use it when the user asks codex to review changes rather than have a conversation — always a one-shot, no tmux session:
codex review --uncommitted # staged + unstaged + untracked
codex review --base main # this branch vs a base branch
codex review --commit <SHA> --title "summary" # a specific commit
codex review --uncommitted "Focus on concurrency safety and error handling."
Model note: review bypasses the helper script — CC_CODEX_MODEL/CC_CODEX_EFFORT do NOT apply; it uses the codex config's review_model. Pin per call with -c review_model="gpt-5.6-sol".
Route here ONLY when the user explicitly asks for a codex review report of a diff / branch / commit / PR and does not ask to watch or iterate. "Reviewers I can watch", "review it in the pane", multiple/parallel reviewers, or any discuss/iterate phrasing → the visible co-worker pane(s) instead (pane, or pane --topic <slug> per reviewer). If unsure whether the user wants the one-shot report or a visible reviewer, ask. Flag details: references/cli-features.md.
Capturing exec output cleanly (structured / scripted use)
For exec one-shots, prefer these over scraping stdout when you need the result programmatically: -o FILE / --output-last-message FILE (only codex's final message, no TUI chrome), --output-schema FILE (JSON-Schema-constrained output), --json (JSONL event stream). Related: --ephemeral runs without persisting a session file (throwaway one-shot, not resumable). Flag details: references/cli-features.md.
OUT=$(mktemp -t cc-codex-out); "$CODEX" exec -o "$OUT" "Summarize @report.md in 3 bullets."
File context passing
Pass file paths to codex; do not embed file contents in the prompt.
@path/to/file— explicit file reference inside the prompt (works in both modes).--cwd /pathonpane/bind/new— set working directory for the codex pane/window.--add-dir /pathonexec— additional readable/writable directory (one-shot mode only).
Details and resolution rules: references/file-context.md.
Surfacing failures to the user
The helper script fails loudly (non-zero exit + stderr) for lifecycle errors. When it fails, surface the output verbatim. Common signals:
bindexit 7 — a codex pane already exists. The engine refuses to open acc-codexwindow while this session owns a live (or kept-shell) pane, because that pane is drivable from anywhere — the verbs address panes server-wide, inside tmux or not. Drive the pane it names; nothing was created. Onlykillit first, or pass--force, if the user actually wants a separate window.No such file or directory/ exit 127 from the helper — theCODEX=path is wrong. Bare$CLAUDE_PLUGIN_ROOTis not an exported variable; only the braces placeholder is substituted, and only in skill content loaded via the Skill tool. Re-invoketmux-agent:codexand copy the literal path. This is not a reason to callbind— a path error must never route codex into acc-codexwindow.- Codex exited immediately at launch —
pane/bindexit 4 (after one auto-retry) and print codex's last output on stderr. Surface that output; re-run (auto-retries once) or fall back tobind. Adeadstate inls --mine/findis the steady-state version of the same signal (codex's process is gone). Offer to respawn (resolve the target again) or salvage context first (seereuse-existing-window). - Window/pane-not-found errors from
ls,kill,attach,rename— surface the message. - v3.1.0 migration errors from
send/capture— exit 64. Use the driving verbs instead.
Interaction failures mostly surface as wait exit codes: 5 = still running (wait longer, or read to peek — an approval/hooks prompt also looks like this, so check the pane), 8 = stalled (the send never started a turn — re-prompt), 9 = codex exited (kept shell — pane relaunches). Unexpected TUI prompts still need a read + the handle-interruption recipe, or escalate to the user.
Reference index
Generic agentic-tmux background (tmux-agent skill, this plugin):
- The
tmux-agentskill is the canonical home for generic agentic-tmux concepts and the full recipe catalog — identity & naming patterns, kinds & profiles, send/capture/idle-detect (incl. why two-phase), sync/locking, scrollback semantics, and lifecycle/cleanup. This skill links to it for background; see the tmux-agent skill's ownreferences/interaction-recipes.md,references/model-and-identity.md, andreferences/sync-and-lifecycle.md(inskills/tmux-agent/references/, not this skill's references/). Read it when you need the why behind a recipe. Daily tmux fundamentals (session/window/pane model, layouts, copy-mode) live in thetmuxskill of the tmux-core plugin.
Canonical (codex-specific tmux workflow):
references/tmux-mode.md— canonical for codex — codex-specific calibration (model-agnosticgpt-5\.[0-9].*·IDLE_REGEX), thepane(default) /panes(detection) /bind(fallback) workflow, multi-pane topics, the raw recipe forms behind theprompt/wait/read/cancelverbs (calibration + debugging), hooks-review handling, sandbox flags. Generic theory is delegated to thetmux-agentskill.references/cli-features.md— CLI flag table, interactive-vs-exec differences,codex reviewandcodex apply.references/codex-config.md— every-ckey with type and default.references/codex-help.md— raw--helpoutput.references/file-context.md— passing files, directories, and the@syntax.
Legacy (exec-mode escape hatch only):
references/session-workflows.md—codex exec resumecontinuation rules and session-ID tracking.references/examples.md—codex execexamples by use case.references/command-patterns.md—codex execinvocation templates.references/advanced-patterns.md—codex execflag combinations, profiles, multi-phase workflows.references/troubleshooting.md—codex execerror catalog and fixes (tmux-mode troubleshooting lives intmux-mode.md).