MCP Task Orchestrator · Field guidePlate 4 of 9
A schema says which notes an item type must carry at each phase. Traits add cross-cutting requirements to any type. Both live in .taskorchestrator/config.yaml, so changing the process never means changing code or prompts.
The item
type: feature-task traits: needs-migration-review
Its schema
work_item_schemas:
feature-task:
default_traits: [needs-security-review]
notes:
- { key: requirements, role: queue, required: true }
- { key: implementation-notes, role: work, required: true }Traits
traits:
needs-security-review:
notes:
- { key: security-assessment, role: review,
required: true, skill: security-review }
needs-migration-review:
notes:
- { key: migration-assessment, role: queue,
required: true, skill: migration-review }Resolved schema for this item
migration-review skill.The item's type selects a schema. With no type match, its first matching tag does. Failing both, the default schema applies. With no default, the item advances freely.
A schema's default_traits apply to every item of the type. Traits set on a single item layer on after. The first trait to declare a key keeps it.
A trait note whose key already exists in the base schema is dropped. A trait cannot make a required note optional or move it to another phase.
Traits are orchestration signals. Note requirements are only the first of them.
Which notes must exist, in which phase. Enforced at the gate.
notes:
- key: migration-assessment
role: queue
required: trueHow to write the note. Handed to the agent at the moment it is about to fill it.
guidance: "Cover table recreation and data migration strategy."
Names a skill to run first, so the note follows a defined evaluation framework.
skill: "migration-review"
Shared resources the item needs. An exclusive one is leased when the item enters work, and a second item's start is rejected until it frees.
resources:
- staging-db
- key: deploy-token
mode: advisoryWhich agent, model and effort should pick up each phase. Returned to the orchestrator with the transition.
dispatch:
review:
agent: reviewer
effort: highNamed roles inside a phase. A trait can add a seat to any type it is applied to. See the next figure.
seats:
- name: test-author
phase: workA note is what the next agent reads in place of the whole conversation, so its value depends on staying small. A schema can cap each note, and the server can warn or refuse when a body runs over.
note_limits:
mode: reject # warn (default) | reject
work_item_schemas:
bug-fix:
notes:
- key: diagnosis
role: queue
required: true
maxLength: 6000 # characters
maxLength is a backstop on one note. Guidance text usually names a much smaller target.
In warn mode an over-long note is stored with a warning on the result. In reject mode that note fails with NOTE_BODY_TOO_LONG and the rest of the batch is still written. A project can set its own mode.
For test output, diffs and logs, an agent passes bodyFromFile and the server reads the file itself. The text never passes through the model's context.
A phase is often more than one agent's job. A schema or trait can name the seats inside each phase: which seat enters the phase, which seat owns each required note, and in what order they work.
bug-fix schema with the needs-test-author trait. The independent_of bracket follows the reference example in the config documentation.The server serves seats to the orchestrator as signals, reports missing notes grouped by the seat that owns them, and can check that an independent_of note was written by a different actor. Plate 6 covers seats in full.
A config with no seats anywhere behaves exactly as before. Seats are optional at every level.
Some work needs something only one item can use at a time: a staging slot, a test database, a deploy window. A trait can declare that resource, and the server holds a lease on it for as long as the item is in work. There is no acquire or release call. The lease rides on advance_item.
resources: # optional registry
staging-db:
description: "Shared staging database"
defaultTtlSeconds: 1800
traits:
needs-staging:
resources:
- staging-db # exclusive by default
- key: deploy-token
mode: advisory # recorded, never locked
exclusive admits one item at a time. advisory takes no lock and only records that the item used the resource. Reserve exclusive for things that cannot be shared. A credential several agents can use at once should be advisory.
Taken on start or resume into work. Released on any exit: complete, cancel, block or reopen. It expires after an hour by default (24 hours at most) and cannot be renewed. Nothing sweeps an expired lease. The next contender simply gets it.
Put exclusive resources on leaf task types. A feature container can sit in work for days and would hold the lock the whole time.
Keys are server-wide, so on a clash the global registry entry beats a project's. This is the one place the global layer wins. Prefix keys per project to avoid accidents.
The REST API lists active leases and their history, and an admin can force-release one. RESOURCE_LEASES_ENFORCED=false switches acquisition off.
There is no queue and no fairness: whoever retries first after release gets the lease. A lease is checked on entry to work only. It is a coordination aid for cooperating agents.
config-sync hook pushes it at session start and whenever it changes, and the server rejects a push from a stale checkout. A solo developer gets this too: one persistent server serves every repository with its own rules.schema_resolution modedefaultdefault