Workers
The worker registry — one durable identity for anyone who can take Work, human or agent, with ownership, fenced readiness, and bid eligibility built in.
A Worker is anyone who can take Work — a person,
a team, a queue, an external system, or an AI agent. The worker registry is
where that identity becomes durable: a registration row with a stable
worker_id, an immutable binding to the thing it represents, a settlement
account, and the standing facts — status, readiness, capacity, capabilities —
that decide whether it may bid. This page is the operational guide to the
registry and the WorkerService API behind it
(Worker (WorkerRegistration)).
The registry is deliberately not a copy of anything. A worker is a projection over exactly one upstream subject, and that binding is fixed for the life of the worker:
- recipient
- A routing recipient projects into a worker directly — its live availability and capacity show through at read time, never copied.
- agent_definition
- An AI agent projects only once a caller pins an immutable definition — id, version, and content hash — so an agent worker's identity can never drift under an award.
- work_assignment_candidate
- A case-management candidate, projected with registry-owned readiness.
- human_principal
- A human identity from the auth plane, for workers that are people rather than routing recipients.
- external_system
- An external work system reached through a connector or bridge.
Five kinds of upstream subject, one registration shape, one eligibility answer the market consumes:
One worker per subject, enforced by the database: registering the same subject twice converges when the payload is identical and conflicts loudly when it is not. The subject columns are never touched by any update — immutability is a schema property, not a convention.
The registration record
Everything a worker carries, in one durable row:
Prop
Type
Registering an agent as a worker
An agent does not need an operator to pin a definition for it. The pin is derived from an agent preset the agent (or its owner) authors, and every preset read publishes the hash the registry will verify:
Author the preset. POST /api/v2/agent-presets with the model, provider,
instructions, and tools the agent runs under. Each update creates a new
immutable version.
Read the hash. GET /api/v2/agent-presets/{preset_id}/versions/{version} returns
definition_hash, the content hash of the definition this version derives
to. It is computed by the same code that later verifies the pin, so there is
nothing for the client to reproduce.
Register. POST /api/workers with kind: WORKER_KIND_AI_AGENT, a
subject of kind SUBJECT_KIND_AGENT_DEFINITION whose ref is the preset id,
and definition: { id: <preset id>, version, hash: <definition_hash> }. If
the registry holds no snapshot for that pin yet, it derives the definition
from the preset, checks the hash, and pins it.
A pin the registry cannot honour is refused with the reason in detail, never
a bare 500:
| Refusal | Status | detail names |
|---|---|---|
| Missing id, non-positive version, or a hash that is not 64 hex characters | 400 | the field: definition.id, definition.version or definition.hash |
| Preset or version does not exist in the tenant | 404 | agent preset "<id>@<version>" not found |
| Hash does not match what the preset derives to, or what is already pinned | 400 | definition.hash with both the expected and the requested hash |
The award retains the original source snapshot. A re-pin before launch voids
the award and releases its hold; it cannot silently substitute another agent.
During execution the governed runtime derives a separate content-addressed
definition from that source. Acceptance evidence and signed receipts retain
both references. A later re-pin or registration deletion cannot change a
queued receipt's worker pins. Use an award-bound AI_AGENT step as shown in
Clear AI work.
Payout account snapshots
A held award requires a nonempty settlement_account_ref. At commit, the server
trims and copies the account from the original hold command into the award in
the same transaction. Capture, release, and claw-back use that original account;
a later account rotation or registration deletion cannot redirect an existing
award. A new award uses its own committed account. Definition re-pin checks
still govern launch identity separately from this financial snapshot.
Ownership is server-derived
The registry never trusts a payload to say who owns a worker. The owning principal is captured from the authenticated caller at registration, and every mutation of an owned worker — update, status change, re-pin, readiness report — verifies the caller against it. A mismatch is refused with a uniform permission error that does not reveal whether the foreign worker exists. Ownerless workers (a recipient-backed queue, say) stay tenant-scoped.
This is the same check the market uses: when an agent submits a bid as
worker_id, the bid path verifies the caller owns that worker through the
registry before anything is priced. One ownership model, two enforcement
points, zero payload trust.
Readiness under a fence
Readiness is a moment-to-moment fact, and moment-to-moment facts arrive out of order. Registry-owned readiness is therefore reported under a monotonic fence: every report carries a strictly increasing number, and a report whose fence does not advance is refused with a typed conflict — visibly, never silently absorbed.
The failure this kills: an agent reports not ready (it is out of budget), then a delayed earlier report arrives claiming ready. Without fencing, the stale report wins and a down agent looks biddable. With fencing, the late arrival is refused and the caller knows it.
Recipient-backed workers skip all of this — their readiness is projected from the live recipient at read time. The registry never stores a copy that could go stale, and if the recipient subsystem is briefly unreachable, reads still succeed with the worker degraded to not ready with an explicit reason — fail-closed for bidding, never fabricated-ready.
Bid eligibility
CanBid is one question with a normalized answer. A worker may bid when it is
active, ready, within capacity, and — for an ai_agent — bound
to a pinned definition. Anything else is a refusal with a reason:
Status is the lifecycle gate in front of that question. Removal is reversible by design — there is no hard delete:
statusThe lifecycle gate. Disabled workers are out of the market entirely; paused workers are resumable.
ai_agentAn agent worker with no pinned definition has no stable identity to award against — refused until a definition is pinned.
readinessCarries the reported reason through — budget exhausted, runtime down, off-schedule, enrichment unavailable.
concurrencyCurrent load has reached the declared ceiling. Clears itself as work completes.
Nothing in this list is a silent drop. Every refusal reaches the caller — and the market's rejection records — as a normalized reason string.
The WorkerService API
Every RPC requires authorization, carries the tenant from the authenticated context (never the payload), and maps refusals to typed errors:
Prop
Type
The registry ships enabled by default behind the worker_registry config
gate. Disabling it removes the service cleanly — dependent surfaces fail
closed rather than half-working.
Where to go deeper
Worker
The primitive this registry makes durable.
Agent procurement
How a registered worker bids — typed terms, pinned identity, buyer-side clearing.
Pools & recipients
The recipient substrate recipient-backed workers project over.
Durable agent runtime
Budgets, delegation, and journaled state for ai_agent workers.
Pools & Recipients
Manage routing targets — pools (containers with a strategy and kill-switch) and recipients (concrete endpoints with capacity and state) — over the management API.
Rules
Manage routing rules — CEL expressions attached to a pool, with priority, enable/disable, validation, and the cross-instance cache invalidation that makes edits take effect live.