Skip to main content

Approval Workflow

Concepts

A developer hits a policy, model, or budget limit and wants a bounded, temporary way past it. This page explains the request → approve → grant → expire/revoke lifecycle that handles that, and when a decision needs more than one approver.

The lifecycle

Every request an admin can approve goes through the same four stages:

  1. Request — a developer submits a request (from the Builder Portal, the API, or inline in the tool that was blocked), naming what they need and why. AIControls immediately notifies the approver audience.
  2. Approve or deny — an admin reviews the request in Security → Approvals and decides. A denial ends the lifecycle; an approval moves to the next stage.
  3. Grant — approval takes effect immediately: a policy exception is granted, a model becomes usable, or a session's budget increases, depending on the request type (see Request types below).
  4. Expire or revoke — grants that carry an expiry date lapse automatically with no admin action required. An admin can also revoke a still-active grant early; see Revoke a granted exception — there is no dedicated admin UI for this yet, so it's done via the admin API.

Each stage fires a notification (see Notifications) so the requester and approvers stay in sync without polling the UI.

note

Held calls are a different thing on the same page. Security → Approvals also lists live MCP tool calls and LLM requests that an Approve policy has parked mid-flight — those are not requests a developer submitted, and they have no grant/expire stage; they simply resume or stop. Identical held calls arriving while an approval is still pending are consolidated into that one entry, so one decision releases (or stops) all of them, while anything arriving after the decision needs a new approval. See Consolidated approvals and Decide on a held call.

Requesting inline, without leaving the tool

Stage 1 does not have to happen in the portal. When a policy blocks a developer, the denial itself can carry the offer of an exception, so the request is made from inside the conversation that hit the wall:

  1. Violation — a policy denies a chat request, a model, or an MCP tool call.
  2. Offer — instead of a bare error, the developer gets a message naming the policy, explaining what was blocked, and telling them how to ask. On the chat surfaces that is a reply grammar (request exception: <why>); on the MCP surface it is a machine-readable block plus two governance tools the AI tool can call. Both carry a short-lived, signed offer.
  3. Request — the developer replies (or the tool calls aigov__request_exception). AIControls files a pending request and answers with its status. The blocked action does not run — a request is never a grant.
  4. Approval — the request lands in Security → Approvals exactly like a portal-submitted one, and an admin decides. The approver's identity is recorded on the decision.
  5. Grant and expiry — approval creates the same time-boxed grant, and it lapses or is revoked the same way (stages 3 and 4 of the lifecycle above).

Retrying the same blocked action while the request is still open returns its live status — the request id, and once decided, the outcome and who decided it — rather than offering again. That keeps a single request per developer per policy no matter how many times the block re-fires.

See Request an exception inline for the developer-side steps on each surface.

note

The offer is authenticated; the conversation is not. The offer AIControls attaches to a denial is signed and bound to the policy (or model) that produced it, the identity it was issued to, and a ten-minute window. Redeeming one can only file a request for that exact target, attributed to that identity. Text a developer — or injected content in a document or a web page — writes into the conversation cannot forge one, and cannot change what an existing one asks for. The justification is the only part of the request that comes from the conversation, and it is stored and displayed as data for the approver to read.

Per-developer limits (5 unresolved requests, 20 per hour) bound how much review load any one identity can create.

Single- vs multi-approver co-sign

Most requests need only one approver — whoever reviews it first decides its outcome. Higher-risk requests can require co-sign: two or more specific approvers must all approve before the grant is final. While co-sign is pending, the request shows as Under Review in the Approvals list with a checklist of who has and hasn't decided yet.

note

The first approver's decision (the one who names the additional required co-signers) creates the grant immediately — it's live and enforced for the rest of the review window, not just once every co-signer has decided. Co-sign is a review-and-veto period on an already-active grant, not a hold before one exists. This is why a later denial (below) revokes rather than simply declining to create.

Co-sign resolves as follows:

  • Any approver denies → the request is immediately denied, regardless of how the other approvers were leaning, and the grant created when co-sign started is revoked — access reverts as if it had never been granted.
  • Every required approver approves → the request is marked approved; the grant created when co-sign started remains in effect unchanged.
  • Some approvers still pending → the request stays Under Review; the grant stays active and nothing else happens until the quorum is reached one way or the other.

Only the approver named in a decision can record it — the request/approve/deny API rejects a decision submitted by anyone else, so approvers can't act on each other's behalf.

Because two co-signers can act within moments of each other, AIControls guarantees the request completes exactly once no matter how close together the deciding decisions land — you'll never see a double approval, a double revoke, or a duplicate notification from a co-sign race.

Request types

Request typeWhat approving it doesDurability
ExceptionGrants a time-bounded exception to a named policy for the requesting developerExpires at the configured time, or until revoked
Model accessGrants the requested model to that developer via the same config-target exception mechanism a policy exception uses, on top of their team/org ceilingNo expiry is set by default, so the grant persists until revoked from Security → Approvals → Granted or the admin API — see Revoke a granted exception. (Grants approved before this mechanism shipped are separate, durable per-developer overrides — still revocable via the admin API DELETE /api/v1/developers/{id}/model-overrides.)
Session budget top-upAdds a one-time dollar amount to the requesting developer's current session's spend cap onlyEphemeral — scoped to that one session; see Grant a session budget top-up
Extend sessionExtends the requesting developer's current session by the requested number of hoursApplies once, to that session
Resume sessionReactivates a paused session (e.g. after an anomaly auto-pause)Applies once
note

"Session budget top-up" here is a different mechanism from the durable, org-wide budget top-up described in Set a Budget → Exceptions, which raises a team or user's monthly budget cap via a config-targeted exception rather than a single session's cap. Use this workflow when a developer just needs a bit more headroom to finish what they're doing right now; use the Cost Governance exception flow for a durable, month-over-month adjustment.

Policy exceptions are the request type most often needed at scale — see Policies, Set a Budget, and Restrict Network Egress for the policy-, budget-, and egress-specific exception mechanics each of those pages documents in more depth.

Notifications

EventFires whenRecipient
exception_approval_requestedA request is submitted and needs approver actionAdmins
exception_grantedA grant is created — single-approver decision or the final co-sign approvalThe requesting developer
exception_deniedA request is denied — by a single approver or any co-signerThe requesting developer
exception_expiredA granted exception's expiry time passesThe requesting developer
exception_revokedAn admin revokes a still-active grant earlyThe developer, plus an admin audit copy

Configure which channels (in-app, email, Slack/Teams/webhook) carry each of these from Settings → Notifications → Routing — see the Generic Webhook event type table for the full list of event types AIControls can deliver.

See also