In CI

The running jobjob_7Hq2 · delivered · document.fr-CA.pdf · $49.00 charged

Run check on every push. It exits 1 on any failure and names each fix, as text for you or JSON for a pipeline, and magic values and test clocks reach every branch without a person or a wait.

check runs every gate on every Service, and has an agent buy a job of each, in-process. It needs no key, no network and no running server, and it exits 1 on any failure.

Here a teammate's push added one line, routed: true on the filing step, and a second Service called Listen. TypeScript passes both files; check doesn't:

magic values: none

$ npx services.dev check
services/listen.ts · 5 lines · $19 per job, within 48 hours, charged on delivery.
  who     AI delivers every job.
  steps   draft · ai → review · ai · adversarial
  agent   order_listen · 22 of 30 words · bought job_7Hq2 · $19.00 · no person
  ledger  +$19.00 · AI $0.84 (example) · you $18.16
  margin  at least $15.20 a job (80%) · a job that stops costs you at most $3.80
  apps    customer portal · owner console
  ✗ A surface serves a call with no row, or lacks a live row. Add the row, or render it. cli listen is service.order's command, and the CLI has none.
    https://services.dev/docs/reference/check/surface_drift

services/translation.ts · 22 lines · $89 per job, within 48 hours, charged when file is accepted.
  who     A sworn translator signs before the file step. The buyer answers at glossary.
  steps   glossary · buyer · answer → translate · ai → harden · ai · adversarial · 2 lenses · then a person signs → file · the registry · routed → correct · buyer · upload · routed → hand_off · buyer · answer · routed
  agent   order_translation · 30 of 30 words · job_7Hq2 waits on party
  ledger  +$89.00 · AI $1.26 (example) ·  · you $57.74
  margin  at least $41.20 a job (46%) · a job that stops costs you at most $47.80
  apps    customer portal · delivery portal · owner console

Only check reads the graph: a routed step that nothing routes to never runs, so the charge its receipt releases never comes. And listen is already a command, so the CLI can't order a Service by that name. Drift belongs to the whole brand, so it fails on every Service. Each failure's page says why the gate exists: step_unreachable, release_unproven and surface_drift.

A pipeline reads these fields of check --json:

FieldWhat it holds
services[].okfalse when any gate fails on that Service
services[].failures[]each failure's code, reason, next (the fix) and doc_url (its gate's page)
services[].agentthe job an agent bought in-process: its tool, job, status, charged in cents, and whether it needed a person
services[].margin.floorthe least you keep of a job, in cents and pct
mcpthe buyer tools, and their tokens against the budget
ai.simulatedtrue until you wire a model
Terminal
$ git diff --staged
diff --git a/services/listen.ts b/services/transcription.ts
similarity index 94%
rename from services/listen.ts
rename to services/transcription.ts
index d70002e..a100384 100644
--- a/services/listen.ts
+++ b/services/transcription.ts
@@ -3,7 +3,7 @@
 import { Service } from 'services.dev'
 
 export default Service({
-  name: 'Listen',
+  name: 'Transcription',
   description: 'A recording, transcribed in the language it was spoken.',
   input: { recording: 'file' },
   output: { transcript: 'file' },
diff --git a/services/translation.ts b/services/translation.ts
index effb319..1f92c79 100644
--- a/services/translation.ts
Terminal
$ npx services.dev check
mcp     14 buyer tools · 5,097 of 8,000 tokens · 9 more with ?toolset=sandbox
    "tokens": 5097,
    "sandbox": 9,
services/transcription.ts · 5 lines · $19 per job, within 48 hours, charged on delivery.
  who     AI delivers every job.
  steps   draft · ai → review · ai · adversarial
  agent   order_transcription · 22 of 30 words · bought job_7Hq2 · $19.00 · no person
  ledger  +$19.00 · AI $0.84 (example) · you $18.16
  margin  at least $15.20 a job (80%) · a job that stops costs you at most $3.80
  apps    customer portal · owner console

services/translation.ts · 21 lines · $89 per job, within 48 hours, charged when file is accepted.
  who     A sworn translator signs before the file step. The buyer answers at glossary.
  steps   glossary · buyer · answer → translate · ai → harden · ai · adversarial · 2 lenses · then a person signs → file · the registry → correct · buyer · upload · routed → hand_off · buyer · answer · routed
  agent   order_translation · 30 of 30 words · job_7Hq2 waits on party
  ledger  +$89.00 · AI $1.26 (example) ·  · you $57.74
  margin  at least $41.20 a job (46%) · a job that stops costs you at most $47.80
  apps    customer portal · delivery portal · owner console

Every command's exit code is its failure's category, so a pipeline branches without parsing words:

Output
Exit codes
  0 ok · 1 check failed · 2 usage · 3 invalid request · 4 authentication · 5 blocked: a person must act · 6 conflict or guard · 10 retry: api error, rate limited, nothing running
ExitcategoryMeans
0it worked
1check found something to fix
2invalid_requestthe command is missing something, has no such name, or the folder has no Services
3invalid_requestthe brand refused the request, such as a signal the Service doesn't take
4authenticationa key that isn't the brand's
5blockeda person must act first
6conflict, guardthe job's state or a guard refused it
10api_error, rate_limitedretry: nothing running, rate limited, or an API error

A command that calls the brand needs dev running. Without it, the answer is still the one error shape, and next is the command that fixes it:

Terminal
$ npx services.dev jobs get job_7Hq2 --json
{
  "type": "BLOCKED",
  "category": "api_error",
  "code": "not_running",
  "reason": "Nothing is running at http://localhost:8787.",
  "next": {
    "do": "run",
    "cli": "npx services.dev dev"
  },
  "doc_url": "https://services.dev/docs/reference/errors#not_running",
  "request_id": null
}
$ echo $?
10

A test never waits for a person or an outside system. Magic values pick the branch:

WhereValueBranch
a party's emailsigns@example.testacts at once: signs, consents, answers
a party's emaildeclines@example.testdeclines, and the job ends at $0 unless a step routes it
a party's emailsilent@example.testnever answers, so the ask reminds, expires and lapses on the clock
metadata.sandbox.outsidereject_oncethe outside system rejects the first submission, so the repair runs
metadata.sandbox.outsideneverthe outside system never answers, so the fallback runs
metadata.sandbox.reviewflag_oncethe first review round flags the work back, so the redo runs

Magic values lists every value and its branch. Test clocks move time, so a silent client's two weeks run in a second. A day before the link expires it reminds, a second ask opens, and when that one expires too the job lapses and the hold is voided:

Output
magic values: client.email = silent@example.test

$ npx services.dev signed-translation document=lease.pdf to=fr "client=Ada Lovelace <silent@example.test>" --max 120
job_7Hq2 · working · $120.00 held
job_7Hq2 · waiting · on party · $120.00 held
  record  translate · ai | harden · ai · adversarial · 2 lenses · pass
  next    hand http://localhost:8787/a/ask_7Hq2?t=8FaWT5EoCj4h-uMyjlXp3_ to the person it asks

$ npx services.dev tick 6d
tc_7Hq2 · 2026-10-25 14:02:11 → 2026-10-31 14:02:11 · 1 fired
  2026-10-31 14:02:11  job_7Hq2  ask.reminded · sign · 1d before expiry

$ npx services.dev tick 1d
tc_7Hq2 · 2026-10-31 14:02:11 → 2026-11-01 14:02:11 · 2 fired
  2026-11-01 14:02:11  job_7Hq2  ask.expired · sign
  2026-11-01 14:02:11  job_7Hq2  ask sign · silent@example.test · sha256:0f61… · open

$ npx services.dev tick 7d
tc_7Hq2 · 2026-11-01 14:02:11 → 2026-11-08 14:02:11 · 4 fired
  2026-11-07 14:02:11  job_7Hq2  ask.reminded · sign · 1d before expiry

The buyer pays $0, and the AI the job ran is yours to bear. To run your brand's whole conformance suite in the same CI job, see Your conformance suite.

check --against live compares your change with the deployed brand and fails breaking_change by the rule Versions sets.