codex-mcp
codex-mcp
Plan with Claude · Execute with OpenAI Codex · Review with Claude
A Claude Code plugin and MCP server that runs a disciplined plan → execute → review loop:
Claude interviews you and designs the plan, Codex writes the code, then Claude reviews each task
and the final pass alongside a required Codex codex_review; findings are compared, fixes go back,
and non-blocking improvements wait for your decision — all from a single command.
· macOS · Windows · Linux · Node ≥ 20 · MIT
Quick start
1. Prerequisites — Node ≥ 20 and the Codex CLI, authenticated:
npm i -g @openai/codex
codex login # ChatGPT Plus/Pro/Team — or set OPENAI_API_KEY2. Install the plugin (bundles the /codex-flow command, ~60 skills, and the codex MCP server):
/plugin marketplace add anhnguyen0905/codex-mcp
/plugin install codex-flow@codex-mcpOnce listed in the Claude community directory, this also works:
claude plugin marketplace add anthropics/claude-plugins-community then
claude plugin install codex-flow@claude-community.
3. Run it in any project:
/codex-flow implement a dark-mode toggle on the settings page# from npm (recommended — ships a prebuilt dist, nothing to compile)
claude mcp add --scope user codex -- npx -y @anhnguyen0905/codex-mcp
# or straight from this repo, which builds from source on first run
claude mcp add --scope user codex -- npx -y github:anhnguyen0905/codex-mcpclaude mcp list should then show codex … ✔ Connected. Copy
commands/codex-flow.md to ~/.claude/commands/ for the workflow
command, or just use the plugin install above which bundles both.
Optional: flint-chart-mcp
codex-flow routes chart and graph tasks to flint-chart (Microsoft Research) via the
codex-flow:exec-visualization skill, rendering polished PNG/SVG charts instead of using ad-hoc
Python plotting.
Register the server with the Codex CLI in ~/.codex/config.toml:
[mcp_servers.flint-chart]
command = "npx"
args = ["-y", "flint-chart-mcp"]Register it with Claude:
claude mcp add flint-chart -- npx -y flint-chart-mcpThis setup is optional; when the server is not present, the exec-visualization skill degrades to
a fallback.
The plugin is distributed as a git clone and dist/ is gitignored, so up to v0.14.0 a freshly
installed plugin had no build and its node dist/index.js launcher exited immediately.
Since v0.15.1 the bundled .mcp.json runs the published npm tarball
(npx -y @anhnguyen0905/codex-mcp@<version>), which ships a prebuilt dist/ — nothing is compiled
at install time. Updating the plugin is the fix:
/plugin update codex-flow@codex-mcpIf you are pinned to an older version, patch that install once instead:
cd ~/.claude/plugins/cache/codex-mcp/codex-flow/<version>
npm install --no-audit --no-fund && npm run buildThen restart Claude Code and confirm with claude mcp list (or call codex_health).
How it works
Claude Code ──(MCP stdio)──▶ codex-mcp ──spawns──▶ codex exec --json/codex-flow runs six phases, keeping Claude as the planner/reviewer and Codex as the implementer:
Phase | Owner | What happens |
0 · Preflight | Claude | Verify Codex login; baseline git + tests; resume an interrupted run. |
1 · Interview | Claude | Clarify requirements until every acceptance criterion is verifiable. |
2 · Plan | Claude | Explore the codebase, select relevant skills, write |
3 · Backlog | Claude | Decompose into dependency-ordered tasks in |
4 · Execute | Codex | Implement one task at a time — or several in parallel (see below). |
5 · Review | Claude + Codex | Dual-review each task and the final pass via Claude + required |
The bundled session-report skill writes a per-session bundle to .codex-flow/reports/<YYYYMMDD-HHMMSS>/ with planning, allocation, task, cost, and summary reports plus explicit claude / codex / both PIC attribution.
The server spawns codex exec non-interactively, parses its JSONL event stream, and returns a
structured result (sessionId, agentMessage, fileChanges, commands, token usage, diff).
Highlights
Index-based skill selection
Instead of blind-loading whole skill collections, /codex-flow selects only the skills a task
needs from a local index: it classifies the request's role facets (engineering, data,
marketing, growth, research, design…) and loads every relevant skill that fits a context budget
(~3% of the window), embedding distilled rule blocks into the Codex prompts. Skills on disk cost
zero context until selected; third-party skills are vetted once before first use.
The index covers ~/.claude/skills, ~/claude-skill-library, and the skills/ dir of every
installed plugin (newest version per plugin) — so selection knows about skills the machine
already has instead of reporting a gap. And a domain facet never ends with zero skills: when
nothing indexed fits, Step 7 re-indexes, vets, searches (gh/catalog/web), and — failing all of
that — authors the missing SKILL.md before execution, so the library grows toward the work.
node scripts/sync-awesome-skills.mjs --clone # build a local library from awesome-claude-skills
node scripts/build-skills-index.mjs # → ~/.claude/skill-library/INDEX.mdBesides the phase skills, the plugin ships 17 domain skills authored through Step 7 — paid media, unit economics, media planning, warehouse modeling, event taxonomy, attribution, causal inference, survey design, ASO, localisation, OKRs, creative briefs, influencer strategy, SOPs and data-quality checks, and agent context persistence — so they are indexed and selectable out of the box. Their numeric thresholds are labelled derived, unverified: replace them with your own account history before treating any of them as a target.
Verified by a 32-scenario scope eval (npm run skills:eval) — latest 32/32 — plus a
100-request non-engineering scope run (data analysis, marketing planning, performance marketing,
market research, content, product): 99/100 covered by an existing skill, at precision@1 84/99,
with the remaining case queued for Step 7 acquisition/authoring. Full procedure:
skills/skill-selection/SKILL.md.
Context persistence on large projects
scripts/context-slice.mjs generates budgeted derived slices from .codex-flow/PLAN.md and
.codex-flow/TASKS.md: per-task .codex-flow/CONTEXT-T<n>.md files (≤ 4000 estimated tokens
using the chars/4 heuristic) and .codex-flow/RESUME.md on resume (≤ 8000 estimated tokens
using the chars/4 heuristic). Decision-log blocks carry a git-SHA Anchor:, and slices stamp each
block [fresh] or [verify]; anything unverifiable — including a missing or invalid anchor or a
git failure — degrades to [verify].
scripts/project-context.mjs writes .codex-flow/PROJECT.md, the durable project brief Codex
reads on every task: --generate derives it from the repo (what it is, users, layout, constraints,
quality mechanisms, known limitations, direction) and --refresh regenerates the generated parts
while preserving any <!-- owner-notes --> blocks the team added. /codex-flow Phase 0 generates it
on a fresh run when it is absent and has the user confirm or edit it in the interview; Phase 2 reads
it before exploring; Phase 5 proposes a --refresh (with the diff shown for confirmation) when a
Decision-log block records a contract deviation or an architecture change. It is a tracked project
file, not run state — committed with the run, never archived with it — and slices carry it as a
## Project context item capped at 600 tokens.
Mandatory task text and task statuses are never dropped. Lower-priority content is dropped whole
when necessary, with a restorable
(+N lower-priority items omitted — read .codex-flow/PLAN.md …) pointer. Full
.codex-flow/PLAN.md remains the on-disk source of truth. The slice helper is required: when it is
missing or exits non-zero the flow stops and asks for a plugin reinstall instead of degrading.
Run-state & requirements fidelity
.codex-flow/REQUIREMENTS.mdrecords confirmed acceptance criteria verbatim with atomicR<n>.<m>IDs. Mid-run changes append confirmedADDED/MODIFIED/REMOVEDDeltas instead of rewriting history, and reset affected downstream approvals..codex-flow/STATE.mdis the resume authority instead of file existence. Its 10-key run state tracks the phase, three approvals, immutablerunBaselineRef/ known-red / dirty-baseline values, checkpoint choice, execution mode, and a separateresumeHead.scripts/requirements-coverage.mjsrejects uncited or unknown criterion IDs at the Phase 3 gate; final review then walks every ID and records met/not-met with evidence.TASKS.md records session lineage and an append-only status-transition log. Resume reconciles orphaned in-progress work, while wave scheduling seeds dependencies from done tasks, waits on in-progress tasks, and blocks dependents of failed or unknown states.
In parallel mode, one coordinator writes
.codex-flow/*; workers return structured handoffs with touched files, checks, findings, decision-log proposals, and session IDs.Context slices always carry a stamped contracts index, compact known-red failures, and rank decision blocks by explicit
Applies to:scope before recency; the execution prompt carries the run-position recitation header.
Parallel execution for large backlogs
codex-mcp serializes runs per workspace but parallelizes across workspaces, so independent tasks can run concurrently — each in its own git worktree driven by a Claude subagent, then merged and integration-reviewed per wave.
npm run waves # compute execution waves from .codex-flow/TASKS.mdWaves batch tasks whose dependencies are met and whose files are disjoint, capped at 10
concurrent subagents (--max <n> to lower). Parallel is the default when task-waves reports
width > 1: waves of ≤3 run automatically, while wider waves ask first; parallel execution costs
N× simultaneous quota. Playbook:
skills/parallel-execution/SKILL.md.
Tools
Tool | Purpose |
| Start a new Codex session executing a task/plan |
| Resume a session with follow-up (e.g. review feedback) |
| Read-only review of uncommitted workspace changes |
| Run up to 50 tasks in parallel across distinct workspaces (worktrees) |
| List prior Codex sessions (from |
| Aggregate token/duration/failure metrics from the local run log |
| Check Codex CLI version and login status |
codex_execute / codex_continue / codex_review accept writeNotes: true to persist a markdown
summary of the run to <cwd>/.codex-flow/notes/<sessionId>.md.
When Codex is not logged in or unreachable, /codex-flow no longer stops dead: it offers an
explicit Executor fallback (fix Codex and re-check, or let Claude execute the backlog under the
same plan/review contract, with an independent subagent review replacing codex_review). The choice
is recorded in .codex-flow/STATE.md as executor: and is never made silently or mid-task.
Every codex_execute / codex_continue / codex_review payload carries accepted: boolean, a
fail-closed delivery verdict: status === "success" AND the acceptance evidence holds — the
verifyCommand passed (when given), or for codex_review the findings block parsed. It never
changes status/isError; read it before trusting agentMessage. codex_review is never
auto-resumed: a timed-out or partial review is reported after one attempt.
codex_review asks Codex to end its message with one fenced json block and returns it parsed
fail-closed as reviewFindings: { parsed, findings[], improvements[], dropped, droppedReasons, parseError? } (severity is one of CRITICAL/HIGH/MEDIUM/LOW; malformed entries are counted in
dropped, never coerced). droppedReasons: string[] carries one entry per dropped item, naming the
field that failed validation (for example findings[0].line, or the bare locator findings[0] when
the whole entry is invalid), so dropped is always droppedReasons.length. Any dropped > 0 makes
accepted false for codex_review — a review that lost an entry is never treated as delivered. The
prose agentMessage is still returned for the parsed: false case.
codex_execute / codex_continue accept verifyCommand (plus optional verifyTimeoutMs, default
10 min, cap 30): after the Codex run settles, the server runs that acceptance command in cwd
(still inside the workspace lock) and returns verification: { command, exitCode, timedOut, durationMs, outputTail, passed, skipped? }. This is deterministic evidence that the acceptance
check ran — independent of Codex's own claim. It is skipped (skipped: "run-failed") when the run
itself failed or aborted, and it never changes the run's status/isError. Termination is bounded
(SIGTERM → tree SIGKILL → forced settle) so a hung check can never hold the workspace lock. The
command runs with the server's environment, and its output tail passes through the same redaction
pass as every other returned text — treat it with the same trust as Codex's own output.
codex_execute / codex_continue / codex_review and each codex_batch task accept
reasoningEffort: minimal | low | medium | high | xhigh, passed to Codex as
-c model_reasoning_effort="<value>".
Secret redaction. Every returned or persisted text — agentMessage, stderr, errors,
verification.outputTail, live-progress notifications, the raw JSONL live log, and writeNotes
run notes — is redacted before it leaves the server: each known secret shape (OpenAI/GitHub/AWS/
Slack/Google keys, bearer tokens, JWTs, PEM private keys, SECRET/TOKEN/KEY-style env
assignments) is replaced by [REDACTED:<kind>]. codex_execute / codex_continue / codex_review
report redactions: <n> (and each codex_batch task result its own redactions, with
redactionsTotal on the batch payload) whenever the count is above zero; the fields are omitted at
zero. Redaction is idempotent and never changes status, isError, accepted, or a
verification.passed verdict.
Auth mode & the model guard. codex_health always returns
authMode: "chatgpt" | "apikey" | "unknown", derived from the Codex CLI login output. Under
ChatGPT auth a model override is refused before anything is spawned — codex_execute /
codex_continue / codex_review return an error and a codex_batch task fails with
model override is not allowed under ChatGPT auth; steer with reasoningEffort — because the
ChatGPT-auth backend rejects arbitrary model ids. So pass model only when authMode is
apikey; otherwise omit it and steer with reasoningEffort. /codex-flow Phase 4 follows the same
rule, and a flowDocs guard checks that wording.
Review scope. codex_review accepts scope: { files: string[]; contract?: string } (files
non-empty, up to 200 entries; contract up to 4000 chars). The server appends the contract and the
file list to the reviewer prompt and stamps every parsed finding with inScope: boolean, plus
reviewFindings.outOfScopeCount for the findings outside the declared files. Out-of-scope findings
are non-blocking by default — /codex-flow routes them to the improvements ledger and blocks only
when the reviewer verifies they affect the task's acceptance.
Metrics history & completeness. codex_metrics accepts includeHistory: true to aggregate the
archived history/*.jsonl back-files alongside the live and rotated log (default false, with
historyFiles / historyExcluded reported when archives exist). Every aggregate carries
completeness: { complete, unpricedRuns, missingUsage, readErrors, historyExcluded } so an
incomplete roll-up is visible instead of silent. Note that the shipped COST_TABLE is empty and
CODEX_MCP_PRICING does not fill it, so any run that reported usage counts as unpriced:
completeness.complete is never true for usage-bearing entries in this release.
Sandbox modes: read-only, workspace-write (default), danger-full-access. Default execution
timeout is 60 min (timeoutMs caps at 2 h). Runs into the same cwd are serialized; different
workspaces run in parallel.
By default, the server automatically resumes the same session after a transient turn failure
(at most 2 resumes), timeout (at most 1), or partial result caused by a missing completion marker
or parse errors (at most 1, reported as no-completion-marker), with 2 s then 8 s backoff (8 s
for any later resume). Set CODEX_MCP_AUTO_RESUME=0 to opt out.
Every run tool returns sessionId, agentMessage, fileChanges, commands, token usage,
errors, plus:
diff—git status --porcelain+git diff HEADafter the run (64 KB cap,truncatedflag;nulloutside a git repo) so the caller can review without re-reading files.aborted—truewhen cancelled from the client (Esc in Claude Code); the server forwards cancellation to Codex (SIGTERM → SIGKILL after 5 s).attempts/resumeReasons— total attempts and the ordered reasons for automatic resumes; eachcodex_batchtask result carries the same fields.liveLog— path to the raw JSONL event log when the live terminal view is enabled.
Clients that send an MCP progressToken (Claude Code does) get notifications/progress for every
meaningful Codex event. Set terminal: true (or CODEX_MCP_TERMINAL=1) to also open a live-tailing
window — Terminal.app on macOS, PowerShell on Windows, the first available emulator on Linux. On
macOS, the window closes itself about 4 seconds after a successful run; it stays open after a failed
or interrupted run. The delay defaults to 4000 ms; 0 closes immediately, and values above 60000
are clamped. Windows and Linux windows already close with their process. If no window can open, the
run still succeeds; follow the liveLog or the in-session progress instead.
Configuration
Variable | Effect |
| Auth for Codex CLI (alternative to |
| Override the Codex binary path/name (e.g. |
| Open the live-progress window by default. |
| Never auto-close the live-progress window (the value must be exactly |
| Set the close delay in ms; negative, non-integer, or unparseable input uses |
| Disable bounded server-side session auto-resume. |
| Override the skill index path. |
| Raise Claude Code's MCP tool timeout (ms) for long runs. |
Security & privacy
No credentials handled. The server never reads, stores, or transmits your credentials — auth is handled entirely by the Codex CLI (
~/.codex/). Runnpm run doctorto verify your setup.No network calls of its own. The MCP server only spawns the local
codexCLI (andgitfor diffs). All model traffic is Codex's, under your OpenAI account and its data policies.Local-only telemetry. Run metrics (tokens, durations, exit codes, a 200-char error head) are appended to
~/.codex-mcp/metrics.jsonlon your machine and never uploaded. Live-progress logs and run notes stay under the project's gitignored.codex-flow/.Sandboxed writes. Codex runs in
workspace-writeby default;codex_reviewis alwaysread-only;danger-full-accessis never used unless a task explicitly needs it and the user is told first. Per-cwd locks serialize runs into the same workspace.Caller-defined commands.
verifyCommandruns the acceptance command you pass, in your workspace, with the server's environment; its output tail is redacted like every other returned text, but treat it with the same trust as any other shell output. Third-party skills are loaded only after a content-pinned vet (skill-selection).Report vulnerabilities per SECURITY.md.
Development
npm test # unit tests (vitest)
npm run coverage # enforces 80% thresholds
npm run build # tsc → dist/
npm run test:e2e # real end-to-end smoke test (spawns Codex, uses quota)Server (src/): index.ts (stdio entry) · server.ts (MCP tools, cwd lock, cancellation) ·
argsBuilder.ts (argv) · codexRunner.ts (spawn + timeout/kill) · eventParser.ts (JSONL →
result) · workspaceDiff.ts (git diff) · terminal.ts / liveView.ts / progressFormatter.ts /
progressNotifier.ts (live progress).
Skill & workflow scripts (scripts/): sync-awesome-skills.mjs · build-skills-index.mjs ·
skill-match.mjs · skill-eval.mjs · task-waves.mjs · session-cost.mjs · tail-progress.mjs.