Pure-function evaluator for Glide’sDocumentation Index
Fetch the complete documentation index at: https://glide-9da73dea.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
AgentPolicyEnvelope. Given an envelope
and a PolicyRequest, evaluate() checks 14 independent policy axes and
returns a typed verdict with per-axis reason codes. No DB access, no network
calls, no side effects — the caller is responsible for fetching velocity
aggregates and for deciding whether the verdict enforces on Privy programmable
signing policy (EVM) or in a Redis state layer (Solana stateful axes).
The evaluator has default-deny semantics: any configured axis that cannot be
checked because required input is missing yields a deny reason rather than
silently passing. Axes that are undefined or carry empty arrays on the
envelope are skipped — “not configured” is not the same as “deny all” for most
axes (see the empty-allowlist table below).
Install
Why pure functions?
A stateful evaluator couples tests to DB fixtures or Redis state. A pure evaluator is a unit-testable function: every policy scenario is a data fixture in adescribe block. The caller fetches velocity aggregates from wherever they
live (Redis, Privy state, a Postgres materialized view) and passes them in as
VelocityContext. The engine doesn’t care which source they came from.
This also means the engine is chain-agnostic. On EVM, Privy programmable signing
enforces per_tx_max, counterparty_allowlist, and chain_allowlist natively.
On Solana, stateful axes (daily_cap, velocity_max_txs_per_day) enforce in
the router’s Redis layer. The same evaluate() call drives both paths.
The 14 policy axes
| Axis | Input required | Empty-array semantic |
|---|---|---|
chain_allowlist | request.counterparty.chain | deny when counterparty is present |
amount_cap_cents_per_tx | request.amount_cents | n/a (number) |
amount_cap_cents_per_day | velocity_context.amount_cents_spent_today | n/a (number) |
amount_cap_cents_lifetime | velocity_context.amount_cents_spent_lifetime | n/a (number) |
step_up_amount_cents | request.amount_cents | n/a (soft trigger) |
counterparty_allowlist | request.counterparty | open (any counterparty allowed) |
mcc_blocklist | request.mcc | no-op |
mcc_allowlist | request.mcc | open (any MCC allowed) |
geo_allowlist | request.geo | open (any geo allowed) |
time_window_start | request.requested_at_unix | n/a (optional) |
time_window_end | request.requested_at_unix | n/a (optional) |
velocity_max_txs_per_hour | velocity_context.txs_in_last_hour | n/a (number) |
velocity_max_txs_per_day | velocity_context.txs_in_last_day | n/a (number) |
velocity_multiple_of_baseline_threshold | velocity_context.txs_in_last_hour + velocity_context.baseline_txs_per_hour | n/a (number) |
chain_allowlist: [] + a counterparty present → deny. This is the one axis
that defaults to deny rather than open when empty, because chain restriction is a
required posture for any agent that can transact.
Basic evaluation
Handling deny
Any deny reason wins over a step-up trigger. The reasons array contains one entry per failing axis:Missing velocity context
If the envelope configures a stateful axis (daily cap, velocity limits) but the caller omitsvelocity_context, the evaluator returns deny with reason
nil_input_velocity_context rather than silently passing:
Narrowing detection for grant refresh
The package also exportsisNarrowingOrUnchanged, used by the
agent.grant.refresh MCP tool to determine whether a policy update is safe to
apply without a principal step-up:
- Amount caps: tighter = smaller number, or newly defined where previously absent.
- Allowlists: tighter = subset of the old list (every new entry must be in the old set).
- Blocklist: tighter = superset of the old list (removing a blocked MCC is broadening).
- Any single broadening on any axis →
narrowed: false.
Reading list
- AgentPolicyEnvelope schema — the canonical schema for the envelope this package evaluates.
@glideco/grant-wrapper— callsevaluate()indirectly;ctx.policy_versionfromverifyGrantfeeds the stale-policy detection path.- Money-safety contracts — the F-rules that this engine’s default-deny semantics reinforce.
- Source on GitHub