MCP Task Orchestrator · Field guidePlate 6 of 9

Who does what inside a phase

A phase is often several jobs: plan, build, test, record. Seats name those jobs in config. The orchestrator learns which agent to send, the gate reports missing notes by owner, and the server can check that the tests and the code were written by different actors.

The seats of a bug fix

This project's own bug-fix schema with its default traits. Select a seat to see what the server serves for it.

queue work review after after planner diagnosis test-plan implementer enters the phase implementation-notes test-author added by a trait test-manifest orchestrator the main session session-tracking Arrows are after hints: an order the orchestrator follows. The server serves them and does not enforce them. reviewer review-checklist test-independence-audit
Each box is a seat with the required notes it owns. Amber bars are the phase gates from plate 2. The gate checks the notes of every seat in the phase it guards.

implementer

Phase
Enters phase
Works after
Told not to read
Owns notes
Declared by
Dispatch
Apply a per-item trait to this item:

What a seat declares

work_item_schemas:
  bug-fix:
    default_traits: [delegated, needs-test-author]
    seats:
      - { name: planner,      phase: queue }
      - { name: implementer,  phase: work, enters: true }
      - { name: orchestrator, phase: work, after: [implementer] }
      - { name: reviewer,     phase: review }
    notes:
      - { key: implementation-notes, role: work,
          required: true, seat: implementer }

traits:
  needs-test-author:
    seats:
      - { name: test-author, phase: work,
          after: [implementer],
          reads_exclude: [implementation-notes] }
    notes:
      - { key: test-manifest, role: work, required: true,
          seat: test-author,
          independent_of: [implementer] }
  delegated:
    dispatch:
      work:
        agent: task-orchestrator:implementer
        seats:
          implementer: { model: sonnet }
          test-author: { agent: null, model: sonnet }
FieldMeaningServer's part
name, phaseA named role in queue, work or review. The name means nothing to the server.Validates and serves
entersThis seat makes the transition into the phase.Allows one per phase
afterSeats whose work this one follows.Serves as a hint
reads_excludeNote keys this seat should not read. Keeps a test author blind to the implementation.Serves as a hint
note seatThe seat that owns a note.Groups missing notes by owner
note independent_ofSeats whose author must differ from this note's author.Checks at the gate
dispatch.<phase>.seatsAgent, model and effort for one seat. null clears a field inherited from the phase.Resolves and serves

The YAML is abridged from this project's config, and its independent_of line follows the reference example in the config documentation. A config with no seats anywhere is unaffected: every seat field is left out of every response.

The gate answers by owner

Without seats

"missingNotes": [
  { "key": "implementation-notes", … },
  { "key": "test-manifest", … },
  { "key": "session-tracking", … }
]

A flat list. The orchestrator has to know, from somewhere outside the config, whose job each note is.

With seats

"missingNotes": [ … ],
"missingBySeat": {
  "implementer":  ["implementation-notes"],
  "test-author":  ["test-manifest"],
  "orchestrator": ["session-tracking"]
}

The same failure, routed. A required note that no seat owns is listed under unowned, last.

Independence is the one thing the server checks

When a note declares independent_of, the gate compares the actor who wrote it with the actors who wrote the named seat's notes. Here the implementer's note was written by impl-agent-1, and test-manifest declares independent_of: [implementer].

independence.mode


    

Self-reported unless verified

The actor is whatever string the caller sent. Pair the check with actor authentication and require_verified: true to compare proven identities.

Last writer wins

Re-upserting a note replaces its actor. No history is kept, so the plugin's orchestrator never rewrites a note a seat owns.

The waiver is self-service

Whoever writes the note can add the waiver line. Treat reject as a discipline aid for cooperating agents. It is not a security control.

A bug fix, seat by seat

How the Claude Code plugin's four agent definitions (planner, implementer, test author, reviewer) and the main session take these seats.

  1. planner · queueWrites diagnosis and test-plan. The expected results for the tests are fixed before any code exists.
  2. implementer · enters workCalls advance_item(start). The queue gate checks the planner's notes. Then it writes the fix and its note.
  3. test-author · workWrites tests from the test plan without reading the implementer's note. Fills test-manifest.
  4. orchestrator · workFills session-tracking and advances the item. The work gate checks all three seats' notes.
  5. reviewer · reviewFills review-checklist and test-independence-audit.
  6. orchestratorAdvances the item to terminal. The review gate checks the reviewer's notes.

Only the entry seat calls advance_item. Every other seat fills its own notes and returns, and the orchestrator owns each later transition. For several items at once, the run-wave skill builds these stages from each item's seats.

How seats combine, and what fails the load

Traits add seats, they never redefine one

A trait seat whose name already exists on the schema is dropped with a warning. Across traits, the first to declare a name keeps it.

Dispatch resolves the other way round

For a seat's agent, model and effort, per-item traits are read before default traits. That is how one item can raise its implementer to a stronger model, as the trait toggles above show.

A late second entry seat is demoted

If merging traits at resolve time yields two entry seats in one phase, the first keeps the role and the later one is served with enters: false.

In one config documentResult
Two seats with enters: true in the same phaseThe load fails. A global config stops server startup. A per-project push is rejected and nothing is stored.
Two seats with the same name
A seat named unowned
A cycle in after
A required note with no seat, in a schema that has seatsA warning. The note is served under unowned.
A malformed seat entry or dispatch overrideA warning. That entry is skipped.