Skip to main content
Agents can research, propose strategies, and run backtests autonomously. But deploying capital — even paper capital — requires a human to approve. This is enforced at the code level, not just by policy.

The core rule

An agent can request promotion to paper trading (deploy:paper scope). Only a human can approve it (approvals:decide requires a human actor). An agent calling decide_approval is rejected.
This split is the boundary between the agent’s autonomy and the human’s authority. The agent does the research; the human flips the switch.

Promotion flow

1

Agent requests promotion

The agent calls request_promotion (MCP) or POST /api/runs/{id}/promote with scope: "paper". This creates an approval record in the pending state and emits an approval_requested trace event.
2

Human is notified

The web UI shows a pending approval badge. The human can review the run, its artifacts, and the strategy spec before deciding.
3

Human decides

The human calls decide_approval (MCP) or POST /api/approvals/{id}/decide with decision: "approve" or "deny". This emits an approval_decided trace event.
4

System acts

If approved, the run transitions to the paper-trading lifecycle. If denied, the run stays in its prior state and the denial is recorded.

Approval state machine

pending → approved
        → denied
StateMeaning
pendingRequest created, awaiting a human decision.
approvedHuman approved. Promotion proceeds.
deniedHuman denied. Run is not promoted.
An approval is single-shot: once decided, it cannot be reopened. A new promotion request creates a new approval record.

REST endpoints

MethodPathDescription
GET/api/approvalsList approvals (optional ?run_id=, ?state=).
POST/api/approvals/{id}/decideApprove or deny. Human-only.
See Approval endpoints for full request/response examples.

MCP tools

ToolScopeActorDescription
list_approvalsapprovals:readagent or humanList pending/all approvals for the tenant.
decide_approvalapprovals:decidehuman onlyApprove or deny a pending request.
The decide_approval tool checks actor_kind. If the caller’s principal is an API key (agent), the call is rejected with 403. Only Clerk-authenticated human sessions can decide.

Trace events

Every approval action is traced and streamed over SSE:
Event typeEmitted whendata includes
approval_requestedAgent requests promotionrun_id, scope, requested_by
approval_decidedHuman approves or deniesapproval_id, decision, decided_by
See Trace events for the full event contract.

Audit trail

Every approval is permanent and auditable:
  • The request records the agent’s principal, the run id, the scope, and the timestamp.
  • The decision records the human’s principal, the decision, and the timestamp.
  • Both are written to the shared database with tenant_id scoping.
  • The trace events are persisted and replayable via Session replay.
An approval cannot be silently forged. The decided_by field is stamped from the authenticated human principal — an agent cannot set it.

Scopes involved

ScopeWho has itWhat it allows
deploy:paperagentRequest promotion to paper trading.
approvals:readagent, humanList and inspect approvals.
approvals:decidehumanApprove or deny a pending request.
deploy:live is unissuable. No principal — human or agent — can be granted live deployment. This is intentional. See Scopes.