Overview

Inside one VS Code session, in the virtual machine where all my development work runs, I talk to Claude Code, and the senior developer there directs the work. When a job is bounded and settled enough to hand off, that senior can run it through Codex instead of a Claude sub-agent, by calling my installed Codex command-line tool through a small launcher script. No container and no proxy sit in between: it is the same Codex I use in its own chat, driven for a single task and handing its answer back.

Two reasons to reach for it when Claude already has its own workers. Each subscription has its own usage limit, so moving a job to Codex keeps me working when the Claude side is near its cap. And a review or a plan read from a different provider is a separate opinion, not the same model checking its own work.

This leans on the side-by-side setup: Running Codex alongside Claude Code covers the configuration, shared skills, and agent files that make it possible, and the delegation and review model pages cover the rules it follows. Nothing here moves an approval: every git step and every irreversible action is still mine.

Which jobs cross over

The same worker roles the Claude senior hands down can go to a Codex counterpart instead:

  • a builder that implements an approved plan
  • a researcher that locates code without judging it
  • a correctness reviewer that reads the finished diff for bugs and missing tests
  • an intent reviewer that checks the change against what I actually asked for
  • a proposal reviewer that weighs a plan before it is built

Each role has its own Codex definition file with a fixed model, effort, sandbox, and set of standing instructions. The proposal reviewer exists only on the Codex side, since a Claude reviewer judging a Claude plan is the same provider checking its own work. For the other four I pick the side every time: when a job can be delegated, the senior names it and asks Claude or Codex, and I choose by which subscription has room. For a builder, the branch is made first, and the launcher enforces it.

How the hand-off works

Codex run from the command line does not apply a saved role on its own, so every hand-off goes through a launcher script. The senior names the role, and the launcher reads that role’s model, effort, sandbox, and instructions straight from its definition file and passes them to Codex. None of those values are copied into the brief or anywhere else, so the role file is the one place they live.

The brief is written to a file and holds only the job: the outcome wanted, the files in scope, the decisions already made, and a length limit on the report to send back. The standing rules stay in the role file. A builder’s brief also sets a completion bar: every item in the plan is either fully built or named as not done, with the reason. The launcher adds the name of the checked-out branch to the top of a builder’s brief, so the builder can confirm it without the senior having to remember to write it in.

The call takes this shape:

python codex_run.py <role> --cd "<working folder>" \
  --brief "<brief file>" --out "<scratch folder>"

--cd is the folder Codex works in: the repo under review, or the one folder a builder is allowed to change. --out is a scratch folder outside the repository. Each run gets its own folder there holding the brief, the full log, and the final answer, so nothing lands in the repository on its own.

The launcher refuses to start in a few cases:

  • the scratch folder is inside the working folder
  • for any role that can write files, the working folder is not a git repository, is on main or master, or has no branch checked out

Codex itself is also started in strict mode, so a mistake in its configuration stops the run instead of being quietly ignored.

The launcher also switches off Codex’s own helper agents for that run, so a delegated job cannot start more Codex sessions of its own. The switch applies to the one run only: my Codex settings file is unchanged, and Codex chats I open directly keep their helper agents. Because Codex runs in strict mode, a setting it did not recognize would stop the run, so this one cannot be quietly dropped.

A builder leaves its edits in place but uncommitted, because Codex never touches git; I still approve every commit, merge, and push the usual way.

When a builder stops

A flaw a builder finds in its own changes is part of the job: it fixes it within the plan, keeps going, and mentions it in the report. It stops early only for set reasons:

  • the branch is not the one named in the brief
  • the plan is unclear
  • the work would touch files outside the ones in scope
  • a test looks wrong, since changing a test to make it pass is my call, not the builder’s
  • the work would need a new third-party dependency

Confirming it ran as asked

When the run ends, the launcher reads the log and prints a short summary: the exit code, the model, effort, and sandbox Codex reports it actually used, the tokens used, and the final answer. If any of the three settings is missing from the log or differs from the role file, it prints a warning. The senior reads that summary and opens the full log only when the exit code is not 0 or the answer is missing.

The summary is not the proof, and neither is the builder’s own report. For a builder, the senior reads the actual changes and runs the tests again itself before bringing anything to me. A token count far below what the job should take usually means the worker stopped early, so the senior checks what was covered before reviewing the detail.

One limit holds throughout: on Windows the Codex read-only sandbox bounds what a job can write, not what it can read, so a read-only role rests on the trust I extend to Codex, not a proven wall around what it sees.

Pytest and Windows permissions

On Windows, Codex runs its commands under its own separate Windows accounts. The temporary folders pytest creates during a test run are locked to those accounts, so only Codex or an administrator can remove them, and pytest leaves them behind by default.

Every run gets a new folder with a short name directly under the system temporary folder, and the launcher tells Codex to point pytest’s temporary files there, turn off pytest’s cache, and delete that folder itself as its last step. The short location keeps test file paths under the 260-character limit that Windows places on paths by default.

In case that step is skipped or fails, the launcher also cleans up after every run. It runs a small cleanup script inside Codex’s own sandbox, as Codex’s Windows account, which is the account that owns the files. The script removes this run’s folder plus any leftover launcher test folder older than a day, and nothing else: it accepts only a folder directly in the temporary folder whose name matches the launcher’s exact pattern, and never follows a link. The summary reports whether each folder is gone; only one reported as left behind needs a person. One limit remains: a project whose tests rely on pytest’s cache will fail with the cache turned off.

Why the launcher works this way

Before the launcher, one real builder job used about 40% of a five-hour Codex usage window, and roughly a third of that was waste from three causes: a run that stopped because the brief did not name the branch, test failures from the Windows path-length limit, and a builder that stopped to report flaws in its own work instead of fixing them. The branch line the launcher adds, the short test folder, and the builder’s fix-and-continue rule each close one of those.

Helper agents are off for delegated runs for three reasons. Delegated jobs were starting their own Codex helpers, and those helpers used a large share of the Codex usage limit on top of the jobs themselves. The launcher’s summary counts only the delegated job’s own tokens, so that extra use did not show up in it. And a correctness review started by a helper ran at medium effort, not the high effort its role file sets, so it was not the review the role promises. In testing, Codex could not start a helper with the switch applied, and could without it.