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 orch 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, log, status: "running", note}.
Pass wait: true to block until the worker exits instead; that reply adds exit
and verification (the worker's own half — tests[], symbols[], criteria[],
summary from verify_report — plus orch's observed half — guardrails,
files[]). msg_send returns {message, delivery}.
Gotchas#
- The preset id is
cursor, notcursor-agent.cursor-agentis the binary behind it; orch'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 orch 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.- Workers talk sideways with
to_role: "sibling"orto_worker, never by opening each other's CLI. - Ledger gate. With
clarify_before_spawnon, the spawn is denied untilorch ledger checkpasses;force: true(orORCH_LEDGER_FORCE=1) overrides it.