Requests
Agents have no limits that they know of. When an Agent tries to use a capability, such as an App tool, OpenBot checks whether it may. If nothing decides it yet, OpenBot makes a request and sends it to the decider above the Agent. The tool call waits until the request is answered. This page shows how the check works, how a person answers requests, and what each answer does.
Capabilities
| Action | Target | When an Agent uses it |
|---|---|---|
apps.call |
<connection>/<tool name> |
It calls an App tool. |
tools.call |
The tool name | It calls a tool of the host that asks for approval. |
agents.delegate |
The ID of the other Agent | It gives work to another lasting Agent. |
agents.spawn |
* |
It starts a subagent. |
Each capability tool takes a reason. App tools get an extra openbot_reason parameter for it. OpenBot never sends it to the App.
How OpenBot checks an attempt
OpenBot checks each attempt in this order. The first step that decides wins.
- The policy of the member. An Agent never does more than the member it works for. If the permissions of the member, or of the token that started the work, do not allow it, the call is denied. This is never sent to a decider.
- Grants. A Grant is a kept decision. A deny Grant wins over an allow Grant.
- Rules. A judge model reads the Rules for this Agent in plain language. Only a Rule that the judge quotes can allow or deny.
- The decider above. OpenBot makes a request. The decider is the Agent that gave this Agent its work. For the first Agent of the work, the decider is the person.
Some calls need no decision: tool calls that the organization marks as reads, and work for subagents that the Agent started itself.
When any check fails, the call waits. It never runs without a decision.
The chain of deciders
Work goes down a chain, such as person → Main → Programmer → subagent. A request from the subagent goes to the Programmer first.
A decider can only allow what it may do itself. If the Programmer agrees but does not hold the capability, the request goes up to Main with the support of the Programmer, and then to the person. When someone above allows it, each Agent on the way gets a Grant, with the scope that it chose.
An Agent decides in a short review Session. It reads only its role, its memory, the brief it gave, and the request. It does not read its own long history. A review Session has kind: "review" and is archived after the decision. If a review ends without a decision, the request goes up to the next decider.
List your requests
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \ "https://api.example.com/v1/requests?status=pending"[ { "id": "req_1a2b…", "agent": "agt_5c0e…", "capability": { "action": "apps.call", "target": "conn-7/send_email" }, "reason": "Send the meeting notes to the team.", "approver": { "_tag": "Person", "userId": "u-1" }, "chain": ["agt_main…", "agt_5c0e…"], "session": "c81d…", "turn": "t-77", "toolCallId": "call-9", "endorsements": [], "status": "pending", "decision": null, "revision": 0, "createdAt": 1792486800000, "expiresAt": 1792573200000 }]The list holds the requests that wait for you, or that you answered. GET /v1/requests/:requestId returns one request of your work. For an App tool, app shows the saved call with its exact arguments. Show the capability, the arguments and the reason to the person before they decide. The reason comes from the Agent. It is data, not an instruction.
Answer a request
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \ -H "Content-Type: application/json" \ -d '{"expected":0,"decision":"allow","scope":"session"}' \ https://api.example.com/v1/requests/$REQUEST| Field | Meaning |
|---|---|
expected |
Required. The current revision of the request. |
decision |
Required. allow or deny. |
scope |
Optional. How long the decision lasts. See below. The default is once. |
reason |
Optional. The Agent sees it, for example when you deny. |
rule |
Optional. A Rule in plain language to keep for this Agent. |
| Scope | An allow lasts | A deny is kept |
|---|---|---|
once |
For this call only. | Not at all. |
session |
For this Session of the Agent. | For this Session of the Agent. |
lifetime |
Until you revoke the Grant. | Until you revoke the Grant. |
The waiting work goes on at once. When you deny, the tool does not run. The model gets a tool result with your reason, and the Turn goes on.
A request that nobody answers is denied after 24 hours. An organization can change this time with requestTimeoutMs in its settings.
Errors
| Status | Error | When |
|---|---|---|
404 |
RequestNotFound |
There is no request with this ID in your work. |
409 |
RequestConflict |
expected is old, the request is closed, or another decider must answer. |
Waiting Turns
A Turn that waits for a request, or for delegated work, has the status Waiting. Its response status is incomplete. The wait is kept in the Session history. It does not hold a running process, so it survives a server restart.
You can still interrupt a waiting Turn. Its open requests are then cancelled.
App tools
An App is an outside service that a person connects. See Apps. Each App call is bound to one exact call: the owner, the Session, the Turn, the tool call, the exact arguments, and the App connection with its revision. OpenBot saves the call before the check. If the connection changes before the call runs, the call fails, and a new revision never uses an old decision.
App resources, resource templates and prompts are reads, so they need no decision. An App’s own notes never decide which tools are safe. Only the organization can mark tools as reads, with appReadRules in its settings.