Approvals (human-in-the-loop)

Require human sign-off before an agent runs a sensitive tool.

Some tool calls are too consequential to run unsupervised: sending an email, writing to a CRM, moving money. Rightbrain lets you put a human in the loop on a per-tool basis. When a gated tool is called, the run pauses and raises an approval request. Approval records the decision; the API client then resumes the run to execute the approved tool.

Approvals are configured on the agent revision, so they are versioned alongside the rest of the agent’s wiring. Changing an approval policy creates a new revision, and rolling back restores the previous policy.

Per-tool action controls

Every tool attached to an agent revision — a Task, an integration tool, an MCP tool, or a registered tool — carries an action control:

action_mode
'auto_run' | 'require_approval'Defaults to auto_run

auto_run lets the agent call the tool without interruption. require_approval pauses the run and raises an approval request before the tool executes.

rejection_behavior
'end_run' | 'return_rejection_to_model'Defaults to end_run

What happens when a request is rejected. end_run stops the run and marks it failed with termination_reason: "approval_rejected". return_rejection_to_model keeps the run paused until your client calls /resume; the agent then receives the rejection and can reconsider its approach.

approval_percent
integerDefaults to 100

Percentage of eligible calls that require approval, from 1 through 100. It applies only when the effective action_mode is require_approval. Calls outside the sampled percentage execute without human approval.

You set these by configuring tool action controls on the agent revision.

Reach for return_rejection_to_model when you want a reviewer to redirect the agent (“don’t email this customer, log a note instead”) rather than abort the whole run. Use end_run for hard stops.

Task tools use approval_percent directly. Integration and MCP attachments use default_approval_percent, with per-tool overrides in tool_approval_percents. Use 100 when every eligible call must be reviewed. Sampling is deterministic for a run, action control, and tool-call ID.

Gate selectively

The point of per-tool controls is that you gate the side effect, not the whole agent. Attach every tool an email agent needs — read the inbox, look up the customer, draft the reply, send it — but leave the reads and the draft on auto_run and set only the send tool to require_approval. Reading and drafting are preparatory and safe to run unattended; sending is the irreversible step a person should sign off on. The agent works right up to the edge of the consequential action, then waits.

What happens during a run

When an agent calls a tool set to require_approval:

1

The run pauses

The run status becomes waiting_for_human. The agent stops before the tool executes.

2

An approval request is raised

Rightbrain creates an approval request identifying the tool, with a sanitized argument preview, a hash of the full arguments, and the agent’s reason for requesting the call when available.

3

A human reviews it

A reviewer inspects the request and approves or rejects it over the API.

4

The request is resolved

Approval records the decision, after which the client calls /resume to execute the tool and continue the run. Rejection follows the tool’s rejection_behavior. A resumed run keeps its session and files.

A single run can pause and resume multiple times if it calls more than one gated tool.

Finding and resolving requests

List approval requests project-wide, or scope them to a single agent:

PurposeEndpoint
List pending requests in a projectGET …/task-agent/approval-request?status=pending
List requests for one agentGET …/task-agent/{agent_id}/approval-request
Get a single requestGET …/task-agent/{agent_id}/approval-request/{id}
ApprovePOST …/task-agent/{agent_id}/approval-request/{id}/approve
RejectPOST …/task-agent/{agent_id}/approval-request/{id}/reject
Resume a paused runPOST …/task-agent/{agent_id}/approval-request/{id}/resume

All paths are under https://app.rightbrain.ai/api/v1/org/{org_id}/project/{project_id}.

List and approve a request

Set RB_API_KEY, ORG_ID and PROJECT_ID in your environment. Run each command separately in the same terminal, reviewing the request before approving it.

  1. Find pending requests

    List requests awaiting a decision. Choose the request to review and its agent; pending requests may belong to different runs.

  2. Review the proposed action

    Replace the placeholders with that request’s agent ID and approval request ID. Read its status, tool, sanitized argument preview and agent reason before deciding.

    The agent reason is untrusted model-authored text. A human should check the intended action against the original request before running the approval command.

  3. Record the approval

    Run this only after the reviewer approves the proposed action. The empty JSON body is required; you can include a decision_note to explain the decision.

    This records approval but leaves the run paused. To reject, use /reject instead and follow the rejection behavior described below.

  4. Resume the same run

    Resume using the same approval request ID. This executes the approved tool and streams the rest of the existing run.

    Inspect the stream for done, error, or another approval_required event. Use the agent event reader in application code; the end of an HTTP stream alone does not prove completion.

curl --fail-with-body "https://app.rightbrain.ai/api/v1/org/$ORG_ID/project/$PROJECT_ID/task-agent/approval-request?status=pending" \
-H "Authorization: Bearer $RB_API_KEY"

The approve, reject, and resume endpoints all require a JSON body. Send an empty object ({}) when you have nothing to add; approve and reject both accept an optional decision_note.

Approving records the decision — it does not by itself continue the run. Call the /resume endpoint next to execute the approved tool and continue the run; /resume streams the remainder as Server-Sent Events, just like the original run call. Another gated call can pause it again.

To reject instead, call /reject. With end_run, the run immediately fails and cannot be resumed. With return_rejection_to_model, the run stays waiting_for_human: call the approval request’s /resume endpoint to let the agent handle the rejection. The rejected tool does not execute.

Recovering from a lost response

Read the approval request and run status before retrying a decision or resume. Repeating an already recorded decision returns 409; resuming an already completed or failed run also returns 409. If a decision succeeded but the run is still waiting_for_human, resume that request. Do not start a replacement run to recover a lost response: that would create separate work. Handle the resumed stream using the agent event reader.

Approve (or reject) and resume are separate operations: the decision is auditable on its own, and the resume replays into the same session with the run’s files intact.

The approval audit trail

Every approval decision is part of the run’s permanent record. A completed run carries the IDs of the approval requests it raised (approval_request_ids) and the embedded requests themselves (approval_requests) — each with its status, the tool it gated, who requested it (requested_by_user_id), who decided it (decided_by_user_id), and any decision_note the reviewer left. The full approval-request response also includes agent_reason when the model supplied a rationale for the proposed call. If a rejection ended a run, the run’s termination_reason records why.

The trail includes the sanitized argument preview, with recognized secret fields and credential-shaped values redacted. It does not embed the full tool arguments. Treat agent_reason as untrusted model-authored text, not as proof that the action is safe or necessary. See Observability & audit.