Service()

The running jobjob_7Hq2 · working · $49.00 held

Service({...}) is the only constructor. One file in services/ is one kind of work you sell and how it earns; its path is its address, and it runs nothing until it serves.

services/translation.ts
import { Service } from 'services.dev'

export default Service({
  name: 'Translation',
  input: { document: 'file', to: 'language: a BCP 47 tag, such as fr-CA' },
  output: { document: 'file' },
  price: 49,
})
captured/walk.txt · captured
$ npx services.dev check
services/translation.ts · 4 lines · $49 per job, within 48 hours, charged on delivery.
  who     AI delivers every job.
  steps   draft · ai → review · ai · adversarial
  agent   order_translation · 24 of 30 words · bought job_7Hq2 · $49.00 · no person
  ledger  +$49.00 · AI $0.84 (example) · you $48.16
  margin  at least $39.20 a job (80%) · a job that stops costs you at most $9.80
  apps    customer portal · owner console
KeyWrittenLeft outDoes
namestringrequiredWhat buyers call the work: the Site's title and the tool description's first word.
input{ <field>: <type word> }requiredWhat a buyer sends, field by field.
output{ <field>: <type word> }requiredWhat the buyer gets back.
deliverDeliver'ai', briefed by services/<id>.mdWho does the work: 'ai', a person or a role word, a URL, your function, or named steps in order.
humanHumannone: AI delivers every job aloneOptional: 'risky', 'always', your rule, or a credential that signs.
pricenumber | PriceFormrequiredWhat a job costs: dollars, or { usd, payout, within, approved, share, of, release }; with every, what each cycle of a subscription costs, and includes its allowances.
outcomeOutcomenoneWhat a share is paid on: the amount, who proves it, how a payment finds the job, and how long the money stays held.
onTriggersnoneWhat starts jobs on a subscription: dates in schedule, events in event, each minting this Service or the one it names. Needs price.every.
descriptionstringwritten from name, input and outputOne sentence for the Site's lede and the tool description.
reviewReview'adversarial'How the AI checks every job before it ships: 'adversarial', or 'affirmative' for creative work.
policy{ <name>: PolicyEntry }noneWhat an order may set, within your bounds: the buyer's mechanics, and the merits only the client sets.
signals{ <name>: Signal }noneNamed facts that route the work: a predicate, silent for a span, or inbound; goto moves the job.
ends{ <end>: EndSpec }noneEnds beyond accepted, canceled, lapsed and declined, each with its charge, who may reach it, and what can follow.
statusStatus'live''live', 'preview' (test keys only) or 'roadmap' (published, answering not_live).
roles{ [K in R]: Role }none: a role word is your staffWho may do, sign or review a step: each role's Pool, credential, region, pay and separation. A step's role word names one.
rulesRulesnone: no act is reservedThe rules table, from rules.ts or a package you pin: which acts are reserved, open or refused.
subjectSubjectSpecnoneWhat outlives the job: a subject keyed by an input or a receipt, the member of record on it, its kept facts, its periods, and the Service that watches its clocks.
clocks{ <name>: Clock }noneDates the world sets, by name: when each is due, who answers for it, the rungs that notice, escalate, ask for an acknowledgement and run a step, the steps that move it, and what the owner chooses at the end. The rungs, moves, every and on run, and the clock's own calls acknowledge, satisfy, choose and name its owner.
talkTalk | falseon, the AI answering the clientThe job's thread: the AI answers the client in it, and holds an answer in an advice class the rules reserve until a member of adopt adopts it. false turns it off.
calendarCalendarthe brand'sThis Service's own calendar, in place of the brand's: its zone, closed days, closing minute and roll.

subject, written out

KeyWrittenLeft outDoes
subject.kindstringrequiredWhat it is, in your words: 'patent family', 'trademark', 'company'.
subject.key(keyof I | keyof O) & stringrequiredThe input, or the output a receipt fills, whose value names it: application_number, ein.
subject.of_record{ role: RoleWord; named_at: <step>; custodian?: (RoleWord | 'brand')[] }noneThe member of record: whoever attests at named_at stays of record on the subject across jobs. Withdrawal names a successor; a member whose credential or coverage lapses leaves it vacant, and custodian covers it, rung by rung, then the brand.
subject.keepsKnoneFacts the subject keeps across jobs, each from the output that writes it: { carryforwards: 'carryforwards', tax: 'tax' }, typed as that output is. Written only when a job ends accepted, never when it is canceled or lapses, and keyed by the period the job held. Insert-only: each value records { value, job, step, at, period }, and nothing is overwritten.
subject.period(keyof I & string) | ((job) => string)noneOne live or ended job of this Service per subject per period: the input that names the period, or a function of the order. A second order for a period answers 409 period_taken, its next the follow-on the end offers, such as an amendment. A canceled job frees its period.
subject.stewardAnyServicenoneThe Service that keeps the subject's clocks once a job ends with one still running: ordered with the subject's key, it keeps the date in someone's hands. Until it is, the customer portal offers it beside an ask in which the client acknowledges they own the date, and nothing lapses into a gap between jobs.

price, for a subscription

KeyWrittenLeft outDoes
price.everyEverynoneA subscription: an order is a Subscription, sbn_…, charged usd at the start of each cycle, and on mints its jobs.
price.includes{ <name>: number }noneAllowances per cycle, by Service id: inside one a job is $0 and counted; past it, the order answers 402 OFFER at the job's price. Renewal resets them.
The work needsWriteRead
a credentialed person to do or sign a stepa role from a Pool, then by: '<role>' and stamp: true on the stepRoles
some acts reserved to a credential, region by regionrules: rows that are reserved, open or refusedRules
that person paid for each act, fixed when its Task postspay on the roleRoles
the client's consent, signature or decisionan ask step: { ask: 'client', to: 'consent' | 'sign' | 'decide' }Asks
documents or answers from the client firstan ask with to: 'answer' or 'upload', and itemsIntake and request lists
permission to act in the client's name, for a whilea grant ask, and needs on the steps that use itGrants and decisions
work hardened before anyone signs ita review step, with lenses and roundsReview steps
a floor, a cap or a required field on the outputguard on the stepGuards
choices only the client may makepolicy, with binds: 'merits'Policy
a calculation that follows a named authoritya function step with cite: '<authority>'Your code as a step
every extracted value traced to its pagecite: 'source' on the AI stepSourced output
a filing with a system you don't control, and its receipta submit step: to, receipt, rejected, perfect, fallbackSending to outside systems
the charge held until that system answersnothing: a Service with a submit step charges on its receiptSending to outside systems
linked filings, the lead one firsteach: { of, lead } on the submit stepOne submission per element
advice only under a credentialed member's namerules rows of kind: 'advice', and talk: { adopt: '<role>' }Talk
a client who can stop midway and owe only for acts doneends: { withdrawn: { charge: 'acts', by: 'client' } }How a job ends
facts that carry from one job to the nextsubject with keepsSubjects
one member of record across many jobssubject.of_recordOf record
one job per year, quarter or month, and an amendment aftersubject.period, and follow on the endOne job per period
a date a registry or a regulator sets, and someone who answers for itclocks: due, owner, rungs, moves, lapseClocks
a step run before that date, such as an extensiona run <step> <n>d rung on the clockClocks
that date on a calendar: its zone, weekends, closed days and closing minutecalendar on Brand(), or on the ServiceKeeping time
a date closed by a step's commit, with no one actingsatisfied_by on the clockClocks
a date nothing moves, and no work after ithard: { bars } on the clockClocks
a deadline that costs you when it's missed, and a person before it isprice.late, and escalate: { when: 'at_risk' }Deadlines
last period's figures in this period's codekeeps, read with job.subject.factSubjects
a rejection that re-asks only what its code names, element by elementrejected: { <code>: { to: '<ask>', items } }One submission per element
work that recurs, on dates or on eventsprice.every, on.schedule and on.eventSchedules and triggers
the period each scheduled date orders, such as last yeareach on the schedule entrySchedules and triggers
some jobs included each cycleprice.includesSubscriptions
a listing before it takes ordersstatus: 'roadmap' or 'preview'Publish before it takes orders
your own words on every surface, such as a different word for a jobBrand.wordsYour brand's words
ConstructorIts fileWhat it holdsRead
Service({...})services/<id>.ts, one per kind of workthe work, who does each step, and how it earnsthis page
Rules({...})rules.ts, or a package you pinwhich acts are reserved, open or refused, per Service and shared, under one versionRules
Pool({...})pools/<name>.ts, which several brands may shareone kind of people: their roles and credentials, how they join and verify, how a Task reaches themPool()
Brand({...})brand.ts, optionalthe domain, the brand's own words, and the credentials it holdsBrand()
captured/legal-walk.txt · magic values: member = mbr_eligible
$ npx services.dev check
brand.ts · 10 lines · legal · api.lawyer · words job → matter, subject → asset, task → review, member → signer, pool → network, end → outcome
rules.ts · 36 lines · rules 2026-10 · 6 Services · 16 rows · 1 shared
pools/attorneys.ts · 20 lines · attorneys · 4 roles: attorney, practitioner, watcher, student · joins in 3 steps · cascade · hold 24h
✓ ready to sell · 6 Services · each keeps at least 3% of every job
Surfaceservices/translation.ts is
APIPOST /jobs {"service":"translation"}, described in /openapi.json
CLInpx services.dev translation k=v …
MCPorder_translation, at /mcp
SDKconnect({ origin }).translation.order(input)
Site/translation
Docs/llms.txt
Appcustomer portal at /portal, owner console at /console

The tool description agents read: Translation: send a document and a language; get a document back. $49 per job, within 48 hours, charged on delivery. AI delivers every job.

The ruleWhat TypeScript says
The price is required.Property 'price' is missing.
A lone function returns the whole output.Property 'recovery' is missing in type '{ document: InFile; }' but required in type '{ readonly document: FileRef; readonly recovery: number; }'.
A share is of a money output.Type '"document"' is not assignable to type '"recovery"'.
Order options own their names.Type '"text"' is not assignable to type '"✗ key is an order option; rename this input"'.
before names a step.Type '"certfy"' is not assignable to type '"certify" | "delivery" | "draft" | undefined'. Did you mean '"certify"'?
A rule says why.Property 'because' is missing.
after names a step.Type '"drat"' is not assignable to type 'After<"draft" | "examine"> | undefined'. Did you mean '"draft"'?
A review hardens or extends.Type '"none"' is not assignable to type 'Review | undefined'.
An ask asks the buyer or a party input.Type '"document"' is not assignable to type '"applicant" | "buyer" | undefined'.
As JSONRead by
The manifest: every default written, money in integer centsevery surface: the API, CLI, MCP server, SDK, Site, docs and apps
OpAPICLIMCPSDKSiteDocsApp
service.orderPOST /jobs, POST /:service<service> k=v …order_<service><service>.order()/<service>: the order form10 error pagescustomer portal
service.quoteGET /:service.json/<service>: the price sentence1 error page
brand.manifestGET /manifest.json/manifest.json
brand.pricingGET /pricing/pricing

Operations has every column of every row.

CodeCategoryHTTPWhy
input_invalidinvalid_request422The order doesn't match the Service's input.
check gateWhy
description_too_longThe tool description is over 30 words, so agents skim past it.
price_unstatedThe tool description omits the price or when it's charged.
price_below_costA delivered job could lose money: payout, nested Services and the AI cap add up to more than the price.
upgrade_below_payoutThe approved price adds less than the person's payout.
agent_cannot_buyAn agent couldn't order, wait for and accept a job.
service_id_reservedA Service's file name, or a portal's, takes a word services.dev's own routes use.
surface_driftA surface serves a call with no row, or lacks a live row.

The lines that use it in the example brands, as their files write them, and what check read aloud for each file.

legal · services/docket-watch.ts · 10 lines
export default Service({
  name: 'Docket Watch',
  description: 'A docket watched every week, and an office action routed to its response.',
  input: { matter: 'text: an application or file number' },
  output: { status: 'text', next_due: 'date' },
  rules,
  subject: { kind: 'patent family', key: 'matter' },
  roles: { watcher: { pool: attorneys, pay: { usd: 4, on: 'act' } } },
npx services.dev check · captured/legal-walk.txt
services/docket-watch.ts · 10 lines · $12 per month, charged at the start of each month.
  steps   check · ai → ack · patent watcher → review · ai · adversarial

The legal example runs every one of its files, captured.

tax · services/question.ts · 10 lines
export default Service({
  name: 'Tax Question',
  description: 'A tax question, answered with its sources.',
  input: { owner: 'party: who asks', ein: 'text: such as 12-3456789', question: 'text: such as Can we deduct the van?' },
  output: { answer: 'text' },
  rules,
  subject: { kind: 'taxpayer', key: 'ein' },
  roles: { signer: { pool: preparers, pay: 25 } },
npx services.dev check · captured/tax-check.txt
services/question.ts · 10 lines · $49 per job, within 48 hours, charged on delivery.
  steps   answer · ai · cites the code, its regulations and the agency guidance it rests on → review · ai · adversarial

The tax example runs every one of its files, captured.