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.
- id: hold-comments
match: { tool: github_post_comment }
decision: hold
approvers: { roles: [approver, admin] }
timeoutSeconds: 300What happens
Section titled “What happens”- The call pauses and a hold appears in the inbox, live, for the people who may approve it.
- An approver opens it and sees the agent, the person it acts for, the tool and its arguments.
- 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.
Who can approve
Section titled “Who can approve”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.
Timeouts
Section titled “Timeouts”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.
Gates and holds
Section titled “Gates and holds”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.