MCP tools for orchestration
The 17 gp_orch_* tools the built-in MCP server gives a coordinating session, how workers are dispatched and report back, and how gates become question cards.
- Topic
- Orchestration
- Available on
- Available onDesktopCLI Daemon
- Reviewed
- October 12, 2026
On this page
Any session can coordinate a run from the inside. The built-in MCP server exposes seventeen gp_orch_* tools that read and write the private orchestration store, alongside the session tools that actually start workers and the inbox tools that deliver their reports. This page is the reference for that surface.
The tools are advertised to both human-initiated and assistant-attached sessions. None of them shows an approval card. The reads change nothing; the writes change the private store on this host plus two things that hang off it: creating, resolving, or withdrawing a gate — and closing or resetting the run that holds it — also creates, answers, or cancels the matching question card in the coordinator’s transcript, and every settlement writes records to the coordinator’s inbox. Nothing here runs a command, edits a file, or launches a process. Starting a worker is different, because it launches a session; see Dispatching a worker.
Runs
gp_orch_run_create— create a run owned by the calling session. Required:objective. Optional:auto_close(default false) and an initialtasksarray where each entry has atitleand optionally akey, aspec, anddepends_on_keysnaming other initial tasks by key. Readiness is derived; start workers only for tasks whose state isready.gp_orch_run_list— runs visible to this session, with derived readiness and dispatch attempts. Optionalinclude_closed.gp_orch_run_show— one run (run_id) with its tasks, derived states, dispatches, and gates.gp_orch_run_close— close a run (run_id, optionalreason). The stored status becomescompletedwhen every task completed,failedwhen every task is terminal and at least one failed, otherwisecancelled. Open gates are withdrawn. Child sessions are not stopped.gp_orch_run_reset— reset tasks (run_id, optionaltask_ids). Selected tasks return to pending, their active dispatches are superseded, and their open gates are withdrawn; the run reopens. Withouttask_ids, every pending, dispatched, or failed task is reset. Completed and cancelled tasks are refused. Child sessions are not stopped.
Tasks and dependencies
gp_orch_task_create— add a task (run_id,title; optionalkey,spec, anddepends_onas task UUIDs). Returns the task and its derived state.gp_orch_task_update— changetitle,spec,status, orresultontask_id. Fields you omit are left alone.statusaccepts onlypendingorcancelled; everything else is set by dispatch settlement.gp_orch_task_list— a run’s tasks (run_id) and derived states, optionally filtered bystate(ready,blocked,dispatched,completed,failed,cancelled).gp_orch_task_show— one task (task_id) with its derived state, including the tasks and gates blocking it.gp_orch_dep_add— add an edge:task_iddepends ondepends_on_task_id. Both must be in the same run, and an edge that would close a cycle is refused.gp_orch_dep_remove— remove that edge.
Private tasks are separate from board tasks. The board tools (gp_list_tasks, gp_create_task, and the rest) never see them, and a private task id is not accepted where a board task id is expected.
Dispatches
gp_orch_dispatch_list— attempts selected by exactly one ofrun_id,task_id, orchild_work_item_id. Passing none or more than one is refused.gp_orch_dispatch_show— one attempt (dispatch_id) with its settlement outcome.
A dispatch id is the opaque attempt id of the worker session. Each row carries the task, the child session and its host when placed remotely, the attempt number and the attempt it retried, the stored status (dispatched, completed, failed, superseded, cancelled), the last status the worker reported, and, for a current local attempt, the engine-derived liveness of the child.
Gates
gp_orch_gate_create— attach a question totask_id:question, optionaloptions(each with alabel, optionalvalue, optionaldescription),allow_freeform(default false),header, anddefer_until_dependencies_settle(default false; see How a gate becomes a question card). The task is blocked while the gate is open.gp_orch_gate_resolve— answer a gate (gate_id,resolution) through the same durable path an answered question card uses.gp_orch_gate_withdraw— withdraw an open gate (gate_id, optionalreason) and cancel its question card. The task is no longer blocked by it.gp_orch_gate_list— gates selected by exactly one ofrun_idortask_id, optionally filtered bystatus(open,resolved,withdrawn). An open gate whose question is still held readsdeferred: true.
How a gate becomes a question card
When the run is owned by a session, creating a gate emits a pending question on that coordinator session: the same kind of card you see when an agent asks you something, pinned to the top of the transcript with the options you supplied. The coordinator’s status does not change; the session keeps running, and the only thing that changes is the derived readiness of the gated task.
Answering the card, or calling gp_orch_gate_resolve, resolves the gate with that answer, records who answered, unblocks the task if nothing else blocks it, and writes a gate_resolved record to the coordinator’s inbox. If that resolution makes the task ready, a task_ready record follows. Closing or resetting the run withdraws its open gates and cancels their cards, and the engine re-issues cards for still-open gates when it starts up.
Runs owned by an operator have no coordinator session, so their gates never produce a card. Resolve those from the CLI or with gp_orch_gate_resolve.
A coordinator that plans its checkpoints up front can create each gate with defer_until_dependencies_settle: true. The gate blocks its task straight away, but its question card is held until every task the gated task depends on has completed, so you are asked about phase 3 only once phase 3 is next. While it is held, the gate reads deferred: true in gp_orch_gate_list and gp_orch_run_show, and the Plan tab shows it as an upcoming decision rather than a decision waiting on you.
- A task whose dependencies have already completed, or that has none, asks at once.
- Gates on the same task surface together.
- When a dependency fails or is cancelled, the question stays held; the run reports that it is stuck as usual. Retrying the dependency to completion, or removing that dependency with
gp_orch_dep_remove, lets the question through. - You can resolve or withdraw a deferred gate at any time. Closing or resetting the run withdraws it like any open gate.
Dispatching a worker
There is no gp_orch_* tool for starting a worker. Prefer gp_spawn_subagent for an inline child on the calling session’s host. Both human-initiated and assistant-attached sessions can use it, and spawning is auto-approved. The child still has its own questions and permission requests.
Starting an inline worker
gp_spawn_subagent requires prompt. To dispatch a private-run task, pass run_id and task_id at the top level for either kind of caller:
{
"prompt": "Implement the parser and run its unit tests. Report the result to your parent.",
"run_id": "<run UUID>",
"task_id": "<ready task UUID>"
}
Omit run_id and task_id for delegated work that is not part of a private run. The parent supplies the default agent and project. A regular child keeps the parent’s working directory within that project; choosing another project defaults to that project’s directory. Assistant project workers default to their project’s directory. An explicit working_directory overrides the directory default. Regular callers can request a fresh worktree with auto_worktree.
When the child uses the same agent, its harness settings inherit from the parent unless overridden. Omit permission_mode to inherit: this auto-approved path only accepts an explicit mode when it repeats the same agent’s inherited mode. Choosing a different mode requires the approved full-session tools or the child’s human-operated controls. Switching agents does not automatically inherit a bypass mode.
The assistant delegation ladder still applies, and project_work sessions cannot spawn children. A regular session’s session_work child can spawn its own session_work children; the engine sets no nesting-depth limit for regular trees, but each child reports only to its immediate parent, so every level supervises its own workers. gp_spawn_subagent requires a session caller; it is not an operator-only CLI entry point.
The result identifies the child by both work_item_id and session_id, which are the same value. session_id is the name the session tools (gp_get_session_status, gp_get_session_events, gp_steer_session, gp_send_session_message, gp_stop_session) use. A plain inline spawn returns once the child exists and starts its first turn in the background; a retry or a private-run dispatch starts it before returning.
Subagents appear as collapsible cards in the parent’s transcript on desktop, portal, and mobile. They run on the parent’s host even when you view the parent remotely. Omit host_id or use that host’s own id; another host is refused with remote_subagent_not_supported. See Inline subagents and remote viewing.
Starting a full session
Use a full-session tool when the worker needs its own workspace tab or must run on another host. Both tools require approval and accept host_id for cross-host placement:
- Assistant-attached sessions call
gp_start_sessionwith adelegationblock. Addrun_idandtask_idto that block. The delegation ladder still applies: amain_assistantmay only spawn anassistant_task, anassistant_taskmay only spawnproject_work, andproject_workrequires aproject_id. Each call is approved by you. - Human-initiated sessions call
gp_create_sessionwithrun_idandtask_idat the top level. A fresh session needs aproject_id; the call is approved by you. A worker needs aprompt, because a session created without one is not started.
The engine checks the task before the session exists: it must belong to the run, its derived state must be ready, and it must have no active dispatch. Otherwise the call fails with a conflict such as task_not_ready, task_already_dispatched, or run_closed, and nothing is launched. On success the task becomes dispatched and a dispatch row records the attempt.
Retrying uses the session creation tools, including gp_spawn_subagent, with retry_of_session_id (and optionally retry_stop_prior). The retry inherits the run and task and creates a new attempt that supersedes the prior one. Cross-host retry is not available.
When a retry’s replacement does not start
The prior attempt is superseded before the replacement starts, so a replacement that fails to start cannot hand the work back to the prior. Instead, the call fails with retry_start_failed (HTTP 502) and keeps the replacement as a failed attempt. The error’s details carry replacement_session_id, attempt_id, and prior_session_id, and retry_of_session_id names the session to retry from next: the replacement. Retrying from the superseded prior is refused as already superseded.
In a private run, the replacement’s dispatch is cancelled with the reason spawn_failed and its task returns to pending without failing, so the run stays open and nothing downstream is marked unresolvable. That cancelled attempt remains the task’s retry anchor until another dispatch for the task is reserved, so retry_of_session_id set to the replacement continues the lineage with the next attempt number.
If no attempt can serve as the anchor, for example because the run has closed, call gp_orch_run_reset with the task in task_ids. That returns the task to pending and reopens the run. Then start a fresh worker with gp_spawn_subagent, passing the task’s run_id and task_id.
A worker for an operator-owned run must be started on the local host. Asking for another host is refused with operator_run_remote_unsupported.
How workers report
Workers do not need to know they are part of a run. They report the way every delegated child reports, with gp_set_delegation_status: running for progress, awaiting_parent when they need a decision, and completed or failed with a summary when they are done. Terminal statuses are sticky, an identical repeat is a no-op, and a report from a superseded attempt cannot complete the replacement. When a finished worker gets a follow-up message and does more work, it reports that round with follow_up: true: the coordinator receives a new inbox record tagged follow_up with a follow_up_seq, and the original terminal report and the task’s outcome stay unchanged. A follow-up to a coordinator on another host is delivered through the same durable outbox as other reports; a coordinator host too old to file follow-ups refuses it, and the worker’s host drops it instead of retrying.
The engine turns those reports into orchestration state. A terminal report settles the dispatch, sets the task to completed or failed, and recomputes readiness for everything downstream. A worker that exits without reporting has a terminal report synthesized by the engine from its lifecycle state: a session that ended stopped or interrupted becomes abandoned, and any other exit becomes failed. The coordinator never has to guess.
The coordinator reads the results from its durable inbox:
gp_check_inbox— returns unacknowledged records. Optionalwait_ms(up to 25000) long-polls for the next one,limitcaps the batch (up to 50),ack_record_idsacknowledges exact records first, andkindsfilters by exact kind name. Known kinds includetask_ready,gate_resolved,dag_stuck,worker_done,status,stalled,escalation, andquestion; unknown names are accepted so future kinds do not break a filter.gp_ack_inbox— acknowledge exactrecord_idsafter processing them.
Every record carries a common envelope: its id, sequence, kind, a status, an optional summary, and the run, task, gate, or dispatch id it concerns when the kind is orchestration-scoped. Worker-originated kinds (status, worker_done, stalled) also identify the child session, the attempt id and number, whether that attempt was superseded, and the report sequence. Run-scoped kinds do not: a task_ready record, for example, carries no child session or attempt, only the run and task it announces. Acknowledge only after acting on a record; anything unacknowledged is returned again. A running report never wakes an assistant coordinator on its own.
Refusals you may see
task_not_ready,task_already_dispatched,task_terminal,run_closed— the store’s readiness and lifecycle rules, returned as conflicts.dependency_cycle,dependency_limit,task_limit,gate_limit,run_limit— a cycle, more than 50 dependencies on one task, more than 200 tasks in a run, more than 10 open gates on one task, or more than 20 open runs for one coordinator.gate_not_open— resolving or withdrawing a gate that is already resolved or withdrawn.forbidden— a session touching a run it neither coordinates nor works on.invalid_request— a nil id, a selector that is missing or doubled, text over 4096 bytes, orrun_idwithouttask_idon a session start.remote_subagent_not_supported—gp_spawn_subagentaimed at another host; use a full-session tool for cross-host work.subagent_permission_mode_requires_approval— an inline spawn tried to select a different permission mode.operator_run_remote_unsupported— a worker for an operator-owned run aimed at another host.retry_start_failed— a retry created its replacement but the replacement did not start; retry fromdetails.replacement_session_id. See When a retry’s replacement does not start.dispatch_not_active— a retry named an attempt that is no longer the task’s current or anchor attempt.session_busy—gp_send_session_messagereached a session that is starting, running, or waiting on a prompt. Nothing is queued. Steer the turn in flight withgp_steer_session, or wait for the session to be ready and send again.