GVNR
GVNR is the easy half of an idea. If you have run it and watched it refuse something, you already understand the hard half, because it is the same question asked somewhere else.
GVNR asks it on your machine, about an agent you are running:
May this agent do this, right now?
Enforcer asks it inside your application, about whoever is calling:
May this caller do this, to this thing, right now?
Same shape. Same three outcomes. The actor changes from an agent on your laptop to a user, a tenant, a service or an agent hitting your API, and the thing being protected changes from your token budget and your shell to your customers' data and your money movement.
| GVNR | Enforcer | |
|---|---|---|
| Where it runs | Your machine, local | A service your application calls |
| Who is asking | An AI agent you started | A user, tenant, service or agent |
| What it protects | Spend, and what the agent may do | Actions on your own resources |
| How you ask | A proxy or a pre-execution hook | POST /authz/check |
| What comes back | allow, deny, escalate | allow plus a reason |
| Who signs the caller in | Nobody, it is your own machine | Enforcer does, it is one service |
| Price | Free and open | Commercial |
GVNR, you set it up once and it decides silently on every call:
export ANTHROPIC_BASE_URL=http://localhost:4000
# over budget or grounded, the agent gets HTTP 429
Enforcer, you ask it at the point the action happens:
curl -sS -X POST "$BASE/authz/check" \
-H "Authorization: Bearer $TOKEN" \
-d '{ "policy_id": "<your rule>",
"action": "issue",
"resource": { "type": "payment", "id": "pay_123",
"tenant_id": "<its tenant>" },
"contexts": { "amount": 820 } }'
# -> { "success": true, "allow": false, "reason": "over_refund_ceiling" }
The reason is the part worth noticing. A refusal that says why is the difference between an agent that reports "that failed" and one that can tell the user what would make the answer yes.
These are not the same product with two price tags, and it is worth being straight about where each is weaker.
Every GVNR decision is hash-chained on your machine, and editing one visibly breaks the chain. Enforcer returns the reason and the policy_id that decided, and you log those yourself at your call site. Its /audit-events endpoint is the identity and administration trail, sign-ins, API keys, roles, tenants, and it does not record authorization decisions. If you want an Enforcer decision trail, you build it from what the check hands back.
On your own machine there is no question of identity. Inside an application there is nothing but. Enforcer signs the caller in and holds tenants, roles and groups, so the policy is handed an already-resolved caller rather than being passed claims it has to trust. That is the whole reason it is one service rather than two.
A spend cap has no opinion on rm -rf, and GVNR does, because the hook sees the action before it runs. Enforcer is not watching your shell. It is answering whether this caller may touch this row.
GVNR asks you at the moment it matters. Enforcer has no shadow or dry-run mode either: a policy created inactive is stored and simply not evaluated. In both cases you find out what a rule does by turning it on.
GVNR is enough while the risk is on your own machine. The question changes when other people start using what you built:
At that point you are asking GVNR's question about your own product, and that is what Enforcer is.
There is an open sandbox, no sales call. Sign in and get a first allow and deny, or point an agent at it and let it set itself up from the setup page. Neither one requires GVNR, and GVNR does not require Enforcer. They are the same idea at two layers, and plenty of people will only ever need the free one.