AI steps and briefs
An AI step works from a brief you write in Markdown. Every call is recorded with its model, the hash of each input and the brief it read, so any job replays.
An AI step answers one question: what the AI was told, and what it read.
Leave deliver out, and services/translation.md briefs the one AI step:
# Translation
The AI reads this brief on every job. Write it the way you'd brief someone new.
## How the work is done
- Translate the whole document into the language in `to`.On the Service
| Key | Written | Left out | Does |
|---|---|---|---|
deliver | Deliver | 'ai', briefed by services/<id>.md | Who does the work: 'ai', a person or a role word, a URL, your function, or named steps in order. |
Filled when the folder loads, never written
| Key | Written | Left out | Does |
|---|---|---|---|
briefs | { <name>: Brief } | none | The AI's brief per step, read when the folder loads: services/<id>/<step>.md, else services/<id>.md. |
In your code, on the job
| Key | Written | Left out | Does |
|---|---|---|---|
ai | (instructions, ...files) => Promise<string> | required | Calls the model with the Service's brief. Its cost is the ledger's AI cell. |
feedback | string[] | required | What the work was told to fix, oldest first: a review's flagged findings, a send-back's note, an outside system's rejection codes. The AI reads it on every redo. |
A step with its own job gets its own brief at services/<id>/<step>.md. Every other step reads services/<id>.md. Localization's reviewer, qa, has one, and its evidence bundle shows each call read the brief it should:
curl http://localhost:8787/owner/jobs/job_7Hq2/export # each artifact's text left outdecisions: 10, each pinned to simulated-1; briefs services/localization.md and services/localization/qa.mdEvery AI call writes decision.made to the record: the model it was pinned to, a hash of each input, the brief and its version, and what the call cost in cents. The first draft below reads the document and the language. The redo reads one thing more: the hash of the feedback, the review's finding.
→ POST /translation {"document":"lease.pdf","to":"fr-CA","max_usd":49,"key":"decisions","metadata":{"sandbox":{"review":"flag_once"}}}← job_7Hq2 · delivered · lease.fr-CA.pdf · $49.00 charged
record draft · ai | review · ai · flagged | draft · ai · redo | review · ai · passcurl http://localhost:8787/owner/jobs/job_7Hq2 # each decision.made for draft: the first, then the redo{
"type": "decision.made",
"step": "draft",
"by": "ai",
"model": "simulated-1",
"inputs": {
"document": "sha256:cf7622e8980f0ddeafa28c7011a972fd931be541b939ce9819aeba2e94925ee9",
"to": "sha256:5d6d4dd7ebd9caaa51cd2290ad24d68d2dda75714877d7cdc6a6e6de33097e9c"
},
"brief": {
"file": "services/translation.md",
"version": "sha256:858f32d14010584487adfdbf1f0ce69048895a5c745a9966a8a04d0940929c32"
},
"ai": 42
}
{
"type": "decision.made",
"step": "draft",
"by": "ai",
"model": "simulated-1",
A changed brief gets a new version, so a job that ran before the change still names the brief it read. Only the owner reads decisions. A buyer's job and a buyer's events never carry them.
A flagged review, a buyer's send-back note or an outside system's rejection codes become the job's feedback, and the AI reads it on every redo. The AI may spend at most 20% of the price on one job, redos included. Past that, the job stops and the buyer pays $0. Here dev({ review }) from services.dev/dev swaps in a review that flags every round, and the budget runs out:
→ POST /translation {"document":"lease.pdf","to":"fr-CA","max_usd":49,"key":"flagged"}← job_7Hq2 · canceled · ai_cap · $0
record 11 reviews flagged, 10 redos
ledger AI $9.24 · you −$9.24A URL makes an AI you already run the step, as deliver: 'https://…' or { by: 'https://…' }:
| Request | POST <url> with content-type: application/json, a services-job header carrying the job id, and the order's input as the body |
| Answer | a 2xx whose JSON is the step's output |
| A guard refuses it | asked again, up to three proposals in all; then the job stops at $0, step_failed |
| A non-2xx, or a throw | the job stops at $0, step_failed, with the status on the record |
With remote: false | the URL isn't called: the simulated AI stands in, as in every capture here |
In your code, job.ai(instructions, ...files) calls the same AI as 'ai', with the same brief, and its cost lands in the ledger's AI cell.
No call of its own: it changes what the job carries, on every surface that reads one.
Events: review.done.
Operations has every column of every row.
check gate | Why |
|---|---|
price_below_cost | A delivered job could lose money: payout, nested Services and the AI cap add up to more than the price. |
The lines that use it in the example brands, as their files write them, and what check read aloud for each file.
documents: 'ai',services/formation.ts · 30 lines · $299 per job, within 48 hours, charged on form_entity's receipt.
steps consent · founders · consent → advise_entity · attorney · client · 1-item checklist → review · ai · adversarial → form_entity · the state → rename · founders · answer · routed → documents · ai → adopt · founders · sign → advise_83b · attorney · client · 1-item checklistThe legal example runs every one of its files, captured.
draft: { by: 'ai', cite: 'the workpapers and the records the organizer took' },services/amended-return.ts · 22 lines · $900 per job, within 30 days, charged when file or aar is accepted.
steps compute · code · cites depreciation and carryforward schedules → draft · ai · cites the workpapers and the records the organizer took → check · ai · adversarial · 2 lenses → prepare · preparer · * · 1-item checklist → sign · signer · * · stamped in the paid-preparer block → authorize · owner · sign → file · IRS and states, unless a partnership → aar · IRS · Form 8082, for a partnership · emits k1.adjustedThe tax example runs every one of its files, captured.