A date the world sets
Give the filing a date the registry sets and the buyer answers for. Three days out, a rung asks the registry for more time; at the date, unfiled, the buyer chooses what happens.
within is your deadline: how long the work may take. Some dates belong to the world: a registry takes a filing until the day it names. A clock holds that date, names who answers for it, acts before it comes, and at the date asks its owner what happens. This is Grow 5: Grow 4's filing gains a date.
check counts 26 lines. translators() is Grow 4's, unchanged:
import { Pool, Rules, Service } from 'services.dev'
// Grow 5, a date the world sets: the registry takes the filing until a date the buyer names, and the buyer answers
// for it. Three days out, the clock asks the registry for two more weeks, and the extension moves the date. The clock
// is named for the filing, so the filing satisfies it; at the date, unfiled, the buyer chooses to file late or withdraw.
export default Service({
name: 'Translation',
description: 'A document, translated, signed and filed by its date.',
input: { document: 'file', to: 'language: a BCP 47 tag, such as fr-CA', file_by: 'date: the registry deadline, such as 2026-11-04' },
output: { document: 'file', filing: 'text', extension: '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' },
extend: { submit: 'https://registry.example.test/extensions', to: 'the registry', receipt: 'extension', routed: true },
file: {
submit: 'https://registry.example.test/filings',Asking for more time is an act, so rules() gains one row:
extend: { open: true, position: 'Asking a registry for more time needs no credential.' },file_by is the buyer's date. extend is routed: it runs only when the clock sends the job there.
| Key | What it does | Default |
|---|---|---|
due | The date: a function of the job returning a civil date, which closes at the calendar's minute, or a span after a step, an input, an event or another clock, such as '365d after file'. A function that throws, or returns what isn't a date, fails check with clock_due_unreadable | required |
owner | Who answers for it: 'buyer', 'brand', a role, or of_record, the member of record on the subject. An owner that can never resolve fails check with clock_unowned | required |
rungs | What happens before the date, in civil days back: 'notice 30d' and 'escalate 3d' tell the owner, 'ack daily 2d' asks them to acknowledge each of the last two days, and 'run extend 3d' proposes the routed step through the gate. A proposal the gate holds proposes again each day, and escalates | none |
moves | Steps whose committed output moves the date, and to when: '14d after due', or a function of the job. It moves this clock only, so two dates that move differently are two clocks | none |
lapse | What the owner chooses at the date, unsatisfied, through clock.choose. A step's name runs that step through the gate; any other option closes the clock with the choice on the record | none |
satisfied_by | Steps whose commit closes it | the step it's named for |
Clocks covers every, each, lives_on, hard, exposure and the calendar.
npx services.dev checkservices/translation.ts · 26 lines · $89 per job, within 48 hours, charged on file's receipt.
who A translator signs every document before it is filed. (rules 2026-10) The buyer answers at glossary.
roles translator · sworn translator · from sworn-translators · $30 an act
steps glossary · buyer · answer → translate · ai → harden · ai · adversarial · 2 lenses → sign · translator · * · stamped → extend · the registry · routed → file · the registry → hand_off · buyer · answer · routed
clocks file · a date your code decides · the buyer
bounds reserved sign to sworn translator · open extend and file
agent order_translation · 30 of 30 words · job_7Hq2 waits on party
ledger +$89.00 · AI $1.26 (example) · translator $30.00 · you $57.74
margin at least $41.20 when the first translator signs ($89.00 − $30.00 translator − $17.80 AI cap) · $26.20 at the ladder's cap, the lower of 50% and what the floor leaves · $11.20 after a decline and a second translator
a job that stops costs you at most $47.80
apps customer portal · delivery portal · owner console
mcp 13 buyer tools · 4,555 of 8,000 tokens · 9 more with ?toolset=sandbox
✓ ready to sell · 1 Service · it keeps at least 46% of every job
next npx services.dev dev
AI and money are simulated until you wire them. $0.42 a call is an example.The clocks line names the date and its owner. The margin is Grow 4's.
No magic value is needed. The order opens the clock:
→ POST /translation {"document":"lease.pdf","to":"fr-CA","file_by":"2026-11-04","key":"grow","max_usd":89}← job_7Hq2 · waiting · on party · $89.00 held
clock clk_7Hq2 · file · due 2026-11-04 · buyer · openEvery surface reads it alike, its rung armed, its lapse listed:
npx services.dev clocks get clk_7Hq2 --json{
"id": "clk_7Hq2",
"object": "clock",
"livemode": false,
"name": "file",
"service": "translation",
"job": "job_7Hq2",
"subject": null,
"lives_on": "job",
"status": "open",
"due_at": "2026-11-04T23:59:00.000Z",
"due_on": "2026-11-04",
"zone": "UTC",
"original_due_at": "2026-11-04T23:59:00.000Z",
"moves": [],
"occurrence": 0,
"owner": {
"type": "buyer",
"member": null
},
"rungs": [
{
"rung": "run extend 3d",
"rings_at": "2026-11-01T00:00:00.000Z",
"fired": false
}
],
"lapse": [
"file",
"withdraw, in writing"
],
"choice": null,
curl http://localhost:8787/clocks/clk_7Hq2{
"id": "clk_7Hq2",
"object": "clock",
"livemode": false,
"name": "file",
"service": "translation",
"job": "job_7Hq2",
"subject": null,
"lives_on": "job",
"status": "open",
"due_at": "2026-11-04T23:59:00.000Z",
"due_on": "2026-11-04",
"zone": "UTC",
"original_due_at": "2026-11-04T23:59:00.000Z",
"moves": [],
"occurrence": 0,
"owner": {
"type": "buyer",
"member": null
},
"rungs": [
{
"rung": "run extend 3d",
"rings_at": "2026-11-01T00:00:00.000Z",
"fired": false
}
],
"lapse": [
"file",
"withdraw, in writing"
],
"choice": null,
→ tools/call get_clock {"id":"clk_7Hq2"}{
"id": "clk_7Hq2",
"object": "clock",
"livemode": false,
"name": "file",
"service": "translation",
"job": "job_7Hq2",
"subject": null,
"lives_on": "job",
"status": "open",
"due_at": "2026-11-04T23:59:00.000Z",
"due_on": "2026-11-04",
"zone": "UTC",
"original_due_at": "2026-11-04T23:59:00.000Z",
"moves": [],
"occurrence": 0,
"owner": {
"type": "buyer",
"member": null
},
"rungs": [
{
"rung": "run extend 3d",
"rings_at": "2026-11-01T00:00:00.000Z",
"fired": false
}
],
"lapse": [
"file",
"withdraw, in writing"
],
"choice": null,
await lingua.clocks.get("clk_7Hq2"){
"id": "clk_7Hq2",
"object": "clock",
"livemode": false,
"name": "file",
"service": "translation",
"job": "job_7Hq2",
"subject": null,
"lives_on": "job",
"status": "open",
"due_at": "2026-11-04T23:59:00.000Z",
"due_on": "2026-11-04",
"zone": "UTC",
"original_due_at": "2026-11-04T23:59:00.000Z",
"moves": [],
"occurrence": 0,
"owner": {
"type": "buyer",
"member": null
},
"rungs": [
{
"rung": "run extend 3d",
"rings_at": "2026-11-01T00:00:00.000Z",
"fired": false
}
],
"lapse": [
"file",
"withdraw, in writing"
],
"choice": null,
A test clock runs to 2 November, the glossary unanswered:
→ POST /test_clocks/default/advance {"to":"2026-11-02T00:00:00Z"} 2026-10-31 14:02:11 ask.reminded · glossary · 1d before expiry
2026-11-01 00:00:00 clock file · rung run extend 3d → extend proposed · committed
2026-11-01 00:00:00 extend · rcp_7Hq2 accepted
2026-11-01 00:00:00 clock file · moved 2026-11-04 → 2026-11-18
2026-11-01 00:00:00 waits on party at glossary
2026-11-01 14:02:11 ask.expired · glossary
2026-11-01 14:02:11 ask glossary · buyer · 1 item · 1 open (terms)Three days out, the rung proposed extend, the registry's receipt committed it, and moves carried the date to 18 November. The glossary's link expired and reopened as ask_7Hq3. The buyer answers, the translator signs, and the filing satisfies the clock:
→ POST /asks/ask_7Hq3?t=rE5VINsEvPPB93bDQLooDc {"items":{"terms":{"answer":"Lessee, Lessor, Premises"}}}
# 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 · POST /tasks/tsk_7Hq2/clear · POST /tasks/tsk_7Hq2/attest
← job_7Hq2 · delivered · lease.fr-CA.pdf · $89.00 charged
record glossary · reminded 1d before expiry | file clock · run extend 3d · goto extend | extend · the registry · accepted · rcp_7Hq2 | file clock · moved 2026-11-04 → 2026-11-18 | glossary · expired | glossary.terms · answered | glossary · buyer · answer · clock paused 7d 9h | translate · ai | harden · ai · adversarial · 2 lenses · pass | sign · person · sworn translator · * · mbr_7Hq2 | file · the registry · accepted · rcp_7Hq3
clock clk_7Hq2 · file · due 2026-11-18 · buyer · satisfied · moved from 2026-11-04
closed file · satisfied when file committedThe glossary's wait paused the job's own deadline, clock paused 7d 9h; the registry's date kept running.
Had the filing missed 18 November, the clock would turn due and wait for the buyer's clock.choose: file runs the filing late, through the gate, and withdraw, in writing closes the clock with that choice on the record, leaving the job for the buyer to cancel. The clock calls shows one.
npx services.dev diff grow/submit.ts grow/clock.tsgrow/submit.ts (22 lines) → grow/clock.ts (26 lines)
Translation · changed description, input, output, deliver, rules, clocks · adds clocks: dates the world sets, who answers for each, its rungs and what moves it
API ~ operation service.order.translation POST /translation item.description, item.requestBody.content.application/json.schema.properties.file_by, item.requestBody.content.application/json.schema.required · breaking
~ operation service.quote.translation GET /translation.json answers.description, answers.input.properties.file_by, answers.input.required · breaking
+ operation clock.list GET /clocks
+ operation clock.get GET /clocks/{id}
+ operation clock.ack POST /clocks/{id}/ack
+ operation clock.satisfy POST /clocks/{id}/satisfy
+ operation clock.choose POST /clocks/{id}/choose
+ operation clock.assign POST /owner/clocks/{id}/assign
~ operation brand.manifest GET /manifest.json answers.services
+ object clk_ clock
+ 15 events clock.opened, clock.noticed, clock.escalated, clock.ack_due, clock.ack_missed, clock.ran, clock.moved, clock.due, clock.satisfied, clock.rolled, clock.recurred, clock.acked, clock.chosen, clock.assigned, clock.outlived
+ 6 errors needs_the_owner, evidence_required, evidence_used, clock_closed, clock_not_due, clock_moved_on
CLI ~ operation service.order.translation services.dev translation document=… to=… file_by=… input.properties.file_by, input.required · breaking
+ operation clock.list services.dev clocks list
+ operation clock.get services.dev clocks get <clock>
+ operation clock.ack services.dev clocks ack <clock>
+ operation clock.satisfy services.dev clocks satisfy <clock>
The input gains file_by, breaking for clients that type it. The clock brings its own calls, the clk_ object, fifteen events and six errors; MCP only reads clocks.
In a brand, the tax example runs two clocks on one job, because its extension moves one date and never the other.
Paid on the close: a Service that charges only when its buyer's own customer pays.