What an agent can never do

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

Signing, consenting, directing, deciding, granting, attesting and raising a cap belong to a person. No tool exists for them. An agent gets the link to hand on.

An agent can do almost everything a buyer does: find your brand, ask the price, order, wait, read, accept, send back and cancel. Seven acts stay with people. An agent can never sign, consent, direct, decide, grant, attest or raise a cap.

No prompt can argue its way past that, because there's no check to argue with. Each of those acts is a row whose only callers are a person's own session or a party's own link, and no MCP client holds either. So the row renders no tool, and there's nothing to call.

Output
# a person's own: only their session or their link can call it, and no MCP client holds either
job.approve    owner session, member session  POST /:portal/jobs/:id/approve
clock.assign   owner session                  POST /owner/clocks/:id/assign
ask.get        party link, owner session      GET /asks/:id
ask.complete   party link                     POST /asks/:id
ask.revoke     party link                     POST /asks/:id/revoke
job.export     owner session                  GET /jobs/:id/export
job.ledger     owner session                  GET /owner/jobs/:id
key.raise      party link                     POST /keys/:key

# not a call an agent makes over MCP, and what it does instead
subject.list   an agent reads a subject's clocks with list_clocks and get_clock; the subject itself is the buyer's record, read over HTTP and the CLI
subject.get    an agent reads a subject's clocks with list_clocks and get_clock; the subject itself is the buyer's record, read over HTTP and the CLI
clock.ack      only a clock's owner acts on it, with their own key or in their own app: an agent reads it with get_clock, and a call from anyone else answers needs_the_owner with the owner's app as next.hand_to_person
clock.satisfy  only a clock's owner acts on it, with their own key or in their own app: an agent reads it with get_clock, and a call from anyone else answers needs_the_owner with the owner's app as next.hand_to_person
clock.choose   only a clock's owner acts on it, with their own key or in their own app: an agent reads it with get_clock, and a call from anyone else answers needs_the_owner with the owner's app as next.hand_to_person
job.files.put  a file is bytes: send it over HTTP or the SDK, and name it by URL in an order
job.files.get  a file is bytes: send it over HTTP or the SDK, and name it by URL in an order
event.stream   a stream, not a call: an agent reads list_events after a seq, or job:// for one job
watch.create   a watch delivers to a URL your server holds, which an agent's session doesn't: it reads list_events after a seq instead

The first group belongs to a person. The second is left out for a plainer reason, and each row says what an agent does instead. A tool an agent guesses at doesn't exist.

ActWho does it, and whereBuilt on
signthe party, through their link; or a credentialed person at their step, in their own session, the signature stamped on the recorddeliver.ask deliver.stamp
consentthe party, through their linkdeliver.ask
decidethe client, choosing among the step's choicesdeliver.ask
directthe client, naming who acts nextdeliver.direct
grantthe client, giving a scoped permission that expiresdeliver.grant
attesta member, at their Task, in their own sessiona member's acts
raise a capthe buyer, at checkout, through a linkkey.raise

answer and upload asks are different. A party may let an agent that holds their delegated key complete those two for them, dlg_. On localhost the sandbox stands one in: POST /asks/:id with a dlg_ value in the x-services-test-dlg header, and no link, completes an answer or upload ask, and the record names an agent as the one who did. A sign ask sent the same way is refused needs_the_party.

When a job waits on a party, its next is hand_to_person: the link only that person can use, what they're asked to do, and when it expires. tool is null, because no tool finishes it.

Output
→ tools/call get_job {"id":"job_7Hq2","wait":50}
# the text an agent reads first, beside structuredContent
← job_7Hq2 · waiting · on party · $49.00 held
  next  hand http://localhost:8787/a/ask_7Hq2?t=8FaWT5EoCj4h-uMyjlXp3_ to the person it asks
  next  get_job {"id":"job_7Hq2"}
  next  cancel_job {"id":"job_7Hq2"}

  next    {"do":"hand_to_person","url":"http://localhost:8787/a/ask_7Hq2?t=8FaWT5EoCj4h-uMyjlXp3_","arguments":{"ask":"ask_7Hq2"},"party":"buyer","to":"answer","items":[{"id":"terms","label":"Which terms stay in English?","status":"open"}],"expires_at":"2026-11-01T14:02:11.000Z","tool":null,"http":"GET http://localhost:8787/a/ask_7Hq2?t=8FaWT5EoCj4h-uMyjlXp3_"}

# the agent tries to finish the job itself
→ tools/call accept_job {"id":"job_7Hq2"}
← {
  "type": "BLOCKED",
  "category": "blocked",
  "code": "needs_the_party",
  "reason": "glossary waits on the buyer to answer. Only they can, through their own link. Hand them the link in next.",
  "param": "ask_7Hq2",
  "next": {
    "do": "hand_to_person",
    "url": "http://localhost:8787/a/ask_7Hq2?t=8FaWT5EoCj4h-uMyjlXp3_",

The agent's job is to deliver the link, by whatever reached the person in the first place: email, chat, or the app they ordered from. When they act, the job moves on, and the agent's next get_job sees it. If the link goes astray, reissue_ask issues a new one, and the old one stops working at once. The ask itself, its link, expiry and reissue, has its own page: Asks.

An agent that tries anyway gets needs_the_party, with the same body over the CLI, HTTP, MCP and the SDK. Here the party is the client, asked to sign:

$ npx services.dev jobs accept job_7Hq3
sign waits on Ada Lovelace to sign. Only they can, through their own link. Hand them the link in next.
  next    hand http://localhost:8787/a/ask_7Hq2?t=cHGjprSn08ODyOp_8zLIVH to the person it asks
  docs    http://localhost:8787/docs/errors/needs_the_party
$ curl -X POST http://localhost:8787/jobs/job_7Hq3/accept -H 'content-type: application/json' -d '{}'
← 403 · {
  "type": "BLOCKED",
  "category": "blocked",
  "code": "needs_the_party",
  "reason": "sign waits on Ada Lovelace to sign. Only they can, through their own link. Hand them the link in next.",
  "param": "ask_7Hq2",
  "next": {
    "do": "hand_to_person",
    "url": "http://localhost:8787/a/ask_7Hq2?t=cHGjprSn08ODyOp_8zLIVH",
    "arguments": {
      "ask": "ask_7Hq2"
    },
    "party": {
      "name": "Ada Lovelace",
      "email": "ada@example.com"
    },
    "to": "sign",
    "expires_at": "2026-11-01T14:02:11.000Z",
    "tool": null,
→ tools/call accept_job {"id":"job_7Hq3"}
← isError: true, structuredContent:
← {
  "type": "BLOCKED",
  "category": "blocked",
  "code": "needs_the_party",
  "reason": "sign waits on Ada Lovelace to sign. Only they can, through their own link. Hand them the link in next.",
  "param": "ask_7Hq2",
  "next": {
    "do": "hand_to_person",
    "url": "http://localhost:8787/a/ask_7Hq2?t=cHGjprSn08ODyOp_8zLIVH",
    "arguments": {
      "ask": "ask_7Hq2"
    },
    "party": {
      "name": "Ada Lovelace",
      "email": "ada@example.com"
    },
    "to": "sign",
    "expires_at": "2026-11-01T14:02:11.000Z",
await lingua.jobs.accept("job_7Hq3")
× throws BlockedError<'job.accept'> · 403
← {
  "type": "BLOCKED",
  "category": "blocked",
  "code": "needs_the_party",
  "reason": "sign waits on Ada Lovelace to sign. Only they can, through their own link. Hand them the link in next.",
  "param": "ask_7Hq2",
  "next": {
    "do": "hand_to_person",
    "url": "http://localhost:8787/a/ask_7Hq2?t=cHGjprSn08ODyOp_8zLIVH",
    "arguments": {
      "ask": "ask_7Hq2"
    },
    "party": {
      "name": "Ada Lovelace",
      "email": "ada@example.com"
    },
    "to": "sign",
    "expires_at": "2026-11-01T14:02:11.000Z",

The line between an agent and a person is drawn by credential. Each operation names who may call it in the credentials registry, and every surface reads that one table, so a new surface can't open a door the table keeps shut. That's also how a Service meets licensing by design: when a step needs a credentialed person's signature, only that person's own session can give it, and the record says who did.

Worked in: the agent's order, the floor handed to the seller.