Skip to content
Version v0.4 (draft)
ChangelogContributing

Objects

Mandate

What a user lets one agent do.

A mandate is what a user lets one agent do. It is issued by an operator or tenant on the user’s behalf, stored by the authorizer, and never signed or modified by the agent.

The user sets the rules for each agent, at each venue, in each currency. The authorizer only enforces them. It does not decide how wide a rule should be.

An agent MUST have exactly one live mandate (status active and expires_at in the future) for an intent to be judged. None is A2M_MANDATE_INACTIVE; more than one is A2M_MANDATE_AMBIGUOUS. Both fail closed.

Field Meaning
venues Allowlist of venue names. Required, non-empty.
instruments Optional allowlist of instruments. Empty or absent allows every instrument the mandate’s venues list as active.
price_collar_bps Maximum distance of the limit price from the reference price, in basis points. Also bounds the protect price of market orders on venues that need one.
max_open_orders Throttle on working orders.
max_orders_per_minute Throttle on order rate.
expires_at Must be in the future when issued.
reduce_only Restrict the agent to reducing orders.
allow_resize Shrink an order to what the limits allow (verdict RESIZE) instead of rejecting it.

The authorizer keeps the list of instruments each venue lists, refreshed from the venue (see the venue adapter’s ListInstruments). An instrument the venue no longer lists is delisted and refused, whether or not an allowlist names it. An authorizer MAY refuse to store an allowlist that names an instrument the venue does not list as active.

Amounts live in limits, one row per venue and currency. An order is checked only against the row for its venue and its instrument’s quote currency. If there is no such row, the order is refused (A2M_LIMIT_MISSING). There is no FX: a USDC row and a USD row never add up.

Order size is capped by notional only (max_order_notional, in the row’s currency). There is no per-instrument quantity cap, so one rule works the same for a BTC perpetual and a share of stock.

"limits": [
{"venue": "hyperliquid", "currency": "USDC", "max_order_notional": "35",
"position_limit_notional": "80", "daily_loss_limit": "5", "instruments": ["BTC", "ETH"]},
{"venue": "alpaca", "currency": "USD", "max_order_notional": "500",
"position_limit_notional": "2000", "daily_loss_limit": "100"}
]
Row field Meaning Default
venue, currency Which orders the row covers required
max_order_notional, position_limit_notional, daily_loss_limit In the row’s currency. Daily loss is realized PnL in that currency for the UTC day required
approval_above_notional A human approves orders above this notional none
budget_id Sub-budget the row draws on; must be in the row’s currency none
instruments Optional narrower allowlist for this venue. Empty allows every instrument the mandate allows on it empty
allow_short Allows opening or extending a short of whole shares in a shortable instrument, held as 100% cash collateral. Otherwise A2M_SHORT_DISABLED false
options_level 0 to 3; see Options 0
max_leverage Only 1 is accepted until the authorizer models margin. A value greater than 1 is refused 1
short_collateral_ratio Share of short notional held as collateral. A value below 1 is refused until a margin model exists 1

The old flat shape (max_order_notional, position_limit_notional, daily_loss_limit, approval_above_notional, budget_id on the mandate itself) is still accepted when every instrument the mandate allows is quoted in one currency. The authorizer turns it into one row per venue. Reads return limits, plus the flat fields when the mandate has a single row.

max_order_qty, from earlier drafts, is accepted and ignored, both flat and per row. It is not enforced and not returned.

options_level on a limit row sets which option orders may open positions at that venue:

Level Allows
0 No options
1 Covered calls (the shares held) and cash-secured puts
2 Level 1, plus buying calls and puts
3 Level 2, plus spreads (mleg) with defined risk

The authorizer caps the effective level (the reference deployment caps it at 2). Closing an option needs no level. Option orders are capped by their maximum loss, which is also what they hold. Calendar and diagonal spreads are not supported.

A mandate is always checked together with reference data the authorizer holds:

  • Instrument: lot size, tick size, currency, trading calendar (regular sessions, extended sessions, holidays and early closes) and status.
  • Protected unit: one product class on one venue, with its market rules and broker rules (accepted order types and times in force, minimum and maximum notional).

A product class the authorizer has no risk treatment for fails closed (A2M_UNSUPPORTED_PRODUCT).

How a mandate is requested from and confirmed by the user is not standardised yet. In the reference implementation an operator API issues and revokes mandates. A user-facing mandate request flow is planned.