agent-duet
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@agent-duetAdd retry-with-backoff to the HTTP client and cover it with tests"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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/projectUse --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 changesbaseor 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
PATHblock to your shell profile.-d/--directoryskips 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
.gitignorefirst 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-projectThen work normally, in either CLI:
/duet Add retry-with-backoff to the HTTP client and cover it with testsType /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 uninstallIf 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 firstThat 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 runlogs 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_statuson 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? |
| Validates the repo, creates the run, spawns a detached worker, returns a | No |
| Durable phase, verified worker/child liveness, timestamps, evidence, next action | No |
| The same, after one foreground-safe wait of at most 90 s | No |
| Sets the cancel flag and reaps the worker's process group | No |
| 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 -> COMPLETEIf the first authoritative validation fails, one bounded repair path runs:
FINAL_VALIDATING -> CLAUDE_VALIDATION_REPAIRING -> FINAL_VALIDATINGClaude 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 fullWhat you saw | What to do |
Fails immediately at | run |
Fails at | run |
|
|
| all global slots are occupied; wait, finalize, cancel, or raise the configured limit |
| commit or stash, then retry on the same branch |
| from this checkout, run |
Validation fails twice | run |
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 --applycancel 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 repositoryKeep 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 toolsduet_cancelADestructiveIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| run_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| repo | Yes | |
| error | No | |
| phase | Yes | |
| branch | No | |
| run_id | Yes | |
| summary | No | |
| base_sha | No | |
| evidence | No | |
| liveness | No | |
| terminal | Yes | |
| worktree | No | |
| created_at | Yes | |
| updated_at | Yes | |
| current_sha | No | |
| next_action | No | |
| delivery_mode | No |
TDQS
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.
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.
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.
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.
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.
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_finalizeADestructive
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.
| Name | Required | Description | Default |
|---|---|---|---|
| push | No | ||
| run_id | Yes | ||
| commit_message | Yes | ||
| expected_branch | Yes | ||
| deployment_profile | No | ||
| expected_remote_url | No | ||
| expected_remote_name | No | origin |
Output Schema
| Name | Required | Description |
|---|---|---|
| phase | Yes | |
| branch | Yes | |
| pushed | No | |
| run_id | Yes | |
| summary | No | |
| terminal | Yes | |
| tree_sha | No | |
| deployment | No | |
| remote_url | No | |
| next_action | No | |
| remote_name | No | |
| staged_paths | No | |
| local_commit_sha | Yes | |
| remote_commit_sha | No | |
| validation_manifest | No |
TDQS
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.
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.
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.
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.
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.
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_startADestructive
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 -- tomainif 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_branchparks the work on a newagent-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.
| Name | Required | Description | Default |
|---|---|---|---|
| task | Yes | ||
| repo_path | Yes | ||
| delivery_mode | Yes | ||
| idempotency_key | No | ||
| expected_base_ref | No | ||
| acceptance_criteria | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| repo | Yes | |
| error | No | |
| phase | Yes | |
| branch | No | |
| run_id | Yes | |
| summary | No | |
| base_sha | No | |
| evidence | No | |
| liveness | No | |
| terminal | Yes | |
| worktree | No | |
| created_at | Yes | |
| updated_at | Yes | |
| current_sha | No | |
| next_action | No | |
| delivery_mode | No |
TDQS
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.
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.
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.
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.
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.
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_statusCRead-onlyIdempotent
Return durable status and concise evidence for one run. No side effects.
| Name | Required | Description | Default |
|---|---|---|---|
| run_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| repo | Yes | |
| error | No | |
| phase | Yes | |
| branch | No | |
| run_id | Yes | |
| summary | No | |
| base_sha | No | |
| evidence | No | |
| liveness | No | |
| terminal | Yes | |
| worktree | No | |
| created_at | Yes | |
| updated_at | Yes | |
| current_sha | No | |
| next_action | No | |
| delivery_mode | No |
TDQS
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.
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.
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.
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.
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.
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_waitARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| run_id | Yes | ||
| timeout_seconds | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| repo | Yes | |
| error | No | |
| phase | Yes | |
| branch | No | |
| run_id | Yes | |
| summary | No | |
| base_sha | No | |
| evidence | No | |
| liveness | No | |
| terminal | Yes | |
| worktree | No | |
| created_at | Yes | |
| updated_at | Yes | |
| current_sha | No | |
| next_action | No | |
| delivery_mode | No |
TDQS
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.
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.
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.
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.
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.
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.
5 tool updates
v1.0.0- First observed
duet_cancel - First observed
duet_finalize - First observed
duet_start - First observed
duet_status - First observed
duet_wait
TDQS
Scored across 5 tools
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.
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.
Five tools cleanly cover an orchestration lifecycle without redundancy. Each tool earns its place and nothing feels padded or missing for the stated scope.
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
Related MCP Connectors
AI work orchestration for plans, tasks, teams, and coding-agent dispatch.
- ParleyOAuthdev.weldra
Coordination hub for AI coding agents: message teammates, ask humans, audit every event.
Deterministic AI code review, with an audit record. Governance inside the agent loop.
Multi-reviewer AI code review: surfaces findings the reviewers agree on, disputes flagged.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables Claude to collaborate with Gemini for code reviews, second opinions, and iterative software development. It facilitates multi-step workflows including PRD creation and code generation through an AI orchestration framework.29 npm1MIT
- AlicenseAqualityBmaintenanceEnables adversarial code review by connecting Claude Code to OpenAI Codex, iterating until consensus is reached between the two AI models.345 npm1MIT
- AlicenseNot gradedqualityBmaintenanceTurns Claude Code into an engineering project manager by orchestrating feature development with isolated Git worktrees, structured task validation, and approval-gated integration.1MIT
- AlicenseNot gradedqualityBmaintenanceOrchestrates Claude Code and OpenAI Codex to plan, implement, review, and verify code changes via pull requests with security controls.1MIT