Give your autonomous agents granular control over execution: financial, operational, and regulatory control for every agent you run.
AgentOps is a spending firewall that sits in front of AI agents. Before an agent can pay for anything, trade anything, or deploy anything on Casper, AgentOps checks it against one company-wide budget and rulebook, reserves the money, and only then produces a signature. Every approval that actually settles is stamped onto Casper through our own contract — live on mainnet.
Infra/API · Security · Casper Network · DeFi · AI Agents
Live app ·
MCP endpoint ·
x402 services ·
npm i @agops-labs/sdk ·
Mainnet contract
This repository is the client — console, landing page, and visual builder. The engine, contracts, and SDK live in Casper-AGOPS.Server.
A company gives an employee a corporate card, not the bank account: a limit, a list of approved merchants, a receipt per swipe.
AI agents today get the bank account — a private key sitting inside the agent process, buying APIs, pulling paid data, placing trades, pushing transactions. If that agent is tricked, buggy, or simply over-eager, nothing stands between it and the money.
AgentOps is the corporate card system for AI agents, and Casper is what makes the receipts real.
The clearest way to explain it is to walk through what actually happened when we ran it.
The job we gave a team of AI agents:
"Evaluate a 5 CSPR swap on CSPR.trade. Buy whatever market data you need. Report price, liquidity, slippage, fees, and risk. Wait for me to approve before executing anything."
One job, three different ways to spend money. That's the point.
It called casper_guard_policy_check — a dry run, like checking a card limit before you swipe. Six checks in one call:
- Is this agent still active?
- Is trading an allowed action for it?
- Is this specific swap inside its scope?
- Is this network permitted?
- Is 5 CSPR under its per-transaction limit?
- Is it under the organization ceiling?
Passed. No money moved.
Each paid endpoint returned a real HTTP 402 naming the asset (WCSPR, a CEP-18 token), the recipient, and the price. AgentOps evaluated policy and, only on ALLOW, produced the PAYMENT-SIGNATURE header the service demands.
| Agent | Bought | Paid | Settled on Casper |
|---|---|---|---|
| Trade agent | Order-book depth | 2 WCSPR | e1541674… · block 8434250 |
| Risk agent | Risk score | 3 WCSPR | ac53efe1… · block 8434251 |
- Both are real
transfer_with_authorizationcalls on the WCSPR contract - Broadcast by the CSPR.cloud hosted facilitator — not by us. The rail is Casper ecosystem infrastructure, not something we simulated
- Data came back real: best ask $0.05015 · spread 60 bps · risk 32/100 LOW · max size 7.47 CSPR
- Without the header the service returns 402 and refuses to serve. The block is structural, not advisory
We took the trade agent's perfectly working credential and tried to buy the risk agent's data with it:
{
"outcome": "DENY",
"reason": "service_not_allowed",
"policy_id": "…@v2",
"allowed_resource_ids": ["svc:order-book"]
}A working key is not the same thing as permission. That is the entire product in one response.
Each agent transacts from its own Casper account. A fresh one holds no WCSPR and has no purse, so settlement failed on-chain with error 60001. The fix runs after the budget reservation passes and never before:
- Wrap CSPR
- Dust transfer to create the agent's purse →
25215187… - Move 4 WCSPR into the agent's account →
5d4ca4fc…
The agent is funded for exactly what it was just authorized to spend, at the moment it needs it — never a standing balance it could drain. Policy first, money second.
Report written, agent paused. No swap authorization existed. Nothing was reserved. Only after the human approved did it come back and request the 5 CSPR swap.
When a bank approves a card transaction it doesn't wait for the merchant to charge you — it places a hold immediately so the same money can't be spent twice. AgentOps does the same:
- Atomically reserves 5 CSPR from the organization budget before returning the authorization
- The reservation and the solvency check run inside a single script, not next to each other — no gap between "checked" and "acted" for a second agent to slip through
- Approval is never treated as spending. It's a temporary, policy-bound reservation, open until we learn what really happened
CSPR.trade returned no transaction hash. Twice. AgentOps classified both attempts as terminal failures and released both holds:
- 0 CSPR of swap principal debited
- 0 holds left stuck
- 0 failures reported as settled
- The earlier 5 WCSPR of purchases still correctly booked
- Full history exportable as audit JSON
We lead with a failure deliberately, because it's the insight the product is built on:
Saying "yes" is the easy half. Real financial autonomy needs money reserved before the signature and an explicit recovery path after an execution you can't confirm. A system that only says yes or no leaks money the moment reality gets ambiguous.
The settled authorization was hashed and anchored to our GuardRegistry contract — including a real anchor on Casper mainnet: block 8350189, decision cgd_c8030d99…, hash sha256:6a5fce4f…, 0.6806 CSPR gas against a 3 CSPR limit.
To be exact: we anchor settled authorizations only. Denials and failures stay in the off-chain audit trail and export as signed evidence — we don't burn gas recording things that never moved money.
The loop, end to end:
Intent → Policy check → Budget hold → Fund the agent → Sign
→ Execute → Reconcile what really happened → Anchor the successes to Casper
The operator-facing surface: the console where a human sets the rules, watches decisions arrive, and funds the fleet.
| Area | What it does |
|---|---|
| Console | Treasury, agents, policy, decision stream, audit export, members |
| Visual builder | Describe a fleet in plain English → graph → deploy real agents with enforced policy |
| Landing | Product story and live demo entry point |
| Wallet flows | CSPR.click deposit and delegated-key grant, signed in the user's own browser |
An operator describes a fleet in plain English, watches the graph assemble, edits it, clicks Deploy. It's a config surface, not a workflow engine — no node ever "runs." Deploy does exactly three things:
- Creates real agents with one-time keys
- Writes enforced spend policy through the same code path the firewall checks on every authorization — no second enforcement path to trust
- Returns unsigned key-grant handles for the user to sign in their own browser. The server signs nothing here
Policy is attached before any key exists on-chain, so an agent never holds authority without a spend cap already on it.
The console never sees the user's master key. A grant is built server-side as an unsigned deploy, handed to the browser, and signed with CSPR.click. The master key never leaves the user.
Most spending controls work per-wallet or per-transaction. Companies don't work that way — they have one budget, and it doesn't matter which door the money leaves through.
| Rail | AgentOps checks |
|---|---|
| x402 purchase | Amount · real recipient · service scope · velocity · budget |
| CSPR.trade swap | Amount · slippage · risk label · action scope · budget |
| Casper deploy | Network · contract and action scope · amount · budget |
An agent cannot exhaust its allowance buying data and then quietly keep spending the same budget through the trading rail. That gap is precisely where an autonomous agent gets expensive.
An agent holds an API key. Signing happens server-side inside a vault, after the policy check. There is nothing for the agent to sign with — so there is no path around the firewall.
Instead of our server holding a key, each agent gets its own weight-1 key on the user's own Casper account. Full lifecycle, proven on testnet:
| Step | Transaction | |
|---|---|---|
| D1 | Grant — agent key at weight 1, master raised to 3 | 97c50ddf… |
| D2 | Agent transacts completely alone — signed with only the agent's key | 426495a5… |
| D3 | Revoke — agent key removed | 0a6cce33… |
| D4 | The node itself rejects the agent: "invalid associated keys" |
(rejected — no hash, by design) |
D4 is the payoff: after revocation the agent is stopped at the Casper protocol level, not by our policy. Our backend could be offline, compromised, or gone, and the agent still cannot spend.
One detail worth a moment: the obvious implementation bricks the account. The agent must transact alone (deployment threshold 1) but must never touch key management (threshold 3). Naively adding the agent at weight 1 and raising key-management to 3 leaves master(1) + agent(1) = 2, which can never reach 3 — so nobody can ever manage keys on that account again. Our grant raises the master's own weight to 3 in the same deploy, so the master alone still clears the bar.
A deliberately tiny contract: anchor_decision, get_anchor, total_anchored. About 55 lines.
- Append-only and immutable by construction — the same hash again is a harmless no-op; a different hash for an existing decision reverts
- History cannot be rewritten. Not by an attacker, not by us, not by the contract owner
- Emits an event per anchor, so anchors can be counted from the chain without trusting our database
- Deployed to testnet and mainnet with zero logic changes
- We anchor a hash, not the decision: the audit payload stays off-chain and exportable, the chain holds the tamper-evidence
Claude Code, or any MCP-compatible agent, can use AgentOps right now.
| Group | Tools | For |
|---|---|---|
| Discover | list_services, legal_context, trade_data |
Find paid services, fetch terms, read live market data |
| Decide | policy_check, authorize_payment, authorize_action |
Dry-run, or get a real signed authorization |
| Settle & prove | reconcile, decision_status, audit_export |
Confirm settlement, anchor to Casper, export audit JSON |
| Govern the fleet | create_agent, attach_trading_flow, revoke_agent |
Operator-only: provision, attach policy, hard-stop |
createGuardedFetch— drop-in replacement forfetchthat runs the whole x402 handshake (call → 402 → policy check → attach signed header → retry) in one line- Non-402 responses pass straight through, so it's safe as an agent's only fetch
- A refusal arrives as a typed
PaymentDeniedErrorcarrying the reason and decision ID — not a mystery 402
Every other agent-payment SDK gets this ergonomic by putting a private key in the agent process. Here the agent holds only an API key, so the convenience costs nothing in blast radius.
Policy: organization / team / agent-level rules · spend caps and per-transaction limits · hourly velocity controls · service and destination allowlists · network and action restrictions · immutable policy versioning (every decision cites the exact rulebook version that judged it) · human approval boundaries · org-wide emergency suspension.
Money: atomic reservation before authorization · double-spend protection · durable decision lifecycle with terminal-failure and expiry handling · automatic hold release · exact integer accounting, no floats · append-only double-entry ledger.
pnpm install
cp .env.example .env.local # point CASPER_GUARD_API_BASE_URL at the server
pnpm dev # http://localhost:3000| Command | What it does |
|---|---|
pnpm dev |
Development server |
pnpm build |
Production build |
pnpm test |
Unit tests (Vitest) |
pnpm test:e2e |
End-to-end tests (Playwright) |
pnpm lint |
ESLint |
pnpm typecheck |
TypeScript, no emit |
Stack — Next.js 15 (App Router) · React 19 · TypeScript · Tailwind CSS 4 · Zod · CSPR.click · React Flow.
The console is a thin, server-rendered layer over the AgentOps API. It holds no keys and no policy logic of its own: every rule shown here is enforced by the server on every authorization, whether or not the console is running.
# 1. The mainnet contract exists and holds real anchors
casper-client query-global-state --node-address https://node.mainnet.casper.network/rpc \
--key hash-a003b2c32c6c7bddbd51d9596a31af72e0cdad62268a3747147d809add7ff629
# 2. A real decision from the running system, anchored on Casper mainnet
casper-client get-transaction --node-address https://node.mainnet.casper.network/rpc \
0287e36aa351d850c6acb460147a6c8d767755cae3cec5dd2fb4aae6ece0478e
# 3. The live MCP server exposes its tools
curl -s -X POST https://casper-agopsserver-production.up.railway.app/v1/casper-guard/mcp \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '.result.tools[].name'
# 4. The x402 service really demands payment in WCSPR
curl -s -X POST https://casper-agopsservice-production.up.railway.app/risk-oracle/score \
-H 'content-type: application/json' -d '{"pair":"CSPR-USDC","side":"buy","size_motes":"1000000000"}'
# → HTTP 402 { "x402Version":2, "accepts":[{ "asset":"3d80df21…", "payTo":"0060854d…" }] }
# 5. The SDK is public
npm view @agops-labs/sdkAll pulled from a Casper node; error_message was null on all of them.
| # | Network | What | Transaction |
|---|---|---|---|
| M1 | mainnet | GuardRegistry install · chain casper |
e008a246… |
| M2 | mainnet | anchor_decision — real decision anchored · block 8350189 |
0287e36a… |
| T1 | testnet | Order-book x402 payment · 2 WCSPR · block 8434250 | e1541674… |
| T2 | testnet | Risk-oracle x402 payment · 3 WCSPR · block 8434251 | ac53efe1… |
| T3 | testnet | GuardRegistry anchor · block 8461081 | a4eb2071… |
| T4 | testnet | GuardRegistry install · block 8281294 | 1378aa7e…72c8dfb68 |
| D1 | testnet | Grant delegated key · block 8599174 | 97c50ddf… |
| D2 | testnet | Agent transacts alone · block 8599184 | 426495a5… |
| D3 | testnet | Revoke delegated key · block 8599188 | 0a6cce33… |
| D4 | testnet | Revocation enforced by the node — "invalid associated keys" |
(rejected by design) |
| F1 | testnet | Purse-creation dust transfer · block 8623650 | 25215187… |
| F2 | testnet | 4 WCSPR transfer to the agent · block 8623650 | 5d4ca4fc… |
Contracts
- GuardRegistry mainnet — package
a003b2c3…· contract3f4e5a7c…0802ce54ccd - GuardRegistry testnet — package
850b5056…a9e7d7ed· contract4aac5aaa…c2b61671 - WCSPR (CEP-18) —
3d80df21…1314847c1e· CSPR.trade's contract, not ours; we only call its entry points
- Live app — aops-casper.up.railway.app
- MCP endpoint —
casper-agopsserver-production.up.railway.app/v1/casper-guard/mcp - x402 demo services — casper-agopsservice-production.up.railway.app
- SDK —
@agops-labs/sdk - Demo video — AgentOps on Casper
- X — @0xaops
Source
- Console, landing, builder — Casper-AGOPS.Client (this repository)
- Engine, contracts, SDK — Casper-AGOPS.Server
- x402 services — Casper-AGOPS.Service
AI agents are going to buy services, allocate budgets, and push blockchain transactions without a human approving every step. That isn't a prediction — it already happened here. The hard part was never giving an agent money; it's keeping control when the agent, the payment rail, the service provider, or the execution path behaves in a way nobody planned for.
Intent judged before signing. Money reserved before execution. Funding released only against an approval. Outcome confirmed before it's trusted. Proof anchored after success. And a kill-switch the Casper network itself enforces.
License — Apache 2.0 · Contributing — CONTRIBUTING.md · Code of conduct — CODE_OF_CONDUCT.md