Skip to main content
Glama

agent-duet

Have Claude write the code, have Codex review it, then have Claude answer the review — automatically, in one command, with nothing committed until you say so.

You type /duet <what you want done>. Three separate AI sessions run one after another, your tests run, and then it stops and shows you what happened. You decide whether it ships.


Why bother

Asking one model to review its own work does not really work — it agrees with itself. The usual fix is to copy the diff into a second tool by hand, paste the critique back, and keep track of which round you are on. That is the whole job this does for you.

Three rules make it worth the trouble, and none of them is a promise in a prompt — each one is enforced by code:

  • The implementer never reviews its own work. The reviewer is a different CLI, in a different process, with no memory of writing the code.

  • The reviewer cannot edit anything. agent-duet fingerprints the repository before and after the review and compares. If the reviewer touched a file, you are told.

  • Neither one can publish. Committing and pushing live in a separate tool call that only runs after you approve.


Related MCP server: HiveClaude

How a run works

   you ──▶ /duet "add retry-with-backoff to the HTTP client"
                    │
      ┌─────────────▼─────────────┐
      │ 1. Claude Code implements │   a fresh process, no history
      └─────────────┬─────────────┘
      ┌─────────────▼─────────────┐
      │ 2. Codex reviews          │   read-only, verified read-only
      └─────────────┬─────────────┘
      ┌─────────────▼─────────────┐
      │ 3. Claude Code reconciles │   fixes what is justified, argues what is not
      └─────────────┬─────────────┘
      ┌─────────────▼─────────────┐
      │ 4. your tests run         │
      └─────────────┬─────────────┘
                    ▼
              it STOPS and reports  ──▶  you approve  ──▶  commit (+ optional push)

A focused change often takes 5 to 20 minutes. A whole-project audit can take hours. Three real AI sessions run end to end, and the work keeps going if you close your terminal.


Install

git clone https://github.com/slyfox1186/Claude_Code_Codex_MCP_Coordinator.git
cd Claude_Code_Codex_MCP_Coordinator
./setup.sh -d /path/to/your/project

Use --directory instead of -d if you prefer the long form. You can also omit the option and enter the project path when prompted. Setup explains what it needs and asks for consent before creating an environment or installing a missing provider CLI.

  • If Conda is detected, it creates a dedicated environment named agent-duet. Setup never installs Conda or changes base or another environment.

  • Without Conda, it uses the default Python 3.13+ only to create a private environment; packages are not installed into system Python.

  • If Claude Code or Codex is missing, it offers the official installer. It also offers sign-in and a throwaway demo. Before consent, setup shows the expected user-local files; the vendor installers manage their own updates, and Codex may add a PATH block to your shell profile.

  • -d/--directory skips the demo and project-path questions. The value may be relative, absolute, ~/..., and may end in /.

  • The selected project may be an ordinary folder. Setup automatically creates the local Git baseline Agent Duet needs to compare Claude's and Codex's work. It records every existing non-ignored file in one local commit, adds no remote, and uploads nothing. Review the project's .gitignore first if it may contain sensitive files.

Requirements: Linux and Git, plus Python 3.13+ when Conda is absent. curl or wget is needed only if a provider CLI must be downloaded. See INSTALL.md and read SECURITY.md before use.

Setup never uses sudo. It validates generated configuration, backs up files it replaces to <name>.duet-backup, and is safe to rerun.

Setup merges only mcp__agent_duet__duet_status and mcp__agent_duet__duet_wait into Claude Code's user allow rules. Those two tools only read run state. duet_start, duet_cancel, and duet_finalize keep Claude Code's normal permission checks, so installation does not preapprove starting, stopping, committing, or pushing work.

After setup or an upgrade, close and reopen any Claude Code or Codex sessions that were already running. An open client keeps the MCP process and /duet instructions it loaded at startup; continuing in it can show stale or unverifiable progress.


Use it

Point it at a project during installation or later:

./setup.sh -d ~/code/my-project
./setup.sh --directory ~/code/my-project
./setup.sh add-repo ~/code/my-project

Then work normally, in either CLI:

/duet Add retry-with-backoff to the HTTP client and cover it with tests

Type /duet with nothing after it and it will work out the task from your conversation, or ask you if there is nothing to work from. Either way it confirms the acceptance criteria before spending your time.

When it finishes it prints what it did and waits. Say "finalize" and it commits the validated change. If the project has a remote, it can push after approval; without one, it completes with a local commit. Say nothing and nothing happens.

Other setup commands

./setup.sh check                          # is everything working?
./setup.sh -d ~/code/project              # guided setup + this project
./setup.sh --directory ~/code/project     # identical long form
./setup.sh add-repo ~/code/project        # let it work on a project
./setup.sh remove-repo ~/code/project
./setup.sh demo                           # a throwaway project to try it on
./setup.sh demo --clean
./setup.sh uninstall

If a registered project was moved or deleted, check reports that path as a warning instead of claiming Agent Duet is broken. Restore the folder, or remove the stale entry with ./setup.sh remove-repo /old/project/path.

Project registration allows the project's parent directory, detects its test suite (pytest, npm test, cargo test, go test), and writes the config entry between markers so remove-repo takes it back out cleanly. If the folder has no Git history, setup automatically creates the same local-only baseline used by -d.

For Python tests, setup asks before creating a separate validation environment for that project. It uses constraints.txt to constrain resolution; installs every dependency in requirements.txt, app/requirements.txt, requirements-dev.txt, and the test-requirements variants; installs a PEP 621 pyproject.toml project when present; then installs and verifies pytest. Target-project packages never enter Agent Duet's own environment, Conda base, or another project's environment.

Two different projects can run concurrently by default. A project still gets only one active run, preventing two agent pairs from editing the same checkout. Adjust max_parallel_global from 1 through 16 in ~/.config/agent-duet/config.toml if your machine or provider limits call for a different total. Existing explicit settings are preserved during upgrades.


Where the work ends up

By default a run works on the branch you are already on, so finalizing commits there. If you are on main, it commits to main. That is what most people mean by "make this change", and it needs a clean working tree, because the run edits your checkout in place.

If you explicitly want the work isolated, ask for a review branch:

/duet <task> — put it on a review branch, I want to look first

That runs in a private worktree instead, leaving your checkout completely untouched, and lands the work on its own agent-duet/<id> branch for you to merge. Agent Duet never selects or suggests this mode merely because your working tree is dirty.

Every interactive /duet run passes its mode explicitly. No machine-wide default can silently create a branch.


Checking its work yourself

Everything a run did is kept on disk. You never have to trust the summary.

agent-duet runs                # every run, newest first
agent-duet logs <run-id>       # everything about one run

logs prints the whole story: every command it ran, every argument, every phase transition with a timestamp, and why it stopped. It never prints passwords or tokens, so you can paste it to someone as-is.

Worth confirming once, the first time:

  • The reviewer really was read-only. Look for codex_readonly_verified: true. That is measured — a fingerprint before and after — not claimed.

  • The run outlives your session. Close the CLI completely, open a new one anywhere, and ask for duet_status on the run id. Same run, still going.


The tools

/duet calls these for you. You can also just ask either CLI in plain words.

Tool

What it does

Publishes?

duet_start

Validates the repo, creates the run, spawns a detached worker, returns a run_id in seconds

No

duet_status

Durable phase, verified worker/child liveness, timestamps, evidence, next action

No

duet_wait

The same, after one foreground-safe wait of at most 90 s

No

duet_cancel

Sets the cancel flag and reaps the worker's process group

No

duet_finalize

Commits, pushes, verifies the remote ref, runs a deployment verifier

Yes

duet_start cannot commit, push, deploy, change remotes, or rewrite history — not because a prompt forbids it, but because that code does not exist on that path. Publishing lives only in duet_finalize, which re-verifies the branch, the remote URL, and the exact diff fingerprint that was validated before it will touch anything.


Phases

User-facing updates identify the three model phases plainly: Phase 1 of 3 — Claude implements, Phase 2 of 3 — Codex reviews, and Phase 3 of 3 — Claude reconciles. Phase 1 is not the final step. The names below are the internal state-machine values.

QUEUED -> CLAUDE_IMPLEMENTING -> HANDOFF_VALIDATING -> CODEX_REVIEWING
       -> REVIEW_INTEGRITY_CHECK -> CLAUDE_RECONCILING -> FINAL_VALIDATING
       -> AWAITING_FINALIZE -> FINALIZING -> COMPLETE

If the first authoritative validation fails, one bounded repair path runs:

FINAL_VALIDATING -> CLAUDE_VALIDATION_REPAIRING -> FINAL_VALIDATING

Claude receives the measured exit code and redacted output, repairs the root cause, and the coordinator reruns the complete configured validation set. A second failure is terminal; both attempts remain in the evidence. A failed or cancelled run can never be published with raw Git through /duet—only duet_finalize may publish, and only from AWAITING_FINALIZE.

FAILED, CANCELLED, and COMPLETE are terminal. Every transition is written to SQLite with a timestamp and a reason before the work that follows it happens.

Every status also reports server-measured liveness: whether the detached worker and the expected Claude or Codex child process are alive at that instant. /duet may call a model phase active only when that status belongs to the retained run_id and reports MODEL_ACTIVE; a lost or unknown result is never treated as progress. If cleanup could not terminate a recorded worker or child process, status reports CLEANUP_REQUIRED; repeating duet_cancel retries cleanup instead of forgetting it.

The run survives the client that started it — the worker is detached, so you can close the terminal, reopen either CLI, and pick up where you left off.

Status polling does not limit model work. The shipped configuration gives each Claude or Codex phase a 7,200-second safety ceiling, runs Claude at xhigh effort and Codex at high reasoning effort, and applies no Claude dollar cap. Change those quality/runtime settings in config.toml if a particular machine needs a different trade-off.

If the worker itself dies, that is terminal. The next duet_start on that repository records the run as FAILED with its evidence preserved. There is no phase-aware resume, and a half-finished run is never silently continued.


When something goes wrong

agent-duet logs        # the most recent run, in full

What you saw

What to do

Fails immediately at CLAUDE_IMPLEMENTING

run claude on its own once and sign in

Fails at CODEX_REVIEWING

run codex on its own once and sign in

not below an allowed_repo_roots entry

./setup.sh add-repo <the project>

already active ... max_parallel_global is N

all global slots are occupied; wait, finalize, cancel, or raise the configured limit

refusing an in-place run ... dirty working tree

commit or stash, then retry on the same branch

Denied by auto mode classifier while polling

from this checkout, run ./setup.sh install, or add mcp__agent_duet__duet_status and mcp__agent_duet__duet_wait through Claude Code's /permissions; then retry the poll

Validation fails twice

run agent-duet logs <run-id>; both command results and output tails are preserved

Refuses to finalize

read the reason; something changed after the tests ran


Operator commands

agent-duet doctor              # health report
agent-duet runs                # every run, newest first
agent-duet logs [run-id]       # everything about one run (default: the most recent)
agent-duet cancel <run-id>     # clear an unfinished run and free its slot
agent-duet gc --older-than 30  # dry run: list what old terminal runs left behind
agent-duet gc --older-than 30 --apply

cancel accepts an id prefix. It exists because a run parked at AWAITING_FINALIZE has no live worker and is never reaped — it is waiting for a person — yet it still counts as active, so with the default max_parallel_global = 2 it occupies one of the two global slots until someone finalizes or cancels it.

gc forgets a terminal run completely: its artifact directories, git's worktree registration in the real repository, and its row in the listing. It never deletes a run's branch — that holds the work — so it reports the branches it orphans instead. It only ever touches directories inside the state tree, and only for terminal runs.


Where things live

~/.config/agent-duet/config.toml               0600
~/.local/state/agent-duet/state.sqlite3        0600, WAL
~/.local/state/agent-duet/runs/<run-id>/       0700   prompts, logs, artifacts, manifests
~/.local/state/agent-duet/worktrees/...        0700   private worktrees (review-branch runs)
~/.local/state/agent-duet/locks/               0700   one flock per repository

Keep the state directory off NFS, Dropbox, and Syncthing. Two machines must never share it; they coordinate through git remotes, not through this database.

The config file must be a regular file you own, and must not be group- or world-writable: it names the executables to run and the exact command vectors the coordinator will execute, so write access to it is equivalent to code execution. Loading refuses otherwise.


Installing by hand

Everything setup.sh does is ordinary configuration; nothing is hidden. Copy config.example.toml to ~/.config/agent-duet/config.toml, replace every REPLACE_ME, chmod 700 the config and state directories and 600 the config file, then run agent-duet doctor. Register the server:

claude mcp add-json --scope user agent_duet \
  '{"type":"stdio","command":"<path>","args":[],"env":{},"timeout":120000}'
codex mcp add agent_duet -- <path>

Merge these two exact read-only rules into permissions.allow in Claude Code's user settings; do not replace unrelated settings and do not allow mcp__agent_duet__*:

{
  "permissions": {
    "allow": [
      "mcp__agent_duet__duet_status",
      "mcp__agent_duet__duet_wait"
    ]
  }
}

Use /permissions when changing the rules interactively. Then add tool_timeout_sec = 120 and enabled_tools to the [mcp_servers.agent_duet] table Codex wrote. duet_wait returns within 90 seconds so it stays below Claude Code's two-minute MCP auto-background threshold. Copy commands/duet.md into ~/.claude/commands/ and ~/.codex/prompts/. If an older manual installation reports Denied by auto mode classifier, run ./setup.sh install or add the same two rules through /permissions.


Security posture

Child agents run with full, unsandboxed machine access by deliberate operator decision. Read SECURITY.md before installing this anywhere you would not hand the same access to a person.


More

  • INSTALL.md — the short server installation guide

  • HOW_TO_TEST.md — try it in three commands

  • SECURITY.md — the trust model and every guard, in detail

  • HOW_TO_BUILD_THIS.md — installing it on another machine, step by step with a check after every step. Written to hand straight to Claude Code on the target PC.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

No tool schema history has been recorded yet.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/slyfox1186/Claude_Code_Codex_MCP_Coordinator'

If you have feedback or need assistance with the MCP directory API, please join our Discord server