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_item 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 with a fresh requestId 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 envelope also carries details, such as a gate's missing notes or the blockers of a dependency, and contendedItemId when another agent got there first.
{
  "error": {
    "kind": "transient",
    "code": "claim_contention",
    "message": "Item already claimed by another agent",
    "retryAfterMs": 420000,
    "contendedItemId": "550e8400-…"
  }
}

A requestId makes a write safe to resend

Write tools accept a requestId. The server remembers the response for that actor and id for about ten minutes and returns it again instead of running the call twice. claim_item requires one.

Same id or a fresh one

No response arrived, such as a timeout: resend with the same id. A response arrived, even a failure: use a fresh id, because the remembered failure would be replayed.

Schemas and notes never touch until the gate

Schema rules in config.yaml never stored in the database requires Gate check advance_item 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.