MCP Task Orchestrator · Field guidePlate 2 of 9

One call moves an item. The gate decides.

Every work item sits in one of five roles. Agents never edit status directly. They call advance with a trigger, and that call is where the server checks required notes.

The line an item travels

start skips review when the schema has no review-phase notes start start start queue notes work notes review notes queue work review terminal block · hold blocked resume returns the item to the role it was blocked from reopen: terminal back to queue, gates bypassed
Amber bars are gates: the notes named under each bar must be filled before start passes it. Two triggers are not drawn: complete jumps from queue, work or review straight to terminal and checks the required notes of every phase, and cancel jumps to terminal from any role that is not terminal, blocked included, with no check at all.

Try the gate

A simplified model of the server's rules for one item, using the server's own error wording. Fire triggers in any order and read what comes back. The highlighted station above follows along.

Login API

queue

type feature-task · no status label

Notes · tick to upsert

Server says

Every trigger

TriggerFromToGate
startqueue, work or reviewthe next role on the lineRequired notes of the current phase
completequeue, work or reviewterminalRequired notes of every phase. A blocked item must resume first.
block / holdany non-terminalblockedNone. Saves the previous role.
resumeblockedthe saved roleNone
cancelany non-terminalterminalNone. Sets the status label to cancelled.
reopenterminalqueueBypassed. A terminal parent goes back to work.

Roles are fixed, labels are yours

The role is what the server reasons about. Alongside it, each transition sets a status label: display text for people and dashboards. The five roles never change. The labels can be renamed per project.

TriggerDefault label
startin-progress
completedone
blockblocked
cancelcancelled, always
a cascadedone
resumethe label from before the block
reopencleared, always
status_labels:
  start: "working"
  complete: "finished"
  block: "on-hold"
  cascade: "auto-completed"

The label comes back on every transition result and on item queries. Filter and gate on the role. Show the label.

When a call fails

Every failure carries a kind that says whether retrying can help, and a code to branch on. An agent never has to parse the message text.

A call fails read error.kind transient Back off, then retry the same request A contended lease or claim, a busy database. Or pick another item. permanent Do not retry. Fix the request. Validation errors, not found, not authorized. shedding Wait retryAfterMs, then retry The server is over capacity. Poll less often if it persists.
The error also carries detail, such as a gate's missing notes or the blockers of a dependency, and a fix sentence for codes that define one. A claim_held error names the item and when the claim expires, never the holder.
{
  "ok": false,
  "error": {
    "code": "claim_held",
    "kind": "transient",
    "message": "...",
    "detail": { "itemId": "550e8400-...", "expiresAt": "2026-10-16T13:15:00Z", "retryAfterMs": 420000 },
    "retryAfterMs": 420000
  }
}

An idempotencyKey makes a write safe to resend

Each element of a write call may carry an idempotencyKey. The server records a committed element for 24 hours per principal and tool and returns its stored result again (replayed: true) instead of running it twice. The same key with a different element is idempotency_mismatch.

Same key on every retry

No response arrived, such as a timeout: resend with the same key. Only an element that committed is recorded, so an element that failed runs again when you retry with the same key.

Schemas and notes never touch until the gate

Schema rules in config.yaml never stored in the database requires Gate check advance provides Notes content written by agents stored with no schema reference
Changing a schema changes what the next transition demands. It never rewrites existing notes. An item that matches no schema advances freely.