Navigate docs

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

  1. An agent calls execute() or al gate with an action that matches a policy requiring approval.
  2. AgentLattice creates a pending approval request, visible in the dashboard and via MCP tools.
  3. The agent receives a response indicating approval is required, along with an approval ID.
  4. An operator reviews the request and approves or denies it with an optional reason.
  5. The agent is notified of the decision. If using gate() or al 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 gate command exits with code 2 (timeout)
  • The SDK gate() method throws an ApprovalTimeoutError
  • 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 gate in 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.