> ## Documentation Index
> Fetch the complete documentation index at: https://usenaive.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Approvals (governance)

> How human-in-the-loop approval is enforced and executed.

Approvals gate sensitive agent actions behind a human decision, then execute
them server-side so the agent never has to retry.

## The gate

Every sensitive route delegates to `runGuardedAction(req, { actionType, payload })`:

1. Resolve the subject (`tenant_user` + Account Kit) and the actor.
2. `resolveApprovalRequirement(kit, actionType)` decides if approval is needed:
   start from the built-in `DEFAULT_APPROVAL_ACTIONS` set, then apply the
   per-primitive `requiresApproval` override on the kit.
3. **Agent + required** → freeze the request as a `pending` row, return
   `202 { status: "pending_approval", approval_id }`.
4. **Human session, or not required** → execute immediately.

The same gate runs for MCP tools (via `mcpGuard`) so an agent can't bypass it by
switching transports.

## Deferred replay (single execution path)

There is one executor registry mapping `action_type → service call`
(`cards.create → createCard`, `domains.purchase → purchaseDomain`, …). Both the
immediate path and the post-approval path dispatch through it, so a frozen
action runs exactly as it would have live.

```mermaid theme={"theme":"css-variables"}
flowchart TD
  A["Agent call (API key / MCP)"] --> B[runGuardedAction]
  B --> C[assertKitAllows]
  C --> D{requiresApproval?}
  D -->|"agent + yes"| E[freeze pending approval]
  E --> F["202 pending_approval"]
  D -->|"no / human"| G[executor registry]
  H["Approver (dashboard / CLI / app)"] -->|approve| I[executeApproval]
  I --> G
  G --> J[result stored, status executed]
  H -->|deny| K[status denied]
```

## Data

Pending and resolved approvals live in the `approvals` table, scoped to a
`tenant_user`: `action_type`, `primitive`, the frozen `payload`,
`requested_by_*`, `status` (`pending | executed | failed | denied | expired`),
`result` / `error`, and `resolved_by_*`. Creating, approving, and denying each
write an `activity_events` row (`approval.requested`, `approval.approved`, …)
and publish a live event for dashboards.

## Approvers

Anyone authenticated for the company can resolve an approval: developers via the
dashboard or CLI (any of their tenant users), and end-users via your app
(scoped to their own `tenant_user`). PII-heavy payloads (e.g. KYC members) are
stored minimally and re-fetched at execution time.
