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: Clonst

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.

Available Tools

5 tools
duet_cancelA
DestructiveIdempotent

Request cancellation and terminate the run's process group.

Side effects: signals the detached worker and its children (SIGTERM, then SIGKILL after a grace period). Files the run already wrote are left in place; nothing is committed, pushed, or deployed. Safe to call more than once.

ParametersJSON Schema
NameRequiredDescriptionDefault
run_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
repoYes
errorNo
phaseYes
branchNo
run_idYes
summaryNo
base_shaNo
evidenceNo
livenessNo
terminalYes
worktreeNo
created_atYes
updated_atYes
current_shaNo
next_actionNo
delivery_modeNo

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructive=true, idempotent=true, and readOnly=false, so the safety profile is covered structurally. The description then adds genuine beyond-annotation detail: SIGTERM followed by SIGKILL after a grace period, that already-written files persist, and that nothing is committed, pushed, or deployed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with the action front-loaded and side effects explicitly labeled. Every clause carries a distinct fact; there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need no explanation, and the annotations carry the safety profile. The description still supplies the operational details an agent needs: termination mechanism, data persistence, and repeat-call safety.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the single run_id parameter is documented nowhere. Its name and uuid format make the intent largely self-evident, but the description does not compensate with any clarification of the identifier's scope or how to obtain it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb pair (request cancellation, terminate) and an exact resource scope (the run's process group), which is unmistakable against siblings like duet_finalize, duet_wait, duet_start, and duet_status. An agent knows precisely what this call does without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the tool name and the cancellation semantics, and the description notes it is safe to repeat. However, it never states when an agent should prefer this over a sibling such as duet_finalize, nor any precondition (e.g., must the run be in a running state).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

duet_finalizeA
Destructive

Publish a validated run: commit, optionally push, optionally verify deployment.

Side effects: creates a real commit and, when push is true, pushes it to the named remote and runs the configured deployment verifier. A local-only commit needs no remote or remote URL. Only ever call this after the user has seen the evidence from duet_status/duet_wait and explicitly approved. Refuses unless the run is exactly AWAITING_FINALIZE and the branch and validated diff fingerprint still match; pushes additionally require an exact remote URL match.

ParametersJSON Schema
NameRequiredDescriptionDefault
pushNo
run_idYes
commit_messageYes
expected_branchYes
deployment_profileNo
expected_remote_urlNo
expected_remote_nameNoorigin

Output Schema

ParametersJSON Schema
NameRequiredDescription
phaseYes
branchYes
pushedNo
run_idYes
summaryNo
terminalYes
tree_shaNo
deploymentNo
remote_urlNo
next_actionNo
remote_nameNo
staged_pathsNo
local_commit_shaYes
remote_commit_shaNo
validation_manifestNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well past the annotations (destructive/non-idempotent/openWorld) by spelling out that a real commit is created, that push runs a configured deployment verifier, and by enumerating the exact refusal conditions: run must be AWAITING_FINALIZE, branch and validated diff fingerprint must match, and push requires an exact remote URL match.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads purpose, then a clearly labeled 'Side effects' paragraph, then the call precondition. Dense but every sentence adds a distinct constraint; no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present it needn't describe returns, and the safety-critical preconditions and side effects for a destructive, non-idempotent tool are all disclosed. Nothing an agent needs before calling is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% across 7 params, so the description must carry the load and it does for the ambiguous ones — what 'push' controls, that remote URL/name are only needed for pushes, and the remote URL matching requirement. run_id, commit_message and expected_branch are left to their self-evident names, which is a minor gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence gives a precise verb+resource ('Publish a validated run') plus the three-stage scope (commit / push / verify deployment), which cleanly separates it from siblings like duet_start, duet_wait, duet_status and duet_cancel.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states an explicit precondition ('Only ever call this after the user has seen the evidence from duet_status/duet_wait and explicitly approved') naming the sibling tools that produce that evidence, plus the local-only case where no remote is needed. When-to-use and when-not-to-use are both covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

duet_startA
Destructive

Start one Claude->Codex->Claude run and return immediately with its run_id.

delivery_mode decides where the work ends up:

  • direct_branch (the default) works on the branch the repository is already on, so finalize commits there -- to main if that is where the user is. This is what "make this change" normally means. It requires a clean tree and an attached HEAD, because the run edits the checkout in place.

  • review_branch parks the work on a new agent-duet/<id> branch that somebody then has to merge. Use it only when the user explicitly requested a new or separate branch.

Interactive model callers must pass direct_branch unless the user explicitly asked for a new branch. Never infer or suggest review_branch because the working tree is dirty. The argument is required: omission must never inherit a setting that silently creates a branch.

Side effects: creates a durable run record, a branch and private worktree (in review_branch mode), and a detached worker process that will modify files in that worktree. It NEVER commits, pushes, deploys, changes remotes, or rewrites history; publishing is duet_finalize only. Call this once per task, keep the run_id, and poll with duet_wait.

ParametersJSON Schema
NameRequiredDescriptionDefault
taskYes
repo_pathYes
delivery_modeYes
idempotency_keyNo
expected_base_refNo
acceptance_criteriaNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
repoYes
errorNo
phaseYes
branchNo
run_idYes
summaryNo
base_shaNo
evidenceNo
livenessNo
terminalYes
worktreeNo
created_atYes
updated_atYes
current_shaNo
next_actionNo
delivery_modeNo

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations by enumerating concrete side effects: durable run record, branch, private worktree, and a detached worker process that modifies files. It also draws a firm safety boundary ('NEVER commits, pushes, deploys, changes remotes, or rewrites history') and states the precondition of a clean tree and attached HEAD, which the destructiveHint/openWorldHint annotations do not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose and well organized with bullets for the two modes. The closing lines about not inferring review_branch restate the preceding warning about dirty working trees, which is mild redundancy rather than waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need no explanation, and the description still covers the async lifecycle, side effects, safety guarantees, and the required-argument constraint. Nothing an agent needs to invoke this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must carry parameter meaning. It does this thoroughly for delivery_mode (values, default, selection criteria) but says nothing about repo_path, task, idempotency_key, expected_base_ref, or acceptance_criteria, leaving half the argument surface undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Start one Claude->Codex->Claude run'), including the async contract ('return immediately with its run_id'). It is clearly distinguishable from siblings like duet_wait, duet_finalize, duet_cancel, and duet_status, each of which is named in the workflow description.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent between delivery_mode values ('Use it only when the user explicitly requested a new or separate branch') and gives a hard exclusion ('Never infer or suggest review_branch because the working tree is dirty'). It names the downstream alternatives too: 'publishing is duet_finalize only' and 'poll with duet_wait'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

duet_statusC
Read-onlyIdempotent

Return durable status and concise evidence for one run. No side effects.

ParametersJSON Schema
NameRequiredDescriptionDefault
run_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
repoYes
errorNo
phaseYes
branchNo
run_idYes
summaryNo
base_shaNo
evidenceNo
livenessNo
terminalYes
worktreeNo
created_atYes
updated_atYes
current_shaNo
next_actionNo
delivery_modeNo

TDQS

C2.8/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, and openWorldHint=false, so 'No side effects' is a restatement of the structured data rather than new information. The description adds no behavioral context such as auth needs, rate limits, or what 'durable' means for the returned status.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short, front-loaded sentences with the core action first. Slightly penalized because the trailing 'No side effects' clause duplicates annotation data rather than earning its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no explanation, and the single-parameter surface is simple. However, the description omits the one thing an agent actually needs here: how this differs from duet_wait when polling a run's state.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description is the only place that can clarify run_id. It says only 'for one run', which merely restates that run_id identifies a single run; it gives no hint about the UUID format or how the ID is obtained.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Return durable status and concise evidence') scoped to 'one run', which is clearly distinct from the sibling mutation tools (duet_start, duet_cancel, duet_finalize). It does not explicitly name an alternative, but the resource is unambiguous enough for an agent to select it.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit when-to-use guidance and no mention of alternatives such as duet_wait (which presumably blocks until a run reaches a state). The agent must infer that this is the non-blocking status check rather than a wait operation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

duet_waitA
Read-onlyIdempotent

Wait briefly for one run to change phase, then return its durable status.

Accepts legacy inputs through 300 seconds, but the effective wait is always capped at 90 seconds so Claude Code keeps the call in the foreground. Keep only one call in flight for a run and wait for its response before polling again. No side effects.

ParametersJSON Schema
NameRequiredDescriptionDefault
run_idYes
timeout_secondsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
repoYes
errorNo
phaseYes
branchNo
run_idYes
summaryNo
base_shaNo
evidenceNo
livenessNo
terminalYes
worktreeNo
created_atYes
updated_atYes
current_shaNo
next_actionNo
delivery_modeNo

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses a non-obvious behavioral quirk beyond the annotations: legacy inputs up to 300 seconds are accepted but the effective wait is hard-capped at 90 seconds. That is exactly the kind of context annotations cannot carry. 'No side effects' simply restates readOnlyHint/destructiveHint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, front-loaded with the purpose and the cap constraint. Slightly diluted by the trailing 'No side effects' line, which duplicates the annotations rather than adding information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained. The description covers the concurrency rule and timeout semantics that the schema omits; the only real gap is what 'change phase' means in terms of observable states.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must carry the load — and it does for timeout_seconds, explaining the legacy 300s acceptance and the 90s effective cap. run_id is left undefined, but for a UUID identifier that gap is minor.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — waits for a run's phase change and returns its durable status — which is enough to separate it from duet_status (a pure read). However, it never names the sibling it is contrasted with, so the agent must infer the distinction rather than being told.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete operational guidance: keep only one call in flight per run and wait for its response before polling again. What is missing is an explicit when-to-use-this-vs-duet_status rule, so the routing decision is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 5 tool updatesv1.0.0
    • First observedduet_cancel
    • First observedduet_finalize
    • First observedduet_start
    • First observedduet_status
    • First observedduet_wait

TDQS

A4/5.0

Scored across 5 tools

Disambiguation4/5

Each tool maps to a distinct lifecycle stage (start, status, wait, cancel, finalize). The only mild overlap is duet_wait vs duet_status, since both return status, but the descriptions clearly distinguish waiting-for-phase-change from a plain status read.

Naming Consistency5/5

All five tools use the same duet_ prefix followed by a concise verb (start, status, wait, cancel, finalize) in consistent snake_case. The pattern is predictable and readable.

Tool Count5/5

Five tools cleanly cover an orchestration lifecycle without redundancy. Each tool earns its place and nothing feels padded or missing for the stated scope.

Completeness5/5

The surface covers the full run lifecycle: start, poll status, wait for phase change, cancel, and finalize/publish. Nothing essential (create, monitor, abort, commit) is missing for a single-run orchestration model.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers