Veto CLI — agent-payment policy + on-chain hard-stop. Any agent. Any rail.
Project description
The safety layer for AI agents that spend money.
Any agent. Any payment rail. Safe transactions.
Real-time policy + signed decision receipts + optional on-chain hard-stop.
Quick start · Engine · On-chain · Scaffold · Comparison · Architecture · Commands · Community
The pitch in one paragraph
Veto sits between AI agents and the money. Every spend an agent attempts is checked against a YAML policy you author — caps, allowlists, escalation thresholds, on-chain rules — and an 8-stage risk engine that catches typosquats, address-poisoning, sanctioned addresses, prompt injection, and behavioral anomalies. Every decision ships with a cryptographically-signed receipt anyone can verify offline. For agents that need adversarial-grade enforcement, an optional smart wallet contract refuses to release funds without a fresh, in-scope, Veto-signed mandate — the chain refuses, not just our SDK. Composes with x402, AP2, Stripe MPP, Verifiable Intent.
Built by Investech Global LLC. Elastic License v2. Python + TypeScript scaffolding for agents.
Layer 3 — Operational Policy
The agent-commerce stack has rails (x402, MPP, AP2) and consent (Verifiable Intent, AP2 mandates). The layer between agent and rail — operator-side governance, signed evidence, refusal at the moment of decision — has been empty. Veto is that layer.
Quick start
# 1. Install — agent-friendly (used by Claude Code skills, MCP plugins, scripts)
curl -fsSL https://veto-ai.com/install.sh | bash
# Or human-friendly (pip)
pip install veto-cli
# 2. Register a Veto account from the terminal — no website, no form
veto register --email me@example.com --preset inference
# 3. Ask Veto whether an action is allowed
veto authorize --amount 0.05 --merchant api.openai.com --action payment
Output:
✓ APPROVED — risk 0.18
reason_codes: REPUTATION_NEW
policy: AI Inference v1
policy_hash: 53aa6184…
transaction_id: e9f1c2a4…
receipt: eyJhbGciOiJFZERTQSIs… (Ed25519, verifiable offline)
That's it. No SaaS account, no credit card, no MCP setup required. The API key lives in ~/.veto/config.json (mode 0600) — only your user can read it.
What Veto checks
Eight stages. Every signal that fires lands in the receipt's engine_trace — so "why was this denied?" always has a structured answer.
> veto authorize --amount 14500 --merchant api-anthropc.com --action payment
✗ DENIED — risk 1.00
01 your_rules ✓ within caps
02 prompt_injection ✓ no patterns
03 misspelled_merchants ✗ TYPOSQUAT_CANONICAL
api-anthropc.com ↔ api.anthropic.com (94%)
04 crypto_safety (n/a — fiat)
05 intent ⚠ INTENT_PARTIAL — mission says "inference", merchant unverified
06 anomaly ✗ AMOUNT_ANOMALY (47× 30-day avg)
07 behavior_baseline ✗ AMOUNT_ABOVE_BASELINE_P99
08 final_decision ✗ DENY — fraud floor + amount cap
| # | Stage | What it catches |
|---|---|---|
| 1 | Your rules | Caps, daily limits, allow- and blocklists for merchants, chains, tokens, addresses |
| 2 | Prompt-injection | "Ignore previous instructions" patterns and friends |
| 3 | Misspelled merchants | api-anthropc.com, аpple.com (Cyrillic homoglyph) — for every user, allowlist or not |
| 4 | Crypto safety | OFAC sanctioned addresses (live feed), address-poisoning attacks, known-drainer contracts |
| 5 | Intent | Does the spend match the agent's mission and recent context? Crypto-aware. |
| 6 | Anomaly | Velocity bursts, merchant-diversity spikes, off-pattern amounts |
| 7 | Behavior baseline | Per-agent rolling stats — distinguishes "trading bot at 20 tx/min (normal)" from "inference agent at 20 tx/min (suspicious)" |
| 8 | Final decision | Weighted aggregation, fraud floor, human-required floor, signed receipt with full trace |
Output: approve / deny / escalate plus a risk_score (0–1), structured reason_codes, and the full engine_trace. The receipt signs all of it.
On-chain hard-stop
A minimal smart wallet (VetoGuardedAccount) holds the agent's funds and only releases them on a fresh, in-scope, Veto-signed mandate. Single-use, time-bound, scope-locked. Deployed and proven:
| Live contract | 0xCBbbC4b924AF40D29f135c3a88b6F650d55d92c5 on Base Sepolia |
| First execution | 0x2f9ec…d2af — 0.000001 ETH transferred |
| Replay rejected | MandateAlreadySpent() selector 0xffa64355 — the chain refused a duplicate |
| Off-chain verifier | @veto/mandate-verifier (TS, Node 18+) |
| Source | veto-protocol/contracts |
Verification: secp256k1 EIP-712 + ecrecover (~3k gas). Domain separator binds chainId + verifyingContract → no cross-chain or cross-contract replay either. Each mandate carries a single-use jti the contract tracks on-chain. Production audited contracts ship in v2.
Scaffold an agent
veto agent init --name my-agent --dir ./my-agent
Generates a runnable TypeScript project with a local viem wallet (you own the key — no third-party vendor), an LLM brain you choose during setup (Anthropic Claude, OpenAI, or xAI Grok), tool wrappers for send_eth / send_usdc / get_balance, and every governed call routed through Veto's authorize first. Denies halt the agent before broadcast.
The full 4-step interactive lifecycle:
veto agent init # scaffold the project + generate keys + write .env
veto agent fund # auto-open faucet, poll for funds, confirm
veto agent deploy # deploy a VetoGuardedAccount smart wallet (testnet)
veto agent status # snapshot of agent + wallet + contract + policy
When WALLET_CONTRACT is set in .env, send_* calls go through executeWithMandate(...) on the deployed smart wallet. The chain refuses spends without a fresh, in-scope, Veto-signed mandate. Cooperative on the SDK side, hard-stop on the chain side, simultaneously.
Why Veto
🔒 Signed by defaultEvery approve, deny, escalate ships with an Ed25519-signed receipt over the canonical decision payload — engine version, policy fingerprint, signal scores, decision. Anyone verifies offline against |
⛓️ Optional on-chain hard-stopFor adversarial threat models, a smart wallet contract refuses to settle without a fresh Veto mandate. Live on Base Sepolia today; audited mainnet ships next. Same SDK, same policy, additional chain-level guarantee. |
🛤️ Rail-agnosticx402 (USDC over HTTP 402), Stripe MPP, AP2, direct EVM/Solana, Verifiable Intent. Veto sits one layer above the rail — pick whatever the rest of your stack picked. The policy travels with the agent. |
The comparison
| Wallet stacks | Risk engines | Schema specs | Veto | |
|---|---|---|---|---|
| Holds the agent's wallet | ✅ | ❌ | ❌ | ❌ (non-custodial by design) |
| Per-tx & daily caps | ⚠️ wallet limit | ✅ | ✅ (spec only) | ✅ enforced + versioned |
| Merchant + address allowlists | ❌ | ⚠️ flat list | ✅ | ✅ YAML + rollback |
| Typosquat + address-poisoning checks | ❌ | ⚠️ basic | ❌ | ✅ canonical + homoglyph-aware |
| OFAC sanctioned-address live feed | ❌ | ⚠️ static | ❌ | ✅ OFAC SDN, refreshed |
| Per-agent behavioral baselines | ❌ | ⚠️ per-account | ❌ | ✅ percentile-aware, per-agent |
| Signed decision receipts | ❌ | ❌ | ❌ | ✅ Ed25519 + JWKS, offline-verifiable |
| On-chain hard-stop | ❌ | ❌ | ❌ | ✅ VetoGuardedAccount + EIP-712 mandate |
| Composable across rails | ❌ rail-bound | ⚠️ vendor-bound | ✅ | ✅ x402 / MPP / AP2 / on-chain |
| Open source where it matters | ❌ | ❌ | ✅ | ✅ CLI + schema + contract + verifier |
Veto is the operator-policy layer for autonomous-spending agents. The thing that makes "agent has a wallet" go from scary demo to production default.
All commands
| Command | What it does |
|---|---|
veto register |
CLI-native signup. Creates account + default agent + preset policy. |
veto authorize |
Ask Veto whether an action is allowed. Headline command. |
veto verify |
Verify a Veto receipt offline against the issuer's JWKS endpoint. |
veto policy export/push/show/list/check/activate |
Author and manage versioned YAML policies. |
veto agent init |
Scaffold a runnable Veto-governed agent project (TypeScript). |
veto agent fund |
Open a faucet for the agent's wallet, poll for funds. |
veto agent deploy |
Deploy a VetoGuardedAccount smart wallet (testnet). |
veto agent status |
Snapshot of agent + wallet + contract + policy state. |
veto agent configure |
Re-run onboarding to fill in skipped keys. |
veto init |
Auto-detect MCP clients (Claude Desktop, Cursor, Zed, Continue) and configure them. |
veto status [agent_id] |
Show agent reputation tier + recent decision history. |
veto mcp |
Run the Veto MCP server in stdio mode (used by MCP clients). |
Five policy presets to start from
veto register applies a policy preset so your agent has sensible limits from the first authorize call. Pick one with --preset:
| Preset | For | Defaults |
|---|---|---|
personal (default) |
General-purpose agent | $500/tx, $2k/day, blocks gambling/mixers/adult |
inference |
AI API calls | $5/tx, allowlists Anthropic/OpenAI/Replicate/etc. |
x402-micropay |
x402 testing | $1/tx, Base chain only, auto-approve <$0.10 |
ad-spend |
Meta/Google ads | $1k/tx, escalate >$1k |
dev |
Dogfooding/testing | $500/tx, no merchant restrictions |
When the preset isn't enough:
veto policy export inference > my-policy.yaml
$EDITOR my-policy.yaml
veto policy push my-policy.yaml # auto-versioned, auto-active
veto policy check '{"action":"payment","amount":50,"merchant":"amazon.com"}'
veto policy activate <prior-policy-id> # instant rollback
Every push creates a new versioned row. Receipts cite the exact policy_id, version_number, and policy_hash active at decision time — so an auditor in 12 months can prove which exact policy contents governed any past decision.
How it works
┌──────────────────────────────────────────────────────────────────┐
│ AGENT — your code, your stack, your runtime │
│ Calls veto.authorize() before each spend │
└────────────────────────┬─────────────────────────────────────────┘
│ HTTPS
▼
┌──────────────────────────────────────────────────────────────────┐
│ VETO ENGINE — 8-stage pipeline │
│ Policy · Prompt-inj · Typosquat · Crypto safety │
│ Intent · Anomaly · Baseline · Aggregator │
└────────────────────────┬─────────────────────────────────────────┘
│
┌─────────────────┴─────────────────┐
▼ ▼
┌──────────────┐ ┌──────────────────────┐
│ Receipt │ │ Mandate (optional) │
│ Ed25519 JWS │ │ Ed25519 JWT (off- │
│ for audit │ │ chain) │
│ │ │ + secp256k1 EIP-712 │
│ │ │ (on-chain) │
└──────────────┘ └──────────┬───────────┘
│
▼
┌──────────────────────┐
│ VetoGuardedAccount │
│ smart wallet │
│ ecrecover · verify │
│ scope · settle │
│ or revert │
└──────────────────────┘
The cooperative path (left, just the receipt) is enough for most threat models — bugs, hallucinations, runaway loops. The hard-stop path (right, with the smart wallet) closes the adversarial case where the agent code itself is compromised. Same engine, same policy, two enforcement surfaces.
Composes with
| Spec | One-line | How Veto composes |
|---|---|---|
| x402 | HTTP 402 micropayments (USDC on Base) | veto authorize runs before the agent signs the x402 payload |
| AP2 (Google) | User → Agent intent mandates | Receipts carry mandate_ref to cite an upstream AP2 mandate |
| Stripe MPP | Agent-to-merchant card-rail payments | Veto sits above; rail handles settlement |
| Verifiable Intent (Mastercard + Google) | Sibling of AP2 | Same pattern as AP2 |
| ACP (OpenAI + Stripe) | Catalog/cart/checkout API | Different layer (Layer 5); orthogonal |
Different layer, different problem, complementary primitive. When all four exist on a transaction, the agent carries: AP2/VI mandate (legal consent), Veto receipt (operational compliance), ACP merchant flow (commerce), MPP/x402 settlement (money). All four produce signed credentials.
Documentation
- 📐 Architecture — the 5-layer stack, engine pipeline, on-chain hard-stop
- 🚀 Quickstart — first 60 seconds (install → authorize → verify → agent init)
- 📜 Receipts — receipt format spec, signing, verification, audit guarantees
- 🛡️ Policies — YAML format, presets, customization, lifecycle
- 🗺️ Roadmap — what's shipped (v0.6) → what's next (audit + mainnet)
Public artifacts
| Artifact | Repository |
|---|---|
| CLI source (this repo) | veto-protocol/veto-cli |
| APPS — open policy schema | veto-protocol/x402-policy-schema |
| Mandate verifier (TS) | veto-protocol/mandate-verifier |
| Smart wallet contract | veto-protocol/contracts |
| Veto's own published policies | veto-protocol/veto-policies |
| Documentation | veto-protocol/docs |
| Public JWKS (Ed25519 signing key) | https://veto-ai.com/.well-known/jwks.json |
| Live contract on Base Sepolia | https://sepolia.basescan.org/address/0xCBbbC4b924AF40D29f135c3a88b6F650d55d92c5 |
Community
- 🐦 @veto_ai — release notes, demos, ecosystem updates
- 🐛 Issues — bugs and feature requests
- ✉️ tomer@veto-ai.com — direct line to the founder
Development
git clone https://github.com/veto-protocol/veto-cli.git
cd veto-cli
pip install -e ".[dev]"
pytest # unit tests
veto --help # local CLI
Contributing: open an issue first to discuss meaningful changes. PRs welcome on bugs, docs, new policy presets, and engine signal additions.
License
Elastic License v2 (ELv2). See LICENSE for the full text and copyright. You may use, modify, and embed Veto freely. You may not host Veto as a managed service to third parties or strip the licensing notices.
The safety layer for AI agents that spend money.
Any agent. Any payment rail. Safe transactions.
Built by Investech Global LLC · ELv2-licensed.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file veto_cli-0.7.0.tar.gz.
File metadata
- Download URL: veto_cli-0.7.0.tar.gz
- Upload date:
- Size: 111.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1a63cefe24e1ae8a70214b312b1df90b83238aca8c5588856be2b824af4d9aee
|
|
| MD5 |
c9490d249d6880101fa15f070c5a445a
|
|
| BLAKE2b-256 |
35746ea37a35ce58b012a9e88a3cd9b78fe8ba7844a3251f680a36e26db0f2c1
|
File details
Details for the file veto_cli-0.7.0-py3-none-any.whl.
File metadata
- Download URL: veto_cli-0.7.0-py3-none-any.whl
- Upload date:
- Size: 104.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
431c7afb79271e61fe3cfa53de0606eeef43844a787ecb03e337a5593be9244b
|
|
| MD5 |
71ac314750653e1344a9eb314e064654
|
|
| BLAKE2b-256 |
f5a20b3f06ca00cb4f680324aa393c3feaeb357dbe869021ef33089fb1215d7f
|