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.Promotion flow
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.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.
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.Approval state machine
| State | Meaning |
|---|---|
pending | Request created, awaiting a human decision. |
approved | Human approved. Promotion proceeds. |
denied | Human denied. Run is not promoted. |
REST endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/approvals | List approvals (optional ?run_id=, ?state=). |
POST | /api/approvals/{id}/decide | Approve or deny. Human-only. |
MCP tools
| Tool | Scope | Actor | Description |
|---|---|---|---|
list_approvals | approvals:read | agent or human | List pending/all approvals for the tenant. |
decide_approval | approvals:decide | human only | Approve 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 type | Emitted when | data includes |
|---|---|---|
approval_requested | Agent requests promotion | run_id, scope, requested_by |
approval_decided | Human approves or denies | approval_id, decision, decided_by |
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_idscoping. - 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
| Scope | Who has it | What it allows |
|---|---|---|
deploy:paper | agent | Request promotion to paper trading. |
approvals:read | agent, human | List and inspect approvals. |
approvals:decide | human | Approve or deny a pending request. |
deploy:live is unissuable. No principal — human or agent — can be granted live deployment. This is intentional. See Scopes.Related
- Scopes — the full capability model
- Approval endpoints — REST API reference
- Run endpoints — the promote endpoint
- Trace events —
approval_requestedandapproval_decided