Skip to content
quarry Documentation
Login

Documentation

Summary

Whatever a person may do, their agent may ask them to do. When an agent's call is refused because it lacks authority its person holds, the agent can ask instead of stopping. The person is told at once (inbox, phone push, email), approves or denies with one tap, and an approval runs exactly the call the agent made, as the person, under the person's own permissions at that moment. The result goes back to the agent, a secret in it readable once and by that agent only. Every zeitforge user has this for every agent they register, with nothing to set up.

Motivation

On 2026-11-08 a QA agent needed an account. Creating it was the only step a machine could not take, and it cost the owner three manual steps on a phone: a page to find, a token to copy, a vault to paste it into. The forge already had the right shape for three deed acts (delete, un-serve, hand on a repository): the agent asks, the owner approves, the call runs as the owner. It stopped there for three reasons: an allowlist of three operations, an approver found through a repository's deed (so nothing forge-wide could be asked), and a replay that discarded its result (so a minted token would be lost). This RFC removes all three.

Design

Asking

An agent asks by sending the call it wants with Quarry-Ask: <reason>. The reason is one line in the agent's words, shown to the person beside the forge's own description of the call. Without the header nothing changes: a refusal is a refusal, so no agent queues requests by accident.

The router decides before the operation runs:

When all hold, the answer is 202 Accepted with the request (id, summary, state pending), and nothing else happens. Otherwise the ordinary refusal stands, and the agent learns no more than it would have without asking: a repository it may not see is still answered as one that does not exist.

What may be asked

Anything the person may do themselves (decision 1), except:

Everything else the person can do is askable, forge-wide operations included: creating an agent, granting a role, changing a repository setting, handing a repository on.

Scope

A request must fall inside the agent's scope as its token states it: an agent whose token names repositories can ask only about those, and a token's letter ceiling bounds what it may ask for there. A forge-wide operation needs a token with no repository list. The person's own permissions bound the rest, checked again at approval, so an agent can never obtain through a request what its person could not do.

Answering

The request goes to the agent's person. For a dedicated team or repository agent it goes to that scope's admins, and the first of them to decide closes it. It is delivered at once on the sign-off workflow: in-app, phone push, and email, on by default because a request waits on someone. The email's link opens a page with the request and two buttons, Approve and Deny; it needs the person's own session (a sign-in link if they have none), so a forwarded email approves nothing.

Approval checks first that nothing it was asked about has moved: the agent still exists, is open and still answers to this person; a repository is still the same one (by its project code) and still within the agent's scope; and the person may still do the call. Then it runs the stored call, exactly as made, through the ordinary operation registry as the person. The act is journalled as agent (signed off by person).

SMS is a notify channel, not a quarry feature: it is asked for upstream at danmestas/notify and becomes one more step on the sign-off workflow when notify ships it.

Results

The result of an approved call is kept with the request for the agent to read with signoff.get. A field an operation marks secret (a minted token, an invite link) is readable once, by the requesting agent only, and is never shown on the page, in the email or in the journal; after the read it is gone. A failed run keeps its error for both to read.

Limits

The forge-agent guard

RFC 0021 kept two acts from forge agents so that a machine cannot multiply machines or raise its own standing: making or altering a forge agent, and changing any account's site-admin flag. Those acts stay unavailable to any agent directly, and become askable: with a person's approval they are that person's act, which is what the guard asked for.

Build order

  1. Requests become forge-wide: the approver is the agent's person, the repository optional, the result stored (secret fields once), expiry and the pending limit. The three deed operations move onto it and the allowlist goes.
  2. The router: Quarry-Ask, the authority-only refusal test, the scope test and the 202.
  3. The page and the email: one request, two buttons, session-bound.
  4. The per-agent switch on the agent's page.
  5. Secret fields in operation outputs: agent.token.new, account.invite, agent.token.reissue.

Decisions

  1. What may be asked: anything the person may do themselves, minus the exclusions above, not an allowlist (owner, 2026-11-08: "A").
  2. Who has it: every zeitforge user and every agent they register, according to the agent's scope and the person's permissions, with nothing to set up (owner, 2026-11-08).
  3. Reaching the person: inbox, push and email at once; SMS when notify has it (owner, 2026-11-08: "Inbox is fine but sms or email is even better").
  4. Settled with the owner's choices as the frame: the explicit Quarry-Ask header, approval replaying the exact call as the person, 7-day expiry, 20 pending per agent, a secret read once, and asking on by default with a per-agent off switch.