Veto is the policy runtime for AI agent tool calls — write deny rules in plain English, enforce them deterministically, in 5 lines of code.
Veto sits between an agent and the tools it can execute. It evaluates tool name + arguments against deterministic policy, then allows, denies, warns, logs, or routes to approval before your handler runs. It governs tool calls, not prompts.
Checked-in PR-mode baselines are measured on GitHub Actions runner output, not local hardware or thresholds. CI gates Veto p99 regressions above 10% against benchmark/baselines/*.json; absolute thresholds remain separate.
| Runtime | Workload | Iterations | p50 | p95 | p99 | p99 threshold | Source |
|---|---|---|---|---|---|---|---|
| Veto | single-rule local eval | 50,000 | 0.000260ms | 0.001092ms | 0.002594ms | 0.05ms | measured on GitHub Actions PR-mode, PR #208 CI log |
| Veto | 100-rule merged packs | 50,000 | 0.027291ms | 0.037470ms | 0.057136ms | 0.5ms | measured on GitHub Actions PR-mode, PR #212 CI log |
| Veto | localhost PDP server eval | 250 | 0.402051ms | 0.841651ms | 2.092263ms | 30ms | local loopback fixture baseline; not run in PR mode |
| AGT | policy eval latency per rule | published | 0.012ms/rule | not published | not published | n/a | source: published, not reproduced |
| AGT | throughput at 50 concurrent agents | published | 35K ops/sec | not published | not published | n/a | source: published, not reproduced |
import { protect } from "veto-sdk";
const safeTools = await protect(tools);npm install veto-sdkPass safeTools to LangChain, LangGraph, Vercel AI SDK, OpenAI Agents, MCP adapters, Claude SDK, Google ADK, Mastra, AutoGen, CrewAI, or your own tool runner. If ./veto/veto.config.yaml and ./veto/rules/*.yaml exist, protect() loads them. Without local policy, Veto applies @veto/safe-defaults in observe mode so suspicious shell/file/db/money-movement patterns are logged without surprise blocking.
The unscoped veto npm name is not controlled by Plaw yet; use the owned veto-cli package form until transfer completes.
For a blocking local policy in under a minute:
npm install veto-sdk
npx --package veto-cli@latest veto init
npx --package veto-cli@latest veto policy generate --tool bash --prompt "block rm -rf" --save ./veto/rules/block-rm-rf.yaml
node examples/60-second-denied-call/denied-call.mjsThis path is local-only: no provider SDK or API key is required. For prose generation, Veto tries configured cloud/self-hosted/kernel endpoints first, then uses a local deterministic template fallback with review warnings; in fallback, no prompt or policy data leaves your machine.
For a finance-style irreversible action demo with portable receipts:
pnpm build
node examples/finance-grade-agent/finance-demo.mjs
node packages/sdk/dist/cli/bin.js receipts verify examples/finance-grade-agent/demo-output/receipts.ndjsonThe demo runs local policy for an AP/procurement/refund workflow: one action is allowed, one is denied, one requires approval, and all three decisions are written as an offline-verifiable veto.receipt/1 chain.
Install Veto into developer tools and MCP clients:
npx --package veto-cli@latest veto install claude-code
npx --package veto-cli@latest veto install cursor
npx --package veto-cli@latest veto install codex
veto-mcp-proxy --config ./veto/mcp.config.yaml| Runtime | Artifact | Status |
|---|---|---|
| Provider-agnostic tools | protect(tools), Veto.wrap() |
Canonical path |
| Vercel AI SDK | veto-sdk/integrations/vercel-ai middleware + guard helper |
Supported |
| OpenAI Agents | veto-sdk/integrations/openai-agents guardrails + guard helper |
Supported |
| LangChain / LangGraph | veto-sdk/integrations/langchain middleware, ToolNode, guard helper |
Supported |
| MCP | provider adapters + Veto.wrapMCPTools() |
Supported |
| Browser Use | veto-sdk/integrations/browser-use |
Supported |
| OpenClaw | veto-sdk/integrations/openclaw hooks |
Supported |
| Claude SDK | veto-sdk/integrations/claude-sdk Anthropic tool-use helpers |
Added P2 |
| Google ADK | veto-sdk/integrations/google-adk function declaration/call helpers |
Added P2 |
| Mastra | veto-sdk/integrations/mastra tool wrappers |
Added P2 |
| AutoGen | veto-sdk/integrations/autogen function/tool wrappers |
Added P2 |
| CrewAI | veto-sdk/integrations/crewai tool-function wrappers |
Added P2 |
npm install veto-sdkimport { protect } from "veto-sdk";
const safeTools = await protect(tools);
const agent = createAgent({ tools: safeTools });pip install vetofrom veto import protect
safe = await protect(tools)
agent = create_agent(tools=safe)npx --package veto-cli@latest veto initnpx --package veto-cli@latest veto init creates ./veto/veto.config.yaml and ./veto/rules/defaults.yaml. The default local rules are strict and include deterministic denials for sensitive paths and destructive shell commands.
Prefer prose for new rules, then review the generated YAML:
npx --package veto-cli@latest veto policy generate --tool bash --prompt "block rm -rf" --save ./veto/rules/block-rm-rf.yamlrules:
- id: block-large-transfers
name: Block transfers over $1,000
enabled: true
severity: high
action: block
tools: [transfer_funds]
conditions:
- field: arguments.amount
operator: greater_than
value: 1000Actions: block, allow, warn, log, require_approval.
Veto.init() and .wrap() remain supported for advanced/internal-facing integrations that need an explicit instance, guard() checks, cloud/self-host options, audit exports, or event hooks.
import { Veto } from "veto-sdk";
const veto = await Veto.init({ configDir: "./veto", mode: "strict" });
const safeTools = veto.wrap(tools);
const decision = await veto.guard("transfer_funds", { amount: 1500 });from veto import Veto, VetoOptions
veto = await Veto.init(VetoOptions(config_dir="./veto", mode="strict"))
safe_tools = veto.wrap(tools)
decision = await veto.guard("transfer_funds", {"amount": 1500})| Package | Language | Install | Purpose |
|---|---|---|---|
packages/veto |
TypeScript | local workspace only | Reserved/local wrapper pending npm-name transfer |
veto-sdk |
TypeScript | npm install veto-sdk |
Policy runtime for agent tool calls |
veto (Python) |
Python | pip install veto |
Python parity SDK with protect() |
veto-cli |
TypeScript | npx --package veto-cli@latest veto init |
Currently published CLI package exposing veto |
veto-bash |
Rust + Node | npm install --global veto-bash |
Native bash tool-call enforcement path |
create-veto-app |
TypeScript | npm create veto-app |
Starter TypeScript app |
docker compose up
curl -s http://localhost:3001/v1/validate \
-H 'content-type: application/json' \
-d '{"toolName":"bash","arguments":{"command":"echo hello"}}'See docs/self-hosting.md for the public reviewer path, fixed localhost:3001 compose mapping, disabled-by-default outbound checks, and the local unauthenticated validation contract.
For applications that need managed Postgres persistence, we recommend Neon for the decision-receipt example. It evaluates Veto policy locally, writes portable receipts for allowed and denied decisions to Neon, and verifies the receipts read back from the database. Follow the Neon setup guide. This SDK example requires a database connection; the default Compose server continues to use SQLite.
Veto BYOC runs in the customer plane. Public install artifacts are in helm/, terraform-modules/, cf-templates/, and cdk/. They are outbound-only and must not grant Plaw cross-account IAM or impersonation. Customer policy, decision rows, tool arguments, agent IDs, user IDs, Slack content, prompts, environment variables, and secrets do not cross to Plaw.
Allowed outbound control-plane checks are limited to license heartbeat and optional telemetry. The heartbeat schema is exactly six fields: instance_uuid, license_id, decision_count_30d, sdk_version, operator_version, timestamp.
Install docs:
- Deterministic local evaluation for policy rules that can be checked from tool arguments.
- Provider-agnostic wrapping for any agent framework or custom tool runner.
- Human approval and cost-aware governance for sensitive tool calls.
- Local-first operation with optional self-hosted or cloud policy distribution.
- Apache-2.0 licensed packages and public supply-chain verification artifacts.
Thanks to Neon for supporting Veto through the Neon Open Source Program.
See CONTRIBUTING.md. Report vulnerabilities to [email protected].
Apache-2.0 © Plaw, Inc.