Skip to main content
This guide will get you from zero to a working Veto-protected agent in under 5 minutes.

Prerequisites

  • Node.js 18+ or Python 3.10+
  • An AI agent project (or start fresh)
  • API key for your LLM provider (OpenAI, Anthropic, or Google)

Choose your language

Install Veto

npm install veto-sdk

Initialize Veto

Run veto init to create the configuration structure:
npx veto init
This creates:
  • ./veto/veto.config.yaml — Main configuration file
  • ./veto/rules/defaults.yaml — Default rules
  • ./veto/.env.example — Example environment variables

Add guardrails to your agent

Here’s a complete example using LangChain:
import { Veto } from 'veto-sdk';
import { createAgent, tool } from 'langchain';
import { z } from 'zod';

// Define your tools
const transferFunds = tool(
  ({ amount, from_account, to_account }) =>
    JSON.stringify({ 
      success: true, 
      amount, 
      from_account, 
      to_account, 
      tx_id: 'TX-' + Date.now() 
    }),
  {
    name: 'transfer_funds',
    description: 'Transfer money between bank accounts',
    schema: z.object({
      amount: z.number().describe('Amount to transfer in USD'),
      from_account: z.string().describe('Source account ID'),
      to_account: z.string().describe('Destination account ID'),
    }),
  }
);

const getBalance = tool(
  ({ account_id }) =>
    JSON.stringify({ account_id, balance: 25000, currency: 'USD' }),
  {
    name: 'get_balance',
    description: 'Get the balance of a bank account',
    schema: z.object({
      account_id: z.string().describe('The account ID'),
    }),
  }
);

async function main() {
  // 1. Initialize Veto (loads ./veto/veto.config.yaml + rules)
  const veto = await Veto.init();

  // 2. Wrap tools — types preserved, validation injected
  const tools = veto.wrap([getBalance, transferFunds]);

  // 3. Create agent with wrapped tools
  const agent = createAgent({
    model: 'google-genai:gemini-2.0-flash',
    tools,
  });

  // 4. Use your agent normally
  const result = await agent.invoke({
    messages: [{ role: 'user', content: 'Transfer $500 from ACC-001 to ACC-002' }],
  });

  console.log(result.messages[result.messages.length - 1].content);
  
  // View stats
  console.log(veto.getHistoryStats());
}

main().catch(console.error);

Configure your rules

Edit veto/rules/defaults.yaml to add your guardrails:
version: "1.0"
name: financial-rules
rules:
  - id: block-large-transfers
    name: Block Large Transfers
    description: Transfers over $10,000 require manual approval
    enabled: true
    action: block
    tools: [transfer_funds]
    conditions:
      - expression: "arguments.amount > 10000"
  
  - id: block-external-transfers
    name: Block External Transfers
    description: Block transfers to external banks
    enabled: true
    action: block
    tools: [transfer_funds]
    conditions:
      - expression: "arguments.to_account starts_with 'EXT-'"

Test it out

Run your agent:
node agent.js
Try asking it to transfer $50,000 or send money to an account starting with EXT-. Veto will block these actions based on your rules.

What just happened?

1

Initialized Veto

Veto.init() loaded your configuration from ./veto/veto.config.yaml and all rules from ./veto/rules/.
2

Wrapped your tools

veto.wrap() injected validation middleware into each tool’s execution handler. Types are preserved (TypeScript only).
3

Rules enforced automatically

When your agent called transfer_funds with amount > $10,000, Veto evaluated the conditions and blocked the call before execution.

Understanding rule actions

Veto supports five action types:
ActionBehaviorUse case
blockDenies execution, throws errorHard limits (e.g., never delete production data)
allowExplicitly allows executionWhitelist specific tool calls
warnLogs warning but allowsSoft limits for monitoring
logSilently logs for auditCompliance tracking
askRoutes to human approval queueSensitive actions requiring review
The ask action requires configuring an approval callback URL in veto.config.yaml. See the human-in-the-loop guide for details.

Check policy enforcement

Use the CLI to test your rules without running your agent:
npx veto-cli guard check --tool transfer_funds --args '{"amount": 50000}' --json
Output:
{
  "decision": "block",
  "rule": "block-large-transfers",
  "reason": "amount 50000 > threshold 10000"
}

View audit history

Export decision history for compliance:
const json = veto.exportDecisions("json");
const csv = veto.exportDecisions("csv");

Next steps

Installation guide

System requirements and advanced installation options

Configuration

Deep dive into veto.config.yaml and rule syntax

Rule reference

Complete reference for writing rules

Framework examples

LangChain, Vercel AI SDK, OpenAI, Anthropic, and more
Production tip: Always test your rules in shadow mode first (mode: "log") to validate they work as expected before switching to strict mode (mode: "strict").

Build docs developers (and LLMs) love