Approvals
Human-in-the-loop approval gates surfaced through the Operations queue. An agent that needs authorization for a sensitive action parks an approval item and ends its turn; a person approves or rejects it — an operator from the Operations page or the mobile admin, or the Workspace user the agent addressed it to — and the agent reads the decision back and continues.
Trinity Platform Demo — operator queue & approvals
May 2026
Concepts
approval (a yes/no or multi-choice decision), question (freeform guidance), alert (acknowledgement only). Created by the agent, consumed by a person.approval (typically ["approve", "reject"], but agents may define richer sets like ["draft", "send", "discard"]). The decision must be one of them.response) is what the agent reads: the chosen option, the typed answer to a question, or acknowledged. The note (response_text) is optional free text riding alongside a decision; it never stands alone.addressed_to_email). It appears in that person's Workspace, where they answer it, and stays visible to operators in the queue. An item with no addressee is for the operator alone.critical, high, medium, low. Affects sort order in the queue.expires_at. After expiry the item moves to expired; the agent treats that as “not approved — do not proceed”.How It Works
The agent reaches a step that needs authorization.
The agent appends an entry to ~/.trinity/operator-queue.json (or calls a helper skill that does so) and ends its turn — it never waits in-turn for a human.
The Operator Queue Sync Service polls the file every 5 seconds and persists the item to the backend.
The item appears on the Operations page under the Needs Response tab with a type pill — Needs approval, Question or Heads up — plus title, question, options, and any context the agent attached. Resolved items (responded, cancelled, expired) move to the Resolved tab. An item addressed to a Workspace user also appears in that person's Workspace (below).
A person answers. The controls follow the type: for an approval, pick an option, optionally add a note, and click Send; for a question, type an answer and click Send Answer; for an alert, click Got it. Nothing is sent on a single tap of an option.
The decision is written back into the agent's ~/.trinity/operator-queue.json within about 5 seconds (running agents only).
The agent acts on it and marks the item acknowledged.
When the agent acts on it. By default the answer is read at the start of the agent's next turn — its next scheduled run, loop iteration or message. An agent with no next turn would wait indefinitely, so the agent's owner can turn on Wake this agent when an operator answers: then answering starts one turn immediately and the agent acts on the decision in it. That turn shows in Executions with trigger operator_response. See Wake on Operator Answer.
The decision must be one the agent offered. For an approval that listed options, an answer outside that list is refused with a 422 that names the offered options; matching is exact, so Approve and approve are different answers. Questions, alerts and approvals that offered no options take free text.
Platform heads-ups. Trinity itself files items of other types into the same queue — for example a Workspace client rating a response as not useful, or an agent calling a playbook that does not exist. These carry no decision; they show Got it only, and acknowledging them sends nothing back to the agent.
Asks Addressed to a Workspace User
An agent can address an item to one person it is shared with by setting addressed_to_email on the request entry. The address is checked at ingestion against the agent's own roster: someone the agent is not shared with, or a malformed value, turns the item into an ordinary operator ask rather than being refused. The context block of an ask is never shown to the addressee.
What that person sees in the Workspace:
An ask is answered through the Workspace's own route (below), which records the answer with the same write-back, audit fields and wake-on-answer behaviour as an operator's. A client whose share was revoked stops seeing the ask.
Bulk Operations
The Operations page offers a per-tab Clear All that hides resolved items, and pending items can be bulk-cancelled. Because cancellation can race with a response, submitting a decision returns 409 if the item left the pendingstate in the meantime (for example, it was cancelled by a bulk operation) — refresh the queue and re-check before retrying.
From a Phone
The mobile admin at /m answers the same queue with the same three controls.
Real-Time Notifications
WebSocket events fired along the way:
operator_queue_new — when the item arrivesoperator_queue_responded — when someone decidesoperator_queue_acknowledged — when the agent confirms it saw the decisionFor Agents
Approvals share the operator-queue API surface:
| Endpoint | Method | Description |
|---|---|---|
| /api/operator-queue | GET | List queue items (filter by type=approval) |
| /api/operator-queue/{id} | GET | Get a single item |
| /api/operator-queue/{id}/respond | POST | Submit the decision — {response, response_text?}. 422 when an approval's response is not an offered option; 409 when the item is no longer pending |
| /api/operator-queue/{id}/cancel | POST | Cancel a pending item |
| /api/operator-queue/agents/{name} | GET | Items scoped to a specific agent |
Asks addressed to a Workspace user are read and answered as that user, under the Workspace prefix (a Workspace session token or a platform JWT; agent keys are refused):
| Endpoint | Method | Description |
|---|---|---|
| /api/enterprise/client-portal/asks?agent_name= | GET | Open asks addressed to the caller, optionally narrowed to one agent. Each carries kind, title, question, options, expires_at, status (pending or expired) and the chat_id it belongs to |
| /api/enterprise/client-portal/asks/{id}/answer | POST | Answer one — {response, response_text?}. Returns the ask with status: "answered" and resume_requested (whether answering started a turn). 422 empty_answer / response_not_an_offered_option; 409 expired; a missing or not-yours ask is a uniform 404 |
See the Operating Room doc for the full queue model.
MCP Tools
Agents can inspect the queue and resolve a pending item programmatically:
| Tool | Description |
|---|---|
| list_operator_queue | List queue items, broad or filtered by agent_name |
| get_operator_queue_item | Fetch a single item by id |
| respond_to_operator_queue(item_id, response, response_text?) | Submit the decision for a pending item — the same rules as the respond route: response must be an offered option, and an item that is no longer pending returns a structured error |
Agent-scoped API keys see only items for the calling agent itself plus agents it has been explicitly permitted to access, and can respond only to those. Cancelling remains a human action through the UI or the routes above.