Skip to content

Holds

Calls that wait for a person to approve or reject them in the inbox.

A hold rule pauses a tool call until a person approves or rejects it. Use holds for risky writes: posting in public, sending messages, deleting, paying.

YAML
- id: hold-comments
  match: { tool: github_post_comment }
  decision: hold
  approvers: { roles: [approver, admin] }
  timeoutSeconds: 300
  1. The call pauses and a hold appears in the inbox, live, for the people who may approve it.
  2. An approver opens it and sees the agent, the person it acts for, the tool and its arguments.
  3. Approved: the tool runs. Rejected or timed out: the model gets an error result telling it not to retry.

If the wait itself fails (the server is unreachable), the call does not run, the guard emits an error event, and the model is told the approval could not be confirmed.

approvers takes at least one of:

  • roles: anyone with one of these roles.
  • emails: these specific people.
  • self: true: the person the agent acts for may approve their own hold.

Without self: true, the requester can never approve their own hold, even as an admin. A policy with a hold rule nobody could approve is rejected when it is published.

Approvals only come from people signed in to the inbox. The approver is always the signed-in user. An agent’s API key can never approve.

timeoutSeconds (default 300, at most 86,400) is how long the hold stays open on the server. The guard also has its own holdTimeoutMs (default 300,000 ms); a call that waits longer counts as rejected. Holds that run out are marked expired, and a late approval on an expired hold fails cleanly.

Holds always need the server. HybridGate and HttpGate create them there; in hybrid mode the server re-runs the check and only creates the hold if it agrees. LocalGate has no server, so a hold rule blocks with hold_requires_server.