One Pool, several brands

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

Share one Pool across your brands, import a Pool another operator runs at terms pinned to a version, or export yours so other brands draw on it and pay you placement.

Sharing answers one question: whose people does a role draw on, and who runs their market?

A role names a Pool. The Pool can be one you write and several of your brands import, one another operator runs, or yours, opened to other brands. Each is a source in where a Pool's members come from, with its plan and its placement line.

Write the Pool once, in a package each brand imports:

Run
cat pools/translators.ts   # in @lingua/pools, the package lingua and captions both import
magic values: none
import { Pool } from 'services.dev'

// One Pool for two brands. A member joins once on the door, is verified once, keeps one conflicts ledger
// and one track record, and sees every brand's Tasks in one feed, each named for the brand that posted it.
// Each brand's Services set their own pay.
export const translators = Pool({
  name: 'translators',
  door: 'join.lingua.example',
  roles: { translator: { credential: 'sworn translator' }, subtitler: { credential: 'sworn translator' } },
  join: { name: 'text: your name as sworn', credential: ['sworn translator'], languages: 'language[]' },
  verify: 'https://verify.example.test/translators',
})

A second brand's Service names it like any Pool, at its own pay:

Run
cat services/subtitles.ts   # in captions
magic values: none
import { translators } from '@lingua/pools'
  roles: { subtitler: { pool: translators, pay: 20 } },
Run
npx services.dev check   # in captions
magic values: none
  roles   subtitler · sworn translator · from translators, shared with lingua · $20 an act
  pool    translators · on join.lingua.example · one roster, one queue for lingua and captions
  ledger  +$59.00 · AI $1.10 (example) · subtitler $20.00 · you $37.90
Shared by every brandSet by each brand, in its Services
the roster, each member's verification and its freshnessthe pay of each role
each member's conflicts ledger, checked the same way on every brand's Tasksthe rules rows that reserve each act
one track record across every Pool on a shared door, and each Pool's own tiersthe words its Services speak
one payout account, and one payout with a line per brandeach price, and how each Service earns
the door, its terms and its boardwhich steps post Tasks
one feed in one order for every brand, where each Task names the brand that posted it

A shared Pool serves on its door, so a member signs in once for every brand.

Name the Pool by its door and its name. You write no Pool file, recruit no one and run no verifier. Roles has the pool form:

Run
cat services/translation.ts   # a brand with no Pool of its own
magic values: none
  roles: { translator: { pool: 'gigs.expert/translators', pay: 30 } },
Run
npx services.dev check
magic values: none
  roles   translator · sworn translator · from gigs.expert/translators, imported · $30 an act
  import  gigs.expert runs its roster, verification, dispatch, fill ladder and payouts
  terms   gigs.expert/translators@2026-10 · placement $6.00 · min pay $25 · 30 days' notice before a change
          your rules row still binds: only a member who holds sworn translator in the job's region is offered the Task
  ledger  +$89.00 · AI $0.84 (example) · translator $30.00 · placement $6.00 to gigs.expert · you $52.16

An import pins the exporter's terms at a version. A change takes effect only after the exporter's notice, 30 days unless it sets one, and each Task finishes on the terms it posted under. A role that pays below the exporter's minimum for it is refused with pay_below_floor.

The Pool's operatorYour brand
Roster, verification, conflicts ledgersruns themnever reads them
Track records and tierskeeps them, each the member's ownreads the acts on its own jobs
Dispatch, the fill ladder, payoutssets and runs them, in one feed order for every importerfunds the raises on its own Tasks
Eligibilitythe Pool's own predicatesits rules rows: a member must hold the credential in the region each row names
Paysets nothing; publishes its minimum per rolepay per role, at or above that minimum, and members' own minimum fees still filter what they are offered
Placementearns itpays it, per filled Task

Placement is the operator's flat line on each Task its Pool or its door fills. It accrues when the gate accepts the member's completing act, beside the member's pay, and moves on the Pool's payout schedule:

Call
→ GET /owner/jobs/job_7Hq2/ledger   # the importing brand, after the member signed
200 · job_7Hq2 · charged · magic values: none
  +$89.00   charge            buyer → lingua           released on delivery
  −$0.84    AI                lingua's model key
  −$30.00   translator        lingua → mbr_7Hq2        accrued at the act · paid on gigs.expert's schedule
  −$6.00    placement         lingua → gigs.expert     accrued at the act · tsk_7Hq2 filled
  =$52.16   you

A Task no one fills, a timeout, a cancel, a pass or a refusal accrues none. Placement never comes out of the member's fee, and services.dev's take never applies to it, so each dollar carries one claim. The owner console sets what you pay against a door of your own:

Call
→ GET /owner/console/placement   # the importing brand's console card
200 · placement · last 30 days · magic values: none
  placement  $408.00 paid to gigs.expert in 30 days · 68 Tasks
  own door   your own door on Team breaks even at — Tasks a month · npx services.dev check --fit team

One key opens your Pool to other brands, at the placement you set, the minimum pay per role you accept, and the notice you give before a change:

Run
git diff pools/translators.ts   # the operator who runs the Pool
magic values: none
   verify: 'https://verify.example.test/translators',
+  export: { placement: 6, to: '*', min_pay: { translator: 25, subtitler: 18 }, notice: '30d' },
 })
Run
npx services.dev check pools/translators.ts
magic values: none
pools/translators.ts · 10 lines · translators · 2 roles: translator, subtitler · joins in 2 steps on join.lingua.example · feed · hold 24h
  export  any brand may import translators as join.lingua.example/translators · placement $6.00 a filled Task, to you
  terms   join.lingua.example/translators@2026-10 · placement $6.00 · min pay $25 translator, $18 subtitler · 30 days' notice
  feed    one order for your Tasks and every importer's · no export.first, so no brand goes first
          an importer's rules rows bind its own Tasks · it never reads the roster, a conflicts ledger or another brand's Tasks

Each importer's rules rows bind its own Tasks. It never reads the roster, a conflicts ledger or another brand's Tasks. Every importer's Tasks reach your members in the same feed order as your own. A preference for your own brands exists only as a declared export.first, a span in which your Tasks are offered first, printed on every importer's check and on the door's /terms. Your members see each importer's name on its Tasks, and turn off any brand they choose not to work for.

KeyWrittenLeft outDoes
roles.<r>.poolPool | '<door>/<pool>'the role is yours or your staff'sThe Pool a role draws on. Roles owns its forms.
export{ placement: number; to: '*' | string[]; min_pay?: { [role]: number }; notice?: Within; first?: Within }noneLet other brands import this Pool: every brand or the domains listed, each paying placement dollars per filled Task, at or above min_pay per role, with notice (30 days) before a change, and your own Tasks first for first.
check gateWhy
pay_below_floorAn importing role's pay is below the minimum the exporter publishes for that role.

gigs.lawyer serves api.lawyer, patent.click and incorporations.legal from one roster: one Pool across a family of brands. A founder who sells patent work under a brand of their own imports gigs.lawyer/attorneys and pays its placement on each review. A tax brand that adds bookkeeping imports the accountants' Pool from gigs.accountants beside its own preparers.