Roles

The running jobjob_7Hq2 · waiting · on approval · $49.00 held

Who may do or sign a step, where, and apart from whom. A role names a credential expression, the region its act needs, what the act pays, and the members it must differ from.

A role answers one question: who may do or sign this step, where, and apart from whom?

One role, and the step it signs. by names the role:

Run
cat services/translation.ts
magic values: none
  roles: { translator: { credential: 'sworn translator' } },
  deliver: {
    translate: 'ai',
    harden: { review: 'adversarial', lenses: ['meaning', 'terms'] },
    sign: { by: 'translator', stamp: true },

The rules table decides what the act needs, and the role says who holds it. check reads both back:

Run
npx services.dev check
magic values: none
  who     A translator signs every document before delivery. (rules 2026-10)
  roles   translator · sworn translator · your staff
  steps   translate · ai → harden · ai · adversarial · 2 lenses → sign · translator · * · stamped
  bounds  reserved sign to sworn translator

A role with no pool is your staff, working from the owner console. A role with a pool is filled from your marketplace. A role whose credential doesn't meet the row fails reserved_act_unstaffed, and the fix is the role's one line:

Run
git add -A && git diff --staged
magic values: none
diff --git a/services/translation.ts b/services/translation.ts
index 0585d1f..d9dc9a6 100644
--- a/services/translation.ts
+++ b/services/translation.ts
@@ -6,7 +6,7 @@ export default Service({
   input: { document: 'file', to: 'language: a BCP 47 tag, such as fr-CA' },
   output: { document: 'file' },
   rules,
-  roles: { translator: { credential: 'translator' } },
+  roles: { translator: { credential: 'sworn translator' } },
   deliver: {
     translate: 'ai',
     harden: { review: 'adversarial', lenses: ['meaning', 'terms'] },

A translator holds either of two credentials. A reviewer holds all of one and any of two others, and reviews the translator, so the same member can never do both:

Run
cat services/reviewed-translation.ts
magic values: none
import { Service } from 'services.dev'
import rules from '../rules.ts'

// Credential expressions and separation, read aloud: a translator holds either credential, the reviewer
// holds all of one and any of two, reviews the translator, and so is never the member who translated.
export default Service({
  name: 'Reviewed Translation',
  description: 'Translated by one person, signed by another.',
  input: { document: 'file', to: 'language: such as fr', country: 'jurisdiction: such as FR' },
  output: { document: 'file' },
  rules,
  roles: {
    translator: { credential: ['sworn translator', 'certified translator'], where: 'country' },
    reviewer: { credential: { all: ['sworn translator'], any: ['court interpreter', 'notary'] }, where: 'country', reviews: 'translator', pay: 40 },
  },
  deliver: {
    draft: 'ai',
    translate: { by: 'translator', checklist: ['every page is translated', 'the terms match the glossary'] },
    harden: { review: 'adversarial', lenses: ['meaning', 'terms'] },
    sign: { by: 'reviewer', stamp: true },
Run
npx services.dev check
magic values: none
  who     A sworn translator or certified translator in the job's country does the translate step. A reviewer in the job's country signs every document before delivery. (rules 2026-10)
  roles   translator · sworn translator or certified translator · country · your staff
          reviewer · sworn translator, and court interpreter or notary · country · your staff · $40 an act · reviews translator, so never the member who did it
  steps   draft · ai → translate · translator · country · 2-item checklist → harden · ai · adversarial · 2 lenses → sign · reviewer · country · stamped
  ledger  +$149.00 · AI $1.26 (example) · reviewer $40.00 · you $107.74

Each role gets its own Tasks and its own pay. Every Service that names the same Pool role draws on the same members.

Some work stays with the person who starts it, as a negotiation stays with the closer who wrote the proposal. span names the steps one Task holds. Once a step of the span is the role's, its Task holds every step after it in the span. The member who claims it keeps them all, and the last step's commit fulfills it. A step of the span that comes back after a revival is that member's alone for revive.first_call, then posts again.

talk says how the member reaches the party outside the thread: as the client whose matter it is, even when someone else ordered for them, with mail from the client's domain and calls bridged through the job. The party deals with the buyer alone, no address or number crosses, and every touch lands on the job's thread.

The Deal Service holds a closer for four steps, from the meeting to the close:

Run
cat services/deal.ts
magic values: none
    closer: { pool: closers, span: ['meet', 'propose', 'negotiate', 'close'], revive: { first_call: '24h' },
      pay: { share: '10%', of: 'closed_value', on: 'won', from: 'buyer' },
      talk: { as: 'client', mail: 'client_domain', calls: 'bridged' } },

Worked in: the Deal Service, three roles on one deal.

KeyWhat it saysDefault
credentialWhat a member holds: one credential, any of a list, or { all, any }the Pool role's
whereThe region the act needs: a jurisdiction input, '*' for any admission, or your functionthe rules row's where
poolA Pool you write and import, '<door>/<pool>' for a Pool another operator exports, at the terms its door pins, or 'buyer' for the buyer's own professionalsyour staff
payWhat the act earns, fixed when its Task posts: dollars, { usd, on } at the act, a later step's guard ('meet.held') or an end, or { share, of, on }. Pay says when it is the member'snothing
pay.railWho sells the fee: 'brand', 'member' or 'entity'the row's rail
pay.fromOut of the price, or charged on top: 'price' or 'buyer''price'
pay.killWhat a share role accrues, in dollars, when the buyer withdraws after the claimnone on a share
spanThe steps one Task holds, in order: the member who claims it keeps each one, and the last one's commit fulfills itthe one step
revive{ first_call: Within }: a step of the span that returns after a revival is the same member's alone for that longnone: it posts again
talk{ as: 'client' | 'buyer' | 'brand'; mail?: 'client_domain' | 'buyer_domain' | 'brand_domain'; calls?: 'bridged' }: how the member reaches the party outside the thread, each touch on itthe thread alone; as alone, 'client'
coverageInsurance in force per act, in dollarsthe Pool's
reviewsThis role signs what that role prepares, so never the same membernone
with{ differ, same }: never the member who did one role, always the one who did anothernone
dispatchHow its Tasks reach members: 'feed', 'cascade', 'pick' or 'direct'the Pool's

Each credential's scope, one admission everywhere or per region, is declared once, in the Pool's scopes. Where an act happens has where.

Two more sources fill a role beside a Pool's members:

KeyWhoHow it reaches the record
Pool.firms: truea firm enrolls a bench of its own memberseach member joins and is verified like any other; the firm's conflicts ledger joins each member's check, and the fill ladder's firms rung opens a Task to firms
Pool.invite_by_buyer: truea buyer invites their own professionalthe invited professional joins the Pool through /join and the verifier, and is offered that buyer's Tasks by direct
pool: 'buyer'the buyer's own professionals, named on the orderthe Task goes only to them, and eligibility still holds every one to the rules row

A firm or an invited professional never skips verification, eligibility or the member charter.

SurfaceWhat a role adds
APIIts Task routes, GET /tasks to POST /tasks/:id/attest, for its members' own sessions
CLItasks list to tasks attest <task>, in a member's session
MCPnever: a person acts
SDKnever: a person acts
SiteThe Service page names who signs
Docsllms.txt names who signs
AppThe delivery portal, at /<pool>, or the owner console for your staff
Call
→ GET /llms.txt
magic values: none
A contract flagged, then advised on. $99 per matter, within 48 hours, charged on acceptance. An attorney signs at advise, stamped. The client consents first.
CodeWhen
reserved_act_unstaffedcheck: a step performs a reserved act, and no role on it holds the credential
rail_conflictcheck: pay.rail contradicts the row's rail
ineligibleA member who fails a predicate, separation included, claims a Task. The answer names the cure
reservedA person without the credential attests a reserved act
Run
npx services.dev check
magic values: none
  roles   attorney · bar admission · from attorneys · $50 an act
  roles   practitioner · patent attorney or agent · * · from attorneys · $150 an act
  • Legal. A practitioner from the attorneys Pool signs and files patents anywhere; an attorney signs where the client is admitted. The attorneys' Pool.
  • Tax. A preparer signs the return, and the taxpayer authorizes it. The tax example.
  • Sales. A closer closes, under a guard on the floor the client set. Its roles hold no credential.