One Pool, several brands
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:
cat pools/translators.ts # in @lingua/pools, the package lingua and captions both importimport { 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:
cat services/subtitles.ts # in captionsimport { translators } from '@lingua/pools'
roles: { subtitler: { pool: translators, pay: 20 } },npx services.dev check # in captions 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 brand | Set by each brand, in its Services |
|---|---|
| the roster, each member's verification and its freshness | the pay of each role |
| each member's conflicts ledger, checked the same way on every brand's Tasks | the rules rows that reserve each act |
| one track record across every Pool on a shared door, and each Pool's own tiers | the words its Services speak |
| one payout account, and one payout with a line per brand | each price, and how each Service earns |
| the door, its terms and its board | which 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:
cat services/translation.ts # a brand with no Pool of its own roles: { translator: { pool: 'gigs.expert/translators', pay: 30 } },npx services.dev check 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.16An 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 operator | Your brand | |
|---|---|---|
| Roster, verification, conflicts ledgers | runs them | never reads them |
| Track records and tiers | keeps them, each the member's own | reads the acts on its own jobs |
| Dispatch, the fill ladder, payouts | sets and runs them, in one feed order for every importer | funds the raises on its own Tasks |
| Eligibility | the Pool's own predicates | its rules rows: a member must hold the credential in the region each row names |
| Pay | sets nothing; publishes its minimum per role | pay per role, at or above that minimum, and members' own minimum fees still filter what they are offered |
| Placement | earns it | pays 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:
→ GET /owner/jobs/job_7Hq2/ledger # the importing brand, after the member signed +$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 youA 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:
→ GET /owner/console/placement # the importing brand's console card 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 teamOne 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:
git diff pools/translators.ts # the operator who runs the Pool verify: 'https://verify.example.test/translators',
+ export: { placement: 6, to: '*', min_pay: { translator: 25, subtitler: 18 }, notice: '30d' },
})npx services.dev check pools/translators.tspools/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 TasksEach 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.
| Key | Written | Left out | Does |
|---|---|---|---|
roles.<r>.pool | Pool | '<door>/<pool>' | the role is yours or your staff's | The Pool a role draws on. Roles owns its forms. |
export | { placement: number; to: '*' | string[]; min_pay?: { [role]: number }; notice?: Within; first?: Within } | none | Let 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 gate | Why |
|---|---|
pay_below_floor | An 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.