Action Control
Action Control concepts
How an action is checked, decided, executed, verified and recorded: decision vs outcome, idempotency, the Unknown state and evidence classes.
Agent Action Control (formerly Agent Action Integrity) is a control layer between your AI agents and the systems where money moves. Every business action an agent proposes (a refund, a customer credit, a discount, a subscription change, an order cancel) is checked against your rules before it runs, executed through an Audon connector, its real outcome is verified at the provider, and the evidence is kept. Audon controls the actions, not the model, so it works with any model, agent or framework.
integrity.execute().Action Gateway (MCP)Give an agent its actions as MCP tools.Policies and approvalsRules in plain language, run as deterministic code.The pipeline
One call, integrity.execute, runs the whole path. Authorization and execution are coupled: the checks and the reservation of the action run in one transaction under locks on the idempotency key and the resource, and the provider context is read under the same lock. A second request on the same order waits and then sees the first one in flight.
identity → permission → business rules (fresh provider context)
→ financial limits → duplicates → approvals → decision
→ execute via connector → verify (re-read) → evidence| Check | What it checks | On failure (enforcing) | Monitoring |
|---|---|---|---|
| Identity | The agent key’s agent; an optional agent claim must match it. | Denied | Denied (built-in) |
| Permission | The agent is active, the action is in its allowed_actions, and an execute-mode connector supports it. | Denied | Denied (built-in) |
| Business rules | Built-in rules per action type on fresh provider data (a refund ≤ captured − already refunded − refunds in flight; not disputed; not already cancelled; currency; subscription state). Without provider context the check fails closed. | Denied | Denied (built-in) |
| Your policy | Your deny rules and a default_effect: deny. | Denied | Would deny (shadow) |
| Financial limits | Your limit rules: per-action cap, rolling budget, velocity; per agent, customer, resource or organization. | Denied or approval | Would deny (shadow) |
| Duplicates | The same action type on the same resource or order, for the same amount, within 72 hours: done, in flight or waiting. | Denied | Denied (built-in) |
| Approval | A require_approval rule matches. | Pending approval | Would need approval (shadow) |
Decision and outcome
Two separate fields, so an action is never “approved but failed” in one status.
- Decision:
allowed,denied,pending_approval, orwould_deny(monitoring mode: one of your own policies would have denied it; the action ran). - Outcome:
not_executed,awaiting_approval,executing,completed(verified by re-reading the provider object),failed, orunknown.
A denial is a result with a code and a reason (for example already_fully_refunded, “Order already fully refunded.”), not an error. Relay it to the person; don’t try another way to do the same thing.
Idempotency
Every execute call needs an idempotency key (8–200 characters), as an Idempotency-Key header or idempotency_key. Use one key per intent and reuse it on every retry of that intent.
- The same key returns the original action’s current state with
replayed: true. It never executes again. - The same key with a different body is
idempotency_conflict. - Each attempt is sent to the provider with its own key,
audon_<action id>_<attempt>(Stripe also getsmetadata[audon_action_id]; Shopify refunds use@idempotentand a note marker), so Audon can find it there later.
The Unknown state
When the provider’s answer doesn’t say what happened, the outcome is unknown. Audon never retries it blindly: it asks the provider first.
| Provider answer | Outcome | Retry |
|---|---|---|
| 2xx | completed after a re-read, or executing while pending | — |
| 4xx (including 429), or refused before sending (DNS, connection refused) | failed, retry_safe: true | Allowed |
| Timeout or reset after sending, 409, 5xx, or a webhook 2xx without a status | unknown | Not until resolved |
A reconcile job looks the action up at the provider, first after 30 seconds and then backing off up to 24 hours (12 attempts): Stripe refunds by charge and audon_action_id, credits by balance-transaction metadata, discounts by their deterministic coupon id, subscription changes by the subscription’s state; Shopify refunds by the note on the order’s refunds, cancellations by cancelledAt, discount and gift card codes by their deterministic code; and Webhook connectors through your status endpoint. Found means completed. Reported absent twice, at least a minute apart, means failed with retry_safe: true. Anything else stays unknown and counts as exposure. A retry re-checks business rules and duplicates under the lock and sends the next attempt with a new provider key.
Monitoring and enforcing
An organization starts in monitoring with its first live action. The mode only applies to your own policies (limits, deny rules, default deny, approvals): in monitoring they run in shadow, recorded as would_deny (or an allowed action with decision_code: would_require_approval), and the action still runs. A person switches the organization to enforcing, or sets a single agent to enforce.
Built-in safety checks enforce in every mode, from the first action: the agent key and claimed agent, a paused agent (kill switch), an action the agent isn’t allowed, no execute connector or provider context, the built-in business rules (a refund above the refundable remainder; a refund on a fully refunded or disputed payment; cancelling an order or subscription that is already cancelled), duplicates, and the Unknown state (nothing is retried until reconciliation proves the outcome). A blocked duplicate in monitoring is a normal denied decision with the usual evidence class. The checks record which of them were enforcing and which ran in shadow (basis and enforcement on each check, decision_basis in the evidence).
Agents and agent keys
An agent in Audon is a record for an AI agent you already run: your support bot, a sales agent, a coding agent. Audon doesn’t build or run agents. Registering one under Agents gives it an identity and its own key, so Audon can:
- Check its business actions (refunds, credits, discounts, cancellations) against your rules before they run. This is Agent Action Control.
- Attribute AI spend to it: map the provider projects, workspaces or API keys it uses, and its model spend from Agent Spend Optimization shows on its Cost tab. No agent key needed for this.
- Pause it instantly: one click denies every action it proposes until a person resumes it.
How an agent connects
- Create its agent key on the agent’s Keys tab (shown once).
- Add the key to your agent: as MCP tools through the Action Gateway, or with the SDK or one HTTP call. The Keys tab has a ready snippet for each client.
- Send a test action. It runs through the Test connector and moves no money.
The Agents list shows each agent’s connection: Not connected yet (no call with its key so far), Connected with when Audon last saw it, Spend only (its spend is mapped but it hasn’t sent an action) or Paused. An agent that isn’t connected sends nothing to Audon, so nothing is checked: its actions go straight to your systems until you route them through Audon.
Under the hood, an agent is a platform object (agt_…) with a name, an owner, an environment, its allowed actions and a mode. It can carry cost attribution (provider project, workspace or API key ids), so its spend from Agent Spend Optimization shows next to its actions.
- Agent keys (
aa_agent_…) are bound to one agent and carry onlyintegrity:execute. They stop working when revoked, when they expire or when their creator leaves the organization. - No role holds
integrity:execute: people, admin API keys and OAuth grants can never execute an action. Agent keys can never approve, change policies or read other agents’ evidence. - Pause agent is the kill switch: every action the agent proposes is denied until a person resumes it.
Evidence classes
The same grammar as Agent Spend Optimization: potential and confirmed are never added together, and only confirmed is green.
| Class | Meaning |
|---|---|
observed_action | The action was recorded with its decision and outcome. |
flagged_action | An audit finding or anomaly, such as a possible duplicate refund. |
potentially_prevented_loss | A blocked or held attempt, at its amount at risk. Retries of the same intent count once: five blocked retries of a $450 refund are $450. |
confirmed_prevented_loss | Proof the action would otherwise have executed and caused loss: for a duplicate, the connector confirms the earlier action as completed and the provider would have accepted a second one (for example a customer balance credit). A reviewer can also confirm it, with a reason, and is named on the record. |
outcome_unknown | The provider’s state is not known yet: exposure, neither loss nor benefit. |
suspected_loss, confirmed_loss | Historical audit only: losses that already happened. Never called prevented. |
Blocked is not the same as prevented
A blocked attempt alone is no proven financial benefit. In the $450 example, the order was already refunded in full and Stripe would have refused a second refund too, so the block is potentially prevented loss, not confirmed.
Evidence
Each action keeps an append-only list of evidence records (proposed, each check, the decision, the execution attempts, the verified outcome), hash-chained over canonical JSON; the database refuses to change them. Every record references the active policy versions and the rules that matched. Admin changes go to the activity log, cross-linked by action id.
Security model: route every action through Audon
The controls hold for the actions that pass through them. Give the agent an agent key and the Action Gateway or the SDK, and remove its direct access to the same APIs (for example a Stripe secret key in its environment). Otherwise the agent can bypass the controls. Setup, the gateway and every connector response repeat this.
Money is always integer minor units with a currency ({ amount_minor: "45000", amount_decimal: "450.00", currency: "USD" }), never summed across currencies. Plans: see pricing.
Last updated