Two workers that correct each other
Open one worker with codex and another with cursor-agent on the same task, and have each review the other's diff.
Prompt#
Open an Orchemax worker with codex and another with cursor-agent on this task and have them correct each other.
What the Chair does#
Checks it is not a worker (denyWorkerFanout), resolves the project, then spawns one
worker per preset and relays each diff to the other.
MCP calls#
dispatch_worker({
"agent": "codex",
"prompt": "Rewrite client/internal/gateway/rotate.go so a 429 advances the ring. Report with verify_report.",
"title": "rotate ring on 429 — codex pass",
"name": "codex-a",
"timeout_sec": 900
})
dispatch_worker({
"agent": "cursor",
"prompt": "Review codex-a's diff on orch/<session>. Say what is wrong, do not rewrite it.",
"title": "rotate ring on 429 — cursor review",
"name": "cursor-b"
})
Or, when you want the acceptance criteria on the board:
task_add({ "title": "rotate ring on 429", "agent": "codex",
"context": "gateway owns the ring; keys live in machine-home keys.env",
"acceptance_criteria": ["go test ./internal/gateway/... -race passes",
"no key material in logs"] })
task_run({ "id": "<task id>", "timeout_sec": 900 })
Relay between the two, then close:
msg_send({ "from_session": "<chair session>", "to_worker": "cursor-b",
"kind": "handoff", "body": "codex-a diff on orch/<session>; review, do not rewrite" })
worktree_promote({ "session": "<the session you keep>" })
Expected response#
dispatch_worker and task_run return as soon as the worker is running:
{task?, session_id, worker_id, name, worktree, branch, log, status: "running", note}.
branch is orch/<session> — the branch you paste into the reviewer's prompt,
available while the first worker is still writing. Pass wait: true to block
until the worker exits instead; that reply adds exit, worktree_kept and
verification (the worker's own half — tests[], symbols[], criteria[],
summary from verify_report — plus Orchemax's observed half — guardrails,
files[]). msg_send returns {message, delivery}.
Gotchas#
- The preset id is
cursor, notcursor-agent.cursor-agentis the binary behind it; Orchemax's preset key iscursor, and it runs as a plain subprocess — ACP transport ships only forgeminiandopencode. codexandcursorhave headless defaults too.agents.cmdsshipscopilot,agy,claude,opencode,grok,kimi,commandcode,codexandcursorout of the box.mimoandzcodestill exist only inagents.interactive. Dispatch a recognized CLI preset that has noagents.cmds.<preset>entry and Orchemax fails loudly to the Chair (preset "<preset>" has no headless command: set agents.cmds.<preset>) instead of silently running the stub agent.dispatch_workerreturns as soon as the worker is running (status: running,session_id,worker_id); the two workers run at the same time and the Chair gets ahandoffmessage on the bus when each one exits. Passwait: trueto block until the exit code and verification are in. A worker cannot spawn the other half itself.- The reviewer still finds the diff after the writer exits. With the default
keep_worktree: falsea finished worker's worktree andorch/<session>branch are kept while another worker on the same project is still running (the reply saysworktree_kept: true), and swept when the last one finishes. Before that, the first worker to finish deleted the branch its sibling had been told to review and the cross-review never happened. - Workers talk sideways with
to_role: "sibling"orto_worker, never by opening each other's CLI. - An agent id Orchemax does not know is refused, with the list of presets that do
exist — it no longer falls back to
agents.default_presetand runs a different CLI that reportsdone. Free-form roles go throughtask_assign+task_run. - Ledger gate. With
clarify_before_spawnon, the spawn is denied untilorch ledger checkpasses;force: true(orORCH_LEDGER_FORCE=1) overrides it. - Size
timeout_secto whether the task writes, not to how small it sounds. A real write — even "add one function" — means the agent reads the codebase, edits, then verifies (build/vet) before it exits: measured median 236s for cursor-agent on a one-line helper (R5-E2E item 103), so ≥480s (2×) is the floor for any write task. Reserve ≤180–300s for a genuinely read-only ask. The900above is for the real multi-file rewrite in this example. There is no default ceiling, so a Chair left to guess picks something much larger than the task needs.