How a job runs
One order, carried from the first input to the last cent. Every Service runs the same six stops, whether AI does all of it or a credentialed person signs.
A job is one order, held until the work is done. AI delivers by default. A person is a step you place, where you want one or where the work needs one, and the job waits for them as it waits for anything else.
| Stop | What happens | Who acts |
|---|---|---|
| Order | A buyer, or their agent, sends the input and the most they'll pay, and gets a job with the charge held, or an offer with the exact call to send. | buyer, agent |
| Steps | deliver runs as a graph of work, review, ask and submit steps. Each starts once the steps it waits on are done, and a step can branch, loop, or route the job to another. | AI, your code, a party, an outside system |
| Gate | Every doer proposes, and one gate commits. It checks each proposal against your guards and the job's policy, and writes it to the record or refuses it, the same way for AI and people. | the gate |
| People | Where you placed a person, the job waits for them to act in the delivery portal. A role names the credential the act needs, and a Pool of verified members fills it. | member, staff |
| Delivery | The output ships. The buyer accepts it, or sends it back with a note and the AI redoes it. Seven days after delivery it's final. | buyer |
| Money | The held charge releases on the fact you name: delivery, acceptance, or an outside system's receipt. One ledger splits it into AI, the person's pay and what you keep, and pays each person out on the Pool's schedule. | owner, member |
Four lines and a price: an agent orders, AI drafts, an adversarial review passes it, and the charge releases on delivery.
npx services.devan agent ordered Translation at $49
job_7Hq2 · delivered · document.fr-CA.pdf · $49.00 charged
record draft · ai | review · ai · pass
ledger +$49.00 · AI $0.84 · you $48.16Six stops, and no person at any of them. The buyer accepts or sends it back with a note, and the AI redoes it.
This is Translation after the first four Grow steps. Each key in the file is a stop on the map (its Pool and rules table are Grow 4's):
export default Service({
name: 'Translation',
description: 'A document, translated, signed and filed.',
input: { document: 'file', to: 'language: a BCP 47 tag, such as fr-CA' },
output: { document: 'file', filing: 'text' },
rules: rules(),
roles: { translator: { pool: translators(), pay: 30 } },
deliver: {
glossary: { ask: 'buyer', to: 'answer', items: () => [{ id: 'terms', label: 'Which terms stay in English?' }] },
translate: 'ai',
harden: { review: 'adversarial', lenses: ['meaning', 'terms'], rounds: 2 },
sign: { by: 'translator', stamp: true, est: '20min' },
file: {
submit: 'https://registry.example.test/filings',
to: 'the registry',
receipt: 'filing',
rejected: { missing_certificate: 'sign', '*': 'translate' },
perfect: '2d',
fallback: 'hand_off',
},Order a job with a magic value that makes the registry reject the first filing. The rejection's code chose the branch:
→ POST /translation {"document":"lease.pdf","to":"fr-CA","key":"grow","max_usd":89,"metadata":{"sandbox":{"outside":{"reject":["missing_certificate"]}}}}← job_7Hq2 · waiting · on party · $89.00 held
waiting {"on":"party","since_at":"2026-10-25T14:02:11.000Z","step":"glossary","clock":"paused"}
# 2 hours later, the buyer answers through the link
→ POST /asks/ask_7Hq2?t=8FaWT5EoCj4h-uMyjlXp3_ {"items":{"terms":{"answer":"Lessee, Lessor, Premises"}}}
← job_7Hq2 · waiting · on claim · $89.00 held
waiting {"on":"claim","since_at":"2026-10-25T16:02:11.000Z","step":"sign","task":"tsk_7Hq2"}
# on localhost you are the owner, and the owner holds no credential
→ POST /sworn-translators/jobs/job_7Hq2/approve
← 403 needs_a_person: sign is tsk_7Hq2, a Task for a member of sworn-translators: the member who claims and clears it attests, in their own session.
# 20 minutes later, mbr_7Hq2, the sworn translator, claims tsk_7Hq2 in the delivery portal and signs, in their own session
→ POST /tasks/tsk_7Hq2/claim
← tsk_7Hq2 · claimed · translator · sign · * · $30.00 · 20 min · $90.00 an hour · due 2026-10-27 16:02
→ POST /tasks/tsk_7Hq2/clear · GET /tasks/tsk_7Hq2/packet
→ POST /tasks/tsk_7Hq2/attest
← tsk_7Hq2 · done · translator · sign · * · $30.00 · attested · 20 min · $90.00 an hour · due 2026-10-27 16:02
← job_7Hq2 · waiting · on claim · $89.00 held
waiting {"on":"claim","since_at":"2026-10-25T16:22:11.000Z","step":"sign","task":"tsk_7Hq3"}
Read the record left to right, and it is the map:
- Order.
max_usdcapped the price. The $89 was held from the order and charged at the end. - Steps.
glossaryis an ask: the buyer acts through a link that needs no account, and the clock pauses while they do.translateis AI, andhardenis two AI reviewers, one per lens.fileis an outside system, and its typed rejection routed the job back tosign. - Gate. Each output was proposed, checked and committed one at a time, in the order you read it.
- People.
sign · person · sworn translatoris the credentialed act: a Task only a verified member of the Pool can claim, attested in their own session and bound to the file's hash. The owner's own approve was refused. That's how a Service meets licensing by design. - Delivery. The job shipped once the registry accepted the filing.
- Money. With a submit step, the charge waits for the receipt. The ledger is the split: AI, the translator's $30 for each of two signatures, and what you keep.
Every Service runs all six stops, and each key you add carries one of them. The canonical list of keys, the shape each makes and the plan it runs live on is the default, and what each key adds.
One record. Every proposal, refusal, answer, signature and receipt is a line on one append-only record. It's the only place a step's output is written, and how a job is replayed, exported and audited.
One refusal. A guard refuses AI and a person with the same guard_refused, and an agent that tries what only a person can gets the same shape: the reason, and the next call.
One price, stated first. Every Service says how it earns, and every offer, job and check prints it. services.dev's take is one more line on that ledger, and your plan decides which features run on live jobs (how it earns).
Everyone gets an app: who acts at each stop, and the app each of them gets.