Approvals
When a policy verdict is "requires approval," the agent's action is paused until a human operator makes a decision. This is the human-in-the-loop mechanism that lets you enforce oversight on high-stakes actions without blocking low-risk operations.
Actions enter the approval queue from two policy modes:
- Require approval — every action of this type waits for human review, unconditionally.
- Conditional — the action auto-executes when its conditions pass; escalates to the approval queue when conditions fail. Use this when you want oversight only on out-of-bounds behavior — for example, auto-approve small deploys but require approval when the change count exceeds a threshold.
How Approvals Work
- An agent calls
execute()oral gatewith an action that matches a policy requiring approval. - AgentLattice creates a pending approval request, visible in the dashboard and via MCP tools.
- The agent receives a response indicating approval is required, along with an approval ID.
- An operator reviews the request and approves or denies it with an optional reason.
- The agent is notified of the decision. If using
gate()oral gate, the call unblocks automatically.
Every step is recorded in the tamper-evident audit trail, including who approved, when, and any reasoning provided.
Approval Policies
To require approval for an action type, create a policy with the require_approval effect. For conditional routing — where approval is only required when specific conditions fail — use the conditional effect instead (see Policies for the full comparison).
const al = new AgentLattice({ apiKey: process.env.AL_API_KEY });
// Actions matching "deploy.production" now require human approval
await al.execute("deploy.production", {
metadata: { service: "api", version: "2.1.0" }
});
// Returns: { verdict: "pending_approval", approvalId: "apr_..." }
from agentlattice import AgentLattice
al = AgentLattice(api_key=os.environ["AL_API_KEY"])
result = await al.execute("deploy.production", metadata={"service": "api", "version": "2.1.0"})
# result.status == "requested", result.approval_id == "apr_..."
The agent can then poll for the decision or use the gate() method which handles polling automatically.
Reviewing Pending Approvals
Via the Dashboard
Navigate to the Approvals tab in the dashboard. Each pending request shows the requesting agent's identity, action type, the policy that triggered the requirement, creation time, and time remaining before timeout.
You can act directly from the tile without navigating to the detail page:
- Approve once — approves this specific request and unblocks the agent. Future actions of the same type will still require approval.
- Approve forever — approves this request and turns off the approval requirement for the matching policy. Use this when a recurring action has been reviewed enough times that manual approval adds no value. Requires admin role. A confirmation step appears before the policy is changed.
- Deny — denies the request with a confirmation step. The agent receives a structured denial response.
Who can approve or deny: workspace members and admins. Viewer-role accounts can see the approval queue but cannot take action.
Via MCP
Ask your AI assistant:
"Show me pending approvals."
The assistant calls list_pending_approvals and presents the queue. You can approve or deny directly through the conversation:
"Approve the deploy-bot production deploy."
Via the SDK
// List pending approvals
const pending = await al.listPendingApprovals();
// Approve with reasoning
await al.approveAction(approvalId, {
reason: "Reviewed deployment manifest, changes are safe"
});
// Deny with reasoning
await al.denyAction(approvalId, {
reason: "Deployment window closed, reschedule for tomorrow"
});
# List pending approvals
pending = await al.list_pending_approvals()
# Approve with reasoning
await al.approve_action(approval_id, reason="Reviewed deployment manifest, changes are safe")
# Deny with reasoning
await al.deny_action(approval_id, reason="Deployment window closed, reschedule for tomorrow")
Policy Changes and Pending Requests
When you change a policy while agents have pending approval requests, AgentLattice automatically resolves those requests on the next polling cycle rather than leaving agents blocked.
If you change a policy from "require approval" to "allow": Any pending requests waiting for that action type are auto-approved within ~2 seconds. The agent unblocks on its next poll without requiring a human to manually approve something that no longer needs oversight.
If you deactivate or delete a policy: Same behavior — pending requests for that action type are auto-approved. A deactivated policy means the action is no longer governed; leaving agents blocked would be the wrong default.
This resolution is recorded in the audit trail with resolved_by: null (system resolution) and a note explaining why. It is not a security bypass — the policy genuinely changed, and the auto-approval reflects that new state.
If the policy still requires approval when the agent polls, nothing changes and the request remains pending.
Timeout Behavior
Every approval request has a configurable timeout. If no operator acts within the timeout window, the request is automatically denied. This prevents agents from hanging indefinitely on abandoned approval requests.
Default timeout: 30 minutes. Configurable per policy.
When a timeout occurs:
- The agent receives a denial with reason "approval_timeout"
- The
al gatecommand exits with code2(timeout) - The SDK
gate()method throws anApprovalTimeoutError - The timeout event is recorded in the audit trail
Escalation
If an approval request is not acted on within a configurable escalation window (shorter than the full timeout), AgentLattice can notify additional operators. Escalation is configured at the policy level:
- Email notifications to designated escalation contacts
- Webhook delivery to your alerting system (PagerDuty, Slack, etc.)
This ensures high-priority approval requests do not sit unnoticed during off-hours or busy periods.
Approval Audit Trail
Every approval decision creates an audit event containing:
| Field | Description |
|---|---|
| Action type | What the agent was trying to do |
| Agent identity | Which agent requested the action |
| Operator identity | Who approved or denied |
| Decision | Approved, denied, or timed out |
| Reasoning | Optional explanation from the operator |
| Timestamp | When the decision was made |
| Policy reference | Which policy triggered the approval requirement |
The audit chain is tamper-evident -- each event includes a hash linking it to the previous event. An auditor can verify the integrity of the entire approval history.
Pre-Flight Policy Checks
Before submitting an action that might require approval, agents can perform a dry-run policy check using can_i(). This lets the agent preview what would happen without creating an audit event or triggering an approval request.
from agentlattice import AgentLattice
al = AgentLattice(api_key=os.environ["AL_API_KEY"])
check = await al.can_i("deploy.production")
if check.allowed:
await al.gate("deploy.production")
elif check.needs_approval:
print(f"Will need approval under policy: {check.policy_name}")
# Optionally alert the operator before submitting
await al.gate("deploy.production")
This is useful in CI/CD pipelines where you want to fail fast if a policy will deny the action outright, rather than waiting for a timeout on an approval that will never come.
The equivalent REST endpoint is GET /policies/check. See the Python SDK reference for full usage.
Best Practices
- Use approval for irreversible actions. Deploys to production, data deletions, permission changes -- these benefit from a human checkpoint. Read-only actions and staging deploys usually do not need approval.
- Set reasonable timeouts. A 30-minute timeout works for most business-hours operations. For off-hours or low-urgency actions, consider longer windows. For emergency actions, shorter windows with escalation.
- Include metadata. The more context an agent provides in its action metadata, the faster an operator can make an informed decision. Include service names, version numbers, affected resources, and any relevant context.
- Use
al gatein pipelines. The CLI's gate command is purpose-built for CI/CD approval checkpoints. It handles polling, timeouts, and exit codes so your pipeline script stays simple.