Guards

The running jobjob_7Hq2 · working · $49.00 held

A guard checks a step's output before it commits, such as a floor, a cap or a required field. The AI redoes a refused proposal, and a person's step stays theirs until it holds.

A guard answers one question: is this output acceptable, whoever proposed it?

services/checked-translation.ts
    translate: { by: 'ai', guard: { match: (v, job) => v >= job.policy.match || `below the match the client set (${v} < ${job.policy.match})` } },

On a step

KeyWrittenLeft outDoes
guardGuardnoneChecks on the output before it commits; a failure is guard_refused, for AI and people alike.
checkliststring[]noneWhat a person checks, item by item.

A guard is a function per output field. It reads the proposed value and the job, and returns true or the reason it can't stand. The reason is what everyone sees: the record, the person, the agent.

Refused, the AI redoes it inside its budget, and the record keeps both:

Call
→ POST /checked-translation {"document":"manual.pdf","to":"de","policy":{"match":0.9},"max_usd":79,"key":"guarded","metadata":{"sandbox":{"propose":{"match":[0.7,0.95]}}}}
magic values: metadata.sandbox.propose = { match: [0.7, 0.95] }
← job_7Hq2 · waiting · on person · $79.00 held
  record  translate · ai · refused · guard_refused · match: below the match the client set (0.7 < 0.9) | translate · ai · redo

A person gets the same refusal as a 422, inline, and the step stays theirs:

Call
→ POST /proofreaders/jobs/job_7Hq2/approve {"output":{"match":0.8}}
422 · magic values: metadata.sandbox.propose = { match: [0.7, 0.95] }
  "code": "guard_refused",
  "reason": "match: below the match the client set (0.8 < 0.9)",
    "do": "approve",
    "tool": null,
    "http": "POST http://localhost:8787/jobs/job_7Hq2/approve"

next is approve with no MCP tool: the step is still the proofreader's, in their app, and no key can take it.

Call
→ POST /proofreaders/jobs/job_7Hq2/approve {"output":{"match":0.96}}
200 · job_7Hq2 · working · $79.00 held · magic values: metadata.sandbox.propose = { match: [0.7, 0.95] }
← job_7Hq2 · delivered · manual.de.pdf · $79.00 charged

A guard reads job.policy, so the bound can be the client's. Here match is a merits value only the client sets, and the guard holds the AI and the proofreader to it. See policy.

checklist lists what a person affirms, item by item. An attestation missing an item is refused, the same way.

A signal names a fact and can move the job. It never refuses an output. Blocking is a guard's job.

OpAPICLIMCPSDKSiteDocsApp
job.approvePOST /:portal/jobs/:id/approve, POST /jobs/:id/approve, POST /jobs/:id/sign, POST /owner/jobs/:id/approvejobs approve <job>never: a person actsnever: a person acts8 error pagesowner console, delivery portal

Events: step.refused.

Operations has every column of every row.

CodeCategoryHTTPWhy
guard_refusedguard422A guard refused the output, and says why.

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

legal · services/contract-review.ts · 16 lines
    advise: { by: 'attorney', stamp: true, est: '45min', checklist: ['every flag is addressed', 'the memo answers the goals'] },
npx services.dev check · captured/legal-walk.txt
services/contract-review.ts · 16 lines · $99 per job, within 48 hours, charged on acceptance.
  steps   consent · client · consent → flag · ai → attack · ai · adversarial → advise · attorney · client · stamped · 2-item checklist → send · ai

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

tax · services/amended-return.ts · 22 lines
    prepare: { by: 'preparer', est: '1h', checklist: ['every changed line traces to a source'] },
npx services.dev check · captured/tax-check.txt
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.adjusted

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

sales · services/deal.ts · 42 lines
      guard: { held: (m, job) => m.attended(job.input.account) >= 10 || 'no one from the account stayed 10 minutes' } },
      guard: { closed_value: (v, job) => v >= job.input.value * job.policy.floor || 'below the floor you set' } },
npx services.dev check · captured/sales-check.txt
services/deal.ts · 42 lines · nothing on effort; 5% of closed_value at won, proven by the account's payment, held 60 days by bank, 120 by card.
  steps   source · ai → qualify · ai → book · ai · setter when warm → meet · ai · closer from humans_from, committee or person · skipped for B2A · guard held: the account attends 10 minutes → propose · ai · the closer's span → negotiate · ai · the closer's span → close · ai · the closer's span · guard closed_value at least value × floor → nurture · nurturer · routed

The sales example runs every one of its files.