codex-in-claude
Call OpenAI Codex from Claude Code — an independent second opinion, structured code
review, and delegated coding tasks (cross-model review) — through a FastMCP plugin that drives
the codex CLI safely.
Contents: Why · Quick start · Example · Requirements · Tools · Skills · Result envelopes · Safety · Configuration · Troubleshooting · Local development
Why
A second model is a cheap, high-value check. codex-in-claude lets a Claude Code session hand
Codex a question, a diff to review, or a task to implement — and get back a structured,
safe-by-default result you stay in control of.
| Tier | Codex sandbox | Where edits go | Use for |
|---|---|---|---|
consult |
read-only |
nothing — text/findings only | questions, second opinions |
review |
read-only |
nothing — structured findings | reviewing your git changes |
propose (the delegate tools) |
workspace-write (temp git worktree + OS temp roots) |
worktree diff → returns a reviewable diff, never auto-applied | delegating a coding task |
Planned later milestone: an explicit opt-in apply tier for live-tree edits. It is not exposed by
the current tool set.
Quick start
First, in a terminal, make sure the codex CLI is installed and log in (a no-op if you already are):
codex login
Then, inside a Claude Code session, add the marketplace and install the plugin:
/plugin marketplace add briandconnelly/codex-in-claude
/plugin install codex-in-claude
Then run /codex:status in Claude Code. It is free (no model call) and checks that the codex
CLI is found, authenticated, and within the tested compatibility range.
For a first useful run:
/codex:consult is this approach sound?for a read-only second opinion./codex:reviewto review your current git changes./codex:delegate add focused tests for this behaviorto get a proposed diff in an isolated worktree.
The MCP server is launched on demand via uvx from a pinned PyPI release, so updates are deliberate.
Example
Review your uncommitted changes from a Claude Code session:
/codex:review
Codex inspects the diff read-only and returns a structured result envelope (abridged):
{
"ok": true,
"tool": "codex_review_changes",
"verdict": "concerns",
"confidence": "high",
"review_status": "completed",
"coverage": { "status": "complete", "untracked_files_detected": 0, "untracked_files_omitted": 0, "omission_reasons": [], "redaction": null },
"summary": "The retry path is correct, but the backoff delay leaks between calls and the new branch has no test coverage.",
"findings": [
{
"severity": "high",
"title": "Backoff delay is never reset after a success",
"file": "src/app/retry.py",
"line": 42,
"evidence": "self._delay keeps its last value once a call succeeds",
"risk": "A later transient failure starts from an inflated delay, adding latency.",
"recommendation": "Reset self._delay to the base delay in the success branch."
}
],
"next_steps": ["Add a regression test asserting the delay resets after a success"],
"meta": { "scope": "working_tree", "sandbox": "read-only", "elapsed_ms": 8137 }
}
verdict is one of pass / concerns / fail / unknown; confidence is low / medium /
high; every finding carries a severity (critical … nit) plus evidence, risk, and
recommendation. verdict is the safe overall conclusion: review_status tells you whether the
model actually ran (a tree with nothing reviewable returns not_run/unknown, never a false
pass), and coverage discloses anything the model was not shown — omitted untracked files
(governed by the untracked policy), a truncated diff, or a redacted file — downgrading a pass
over partial coverage to unknown. The envelope above is abridged — meta (always present, with cwd, tier,
sandbox, isolation, and timing), request_id, raw_response, and other fields are trimmed for
brevity; see docs/REFERENCE.md for the complete shape.
Requirements
- macOS or Linux (POSIX). Windows is not supported natively — the async-job safety
layer (file locks, process groups, signal-driven cancellation) is POSIX-only. Run it
under WSL2 on Windows. See
COMPATIBILITY.mdfor the platform contract. - The
codexCLI onPATH, authenticated (codex login— ChatGPT or API key). Tested againstcodex-cli 0.152; the supported range lives incli_contract.py,/codex:statusreports whether your version is in range, andCOMPATIBILITY.mdexplains the policy. uvonPATH(Claude Code launches the MCP server withuvx).- Python 3.11+ available to
uvx. git(for review and delegate).
Tools
Active (call the model and may spend tokens):
codex_consult(question, …)— read-only second opinion / answer.codex_review_changes(scope, base, commit, paths, …)— reviewworking_tree/branch/commit; returns structured findings.- Both consult and review (sync and
_async) also takedeveloper_instructions— optional caller stance/focus text placed in Codex's developer turn behind this server's always-leading framing (max 4096 bytes; stripped, blank = omitted; refused pre-spend if it carries the server's framing markers). It grants no tools and Codex is instructed — not compelled — to keep verdicts its own; compliance with the rest of the text is best-effort for the same reason, and may be silent, someta's fingerprint attests the request the server accepted and staged, not what the model did with it. The text rides the codex command line and the background-job record on disk, so never put secrets in it, and resultmetareports only its{sha256, bytes}. Deliberately not oncodex_delegate: delegate edits files, so a caller stance there would widen what an untrusted workspace can steer. Full contract: thecodex://paramsresource. codex_delegate(task, …)— implement a task in an isolated worktree; returns a reviewablediffthat is not applied.codex_consult_async(question, …),codex_review_changes_async(scope, base, commit, paths, …),codex_delegate_async(task, …)— detached variants of the three active tools, taking the same arguments as their synchronous forms: each returns ajob_idimmediately. Starting a job commits to spend (it runs to completion or its deadline); poll withcodex_job_status/codex_job_result.
Free (local only):
codex_status— readiness, version, auth, resolved defaults, and arate_limitblock (remaining Codex quota for the shorter/rolling and longer windows, read live from the Codex app-server with no model spend;statusisavailable/limited/exhausted/blocked/unknown/unavailable). Advisory — informs whether to spend;unknown/unavailablemean no usable reading, not a problem, whileblockedreports a backend spend control that waiting does not clear.codex_transfer(transcript_path, …)— hand off the current Claude Code session to a resumable Codex thread; returnsresume_command(codex resume <thread_id>) to continue that exact conversation in Codex. No model call or token spend (a local file conversion via the experimentalcodex app-server), but it does create a thread in$CODEX_HOME. Not idempotent for a live session — Codex dedups only a byte-identical transcript, so re-running mid-session makes a new thread. Experimental.codex_dry_run(scope, …)— preview a review's scope/diff size/redactions before spending.codex_delegate_dry_run(task, …)— preview a delegate's seeded baseline (HEAD commit, plus tracked, uncommitted, and untracked counts and size) and prompt size before spending; no worktree is created.codex_capabilities— tool inventory + result fingerprint.codex_models— advisory catalog of validmodelslugs, read from Codex's on-disk cache with a bundled static fallback; also browsable as thecodex://modelsresource. Discovery only —modelstays pass-through, so an unlisted slug still works andcodex execvalidates it.codex_job_status(job_id, …)/codex_job_result/codex_job_consume_result/codex_job_cancel/codex_job_list— background-job lifecycle. State is disk-backed and survives server restarts. Honorpoll_after_msrather than polling in a tight loop; deadlines, eviction, and result retention are covered indocs/REFERENCE.md.
Both dry runs report metadata about the input this plugin would assemble. Neither invokes Codex, so neither enumerates nor bounds the files the model itself reads and sends during the paid run — a clean preview is a check on scope, not evidence that nothing sensitive will be sent (see Safety).
Slash commands wrap these: /codex:status, /codex:transfer, /codex:consult, /codex:review,
/codex:delegate, /codex:delegate-async, /codex:dry-run.
Active tools send the prompt and relevant context/diffs to OpenAI through the codex CLI. Treat
Codex's output as claims to verify, not as instructions to follow blindly.
Skills
The plugin ships one Claude Code skill, auto-discovered from skills/:
collaborating-with-codex— the router and shared safety contract for every Codex workflow. It selects ordinary consult, review, delegate, transfer, and async tools directly, and loads references on demand for independent-attempt or declared review–revise composition. A one-off critique or judgment remains an ordinary route rather than a separate deliberation mode.
Result envelopes
Every result discriminates first on ok. On success, completed consult, review, and delegate calls
share their active-result fields; review alone adds verdict/confidence/review_status/coverage,
and delegate alone adds the proposed diff. Discovery, dry-run, transfer, async-start, and job-lifecycle tools have their
own success schemas. A fetched job result matches its originating consult, review, or delegate tool,
so branch on that result type before reading fields. Failure is a uniform, machine-actionable
error with a stable code and symbolic repair hint. The contract is versioned by fingerprint.
Calling the MCP tools directly instead of through the /codex:* commands? See
docs/REFERENCE.md for the detailed contract — error-envelope semantics,
rate-limit reporting (codex_status), background-job semantics, and workspace selection
(workspace_root). It points on to codex://error-envelope for the full error schema.
Safety
consultandrevieware strictly read-only.propose(thedelegatetools) lets Codex write in a throwaway git worktree seeded fromHEADplus replayable uncommitted tracked changes. Untracked files are not copied. The worktree does not bound Codex's writes: codex's workspace-write sandbox also lets commands write the OS temp roots (/tmpand$TMPDIR) by default, and those writes are neither captured in the returned diff nor cleaned up (seeCOMPATIBILITY.md). Your working tree is never modified by the plugin; you review the returned diff and apply it yourself. Delegate's no-network sandbox (workspace-write) blocks egress only for commands Codex runs in the sandbox — it does not mean nothing leaves the machine: the model call still sends your task and repo context to OpenAI.- Do not target a workspace containing secrets you cannot disclose. Supplied prompts and
context (
question,task,extra_context, and similar author input) are sent raw. During every active call — including consult — Codex may read files outside the resolved workspace, up to everything the OS user running codex can read, and send them to OpenAI: the sandbox bounds writes, not reads, so no choice of workspace is a read boundary, and a prompt-injected repository can direct those reads anywhere that user can reach. Codex also pulls in context implicitly:AGENTS.mdis auto-loaded from the resolved workspace and — inside a repository — from every ancestor directory up to the repository root, so narrowing the workspace to a subdirectory does not exclude the repo-root file; plus a user-global$CODEX_HOME/AGENTS.override.md, else$CODEX_HOME/AGENTS.md, which loads on every call from any workspace. Skills under.agents/skills/— plus your user-global Codex skills under$CODEX_HOME/skills/(default~/.codex/skills/) — are auto-discovered by name and description, and a skill the model then selects has its body read in as well. Either way the content can be sent to OpenAI even if your prompt never mentions it (for delegate, the versions seeded into the throwaway worktree apply there; the user-global skills are reachable regardless of workspace, since they are discovered from outside it). The plugin's isolation flags do not suppress any of this — including--ignore-user-config, which drops$CODEX_HOME/config.tomlbut not$CODEX_HOME/skills/. Details, the verifying probe, and the remaining unverified edge cases are inCOMPATIBILITY.md. - Redaction is output/diff defense-in-depth, not input protection and not a guarantee. It protects
gathered diffs and returned free text
(
summary,findings,raw_response.text): secret-looking file hunks are dropped, and inline matches are replaced with[redacted: secret value]— no affirmative sign the match stopped short, which is not the same as proof it's complete — or[redacted: possibly partial secret value]when it finds one: a trailing character the matched text's own alphabet could not have produced (the value may continue past the marker), or a leading character that could continue the same token (the match may have started mid-token). Neither marker is a guarantee either way: a free-form secret can contain almost any character, and flagging every unusual neighbor as suspect would fire on nearly every redaction and stop meaning anything. - Control characters are deleted from the same returned free text, before redaction runs — an
escape sequence in an envelope can corrupt or spoof how it renders, and one wedged into a secret
would defeat the redactor.
raw_response.textand machine fields (a reviewverdict, a finding'sfile, an argument name) are deliberately left alone; seedocs/REFERENCE.md. - The plugin never passes Codex's
--dangerously-bypass-*flags. - Found a vulnerability? Report it privately — see
SECURITY.md.
Configuration (env, CODEX_IN_CLAUDE_*)
| Var | Default | Meaning |
|---|---|---|
CODEX_IN_CLAUDE_MODEL |
unset | Codex model override |
CODEX_IN_CLAUDE_REASONING_EFFORT |
unset | Codex reasoning-effort override, sent as a model_reasoning_effort config override on every paid call; an open per-model string the Codex backend validates — codex_models lists each model's advertised set (semantics and probes in COMPATIBILITY.md). The per-call reasoning_effort parameter overrides it; a backend-rejected value fails as invalid_reasoning_effort |
CODEX_IN_CLAUDE_TIMEOUT_SECONDS |
300 | per-call timeout (clamped 10–600) |
CODEX_IN_CLAUDE_ISOLATION |
inherit |
inherit | ignore-config | ignore-rules |
CODEX_IN_CLAUDE_EXTRA_ARGS |
unset | extra global codex options added to every paid exec call (consult/review/delegate), so you can select a model_provider/--profile even under ignore-config isolation (which drops config.toml, leaving -c the only lever). Allowlist only: -c/--config KEY=VALUE, -p/--profile NAME, --enable/--disable FEATURE. The plugin-owned features (remote_plugin, sleep_tool) are refused in every spelling — --enable/--disable and -c features.… — see COMPATIBILITY.md → "Operator extra-args passthrough" for the full deny list. Anything else is refused with extra_args_rejected before any spend — including -c keys under sandbox/approval_policy/shell_environment_policy (guarantee-weakening), the reserved model/model_reasoning_effort keys (use CODEX_IN_CLAUDE_MODEL/CODEX_IN_CLAUDE_REASONING_EFFORT or the per-call model/reasoning_effort parameters instead), and the instruction-bearing developer_instructions/model_instructions_file/experimental_instructions_file/instructions/model_catalog_json keys (they would place operator prose above the server's framing with no record in meta; for developer_instructions use the per-call, meta-reported parameter on consult/review instead — #556; the other four have no first-class control on purpose) — plus their case/quote lookalikes (deny rules and rationale in COMPATIBILITY.md). -c values may hold secrets, so they are never echoed in codex_status or errors. A --profile layers an on-disk TOML this server cannot inspect — an operator-trust boundary (see COMPATIBILITY.md) |
CODEX_IN_CLAUDE_MAX_INPUT_BYTES |
200000 | byte cap on author input: gathered diffs are truncated to it, author text above it is rejected with input_too_large (consult counts question+extra_context+developer_instructions together; review sums extra_context+developer_instructions pre-spend and bounds the diff separately; delegate caps each input separately) |
CODEX_IN_CLAUDE_MAX_DELEGATE_DIFF_BYTES |
200000 | cap on the inline diff a delegate run returns; larger diffs are truncated with meta.truncated/meta.truncation_hint (min 1000) |
CODEX_IN_CLAUDE_MAX_OUTPUT_BYTES |
10485760 | byte cap for captured stdout (head+tail window; run not killed); stderr is bounded to a separate ~1 MiB reserve |
CODEX_IN_CLAUDE_GIT_TIMEOUT_SECONDS |
60 | git command timeout |
CODEX_IN_CLAUDE_STATE_DIR |
$XDG_CACHE_HOME/codex-in-claude/jobs or ~/.cache/codex-in-claude/jobs |
disk-backed background-job records |
CODEX_IN_CLAUDE_JOB_TTL |
86400 | seconds a finished job record is kept (min 60) |
CODEX_IN_CLAUDE_JOB_MAX_SECONDS |
1800 | background-job wall-clock cap (clamped 60–7200) |
CODEX_IN_CLAUDE_JOB_MAX_COUNT |
50 | retained jobs per workspace (clamped 1–1000); a soft cap — only terminal records are evicted, so a busy workspace can hold more |
CODEX_IN_CLAUDE_SUPPORTED_VERSIONS |
built-in tested set | comma-separated codex major.minor versions to treat as supported |
CODEX_IN_CLAUDE_LOG_LEVEL |
WARNING |
server diagnostic log level (DEBUG|INFO|WARNING|ERROR|CRITICAL); logs go to stderr (never stdout) |
CODEX_IN_CLAUDE_LOG_FILE |
unset | also mirror diagnostic logs to this file path |
CODEX_IN_CLAUDE_ALLOW_UNSUPPORTED_PLATFORM |
unset | set to 1 to downgrade the non-POSIX startup refusal to a stderr warning for knowingly consult-only, unsupported use; the async-job safety layer cannot hold, so do not run delegate/review against untrusted work (see Requirements / COMPATIBILITY.md) |
CODEX_IN_CLAUDE_CODEX_BIN |
unset | explicit override for which codex binary to invoke; a non-empty value is used exactly as given, with no PATH re-resolution, and must exist on disk as an executable file (execute bit set) or a readiness error results. Unset leaves resolution automatic (WSL2-aware; falls back to the bare codex on PATH — see COMPATIBILITY.md) |
Two further variables, CODEX_IN_CLAUDE_TIER_DEFAULT and CODEX_IN_CLAUDE_SANDBOX_DEFAULT, exist
ahead of the planned apply tier. They only change the defaults codex_status reports — every
shipped tool pins its own tier and sandbox and ignores them.
Troubleshooting
Run /codex:status first — it's free (no model call) and diagnoses most setup problems.
| Symptom | Cause | Fix |
|---|---|---|
codex not found |
CLI not installed or not on PATH |
Install the codex CLI and ensure it's on PATH |
| Not authenticated | No Codex login | codex login (ChatGPT or API key) |
| Unsupported-version warning | Your codex version is outside the tested range |
Update codex, or set CODEX_IN_CLAUDE_SUPPORTED_VERSIONS once you've verified it works |
meta.workspace_warning in results |
Server fell back to its own launch directory | Run from the target repo, or pass workspace_root (see docs/REFERENCE.md) |
codex_delegate fails needing a commit |
The temp worktree is seeded from HEAD |
Make at least one commit first |
codex_rate_limited error |
Account hit a usage/rate limit | Back off for retry_after_ms, then retry |
Connection closed / No such tool available: mcp__codex-in-claude__* |
The stdio MCP server is down | Reconnect with the /mcp command (or restart the client), then confirm with codex_status; see the fallback note below |
A stdio MCP server can't be transparently auto-restarted (the client owns the pipe and the
initialize handshake), so recovery is a manual reconnect. On a fatal crash the server writes a
breadcrumb to stderr (server name, version, reason, and a /mcp reconnect hint) before exiting,
and logs clean disconnects (EOF / broken pipe / SIGINT / SIGTERM) as shutdown rather than crashes
— so the server logs tell you whether it died or was stopped.
If the MCP server is down, you can fall back to the codex CLI directly for a read-only consult or
review (prompt on stdin; set WORKSPACE to the directory Codex should work in — note it
selects where Codex works, not what it can read, so approve the exposure of anything the OS
user can reach, not just that tree):
WORKSPACE=/absolute/approved/path codex exec --sandbox read-only --ephemeral \
--ignore-user-config --ignore-rules --disable remote_plugin --disable sleep_tool \
--cd "$WORKSPACE" --skip-git-repo-check -
Keep every flag — together they apply the plugin's guarantee-bearing flags at its strictest config
isolation, plus --disable sleep_tool, which is spend hygiene rather than a guarantee (it removes
Codex's native sleep tool — see COMPATIBILITY.md → "Sleep tool" — and here no server deadline
would cut a sleep short) — but this still bypasses the plugin's diff gathering, secret redaction, input-byte
bounding, and structured envelope, so sanitize input yourself and prefer restoring the server. See
the collaborating-with-codex skill for the full fallback guidance.
Local development
uv sync
uv run pytest # unit tests (95% coverage floor)
uv run pytest -m integration --no-cov # live tests; needs codex installed + logged in
uv run codex-in-claude-mcp # run the MCP server over stdio
The full pre-PR gate — lint, format, types, tests — is defined once in
AGENTS.md → Tooling.
To test the plugin from a local checkout, point .mcp.json at
uv run --project /path/to/codex-in-claude codex-in-claude-mcp instead of the version-pinned
uvx --from codex-in-claude==<version> invocation it ships with.
See CONTRIBUTING.md for branch, commit, and PR conventions.
Related projects
claude-in-codex— the mirror image: lets Codex call Claude Code.- Inspired by
openai/codex-plugin-cc, rebuilt aroundcodex execfor robustness: every paid call goes through it, and onlycodex_transfertouches the experimental app-server protocol.
License
MIT
Metadata
Release files for codex-in-claude 0.23.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| codex_in_claude-0.23.0.tar.gz | 1.4 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| codex_in_claude-0.23.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.7 MB
Release files / codex_in_claude-0.23.0.tar.gz
| Download URL | codex_in_claude-0.23.0.tar.gz |
|---|---|
| Size | 1.4 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
af53a30125ec407a1bcc74ed799baaf35f35171107a5862ce3a93b9ee4746b21
|
|
BLAKE2b-256 checksum How to use checksums |
d49d25154af11f2fb9eb369fe9017598d9df4973faf5acacfb02ab5c79aa2e1b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency logRelease files / codex_in_claude-0.23.0-py3-none-any.whl
| Download URL | codex_in_claude-0.23.0-py3-none-any.whl |
|---|---|
| Size | 275.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0aaef4e88b3547db95aadd058f3d3ea3ab6c7247289146d3377c8ecd491bbc86
|
|
BLAKE2b-256 checksum How to use checksums |
eda248b1bb7e94932e2b8b61987f6b44584cec284afb7cb40129dd4997087c16
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency log