Veto/docs

Validation Modes

How Veto validates tool calls — local, cloud, API, custom, and kernel modes.

Veto supports five validation modes. The SDK auto-detects the mode from your init options and environment. You can also set it explicitly in veto.config.yaml:

validation:
  mode: "local"  # "local" | "cloud" | "api" | "custom" | "kernel"

Local mode (default)

Evaluates YAML rules from ./veto/rules/*.yaml entirely in-process. No network calls, no API key, no account.

# No validation.mode needed — local is the default
version: "1.0"
mode: "strict"

Supports all YAML condition operators: equals, not_equals, contains, not_contains, starts_with, ends_with, matches, in, not_in, greater_than, less_than, within_hours, outside_hours. Also supports expression-based conditions from the compiled rule format.

Activated automatically when no apiKey, endpoint, or explicit validation.mode is configured.

See SDK Modes for the full auto-detection precedence.

Cloud mode

Routes validation through the Veto Cloud API. Policies are managed in the dashboard — the SDK fetches and caches them automatically.

validation:
  mode: "cloud"

cloud:
  apiKey: "veto_abc123..."   # or set VETO_API_KEY env var
  baseUrl: "https://api.runveto.com"
  timeout: 30000
  retries: 2

approval:
  pollInterval: 2000   # ms between polls
  timeout: 300000      # max wait (5 min)

Three validation paths

Cloud mode uses the fastest validation path that can handle each policy:

PathWhere it runsLatencyWhen it triggers
Client-side deterministicSDK (local)~1-5msPolicy is cached, mode is deterministic, no session/rate constraints
Server-side deterministicVeto Cloud~30-50msCache miss, or policy has session constraints or rate limits
Server-side LLMVeto Cloud~500-2000msPolicy mode is llm

The SDK picks the path automatically. You configure the policy — the routing is handled for you.

Client-side deterministic

When the SDK has a cached deterministic policy with no session or rate constraints, it evaluates constraints locally. No network call. Decisions are logged to the server asynchronously via POST /v1/decisions so the dashboard stays accurate.

Supported constraints: minimum, maximum, greaterThan, lessThan, enum, regex, minLength, maxLength, minItems, maxItems, required, notNull. See Constraints Reference.

Server-side deterministic

Same constraint types, plus stateful checks that require server coordination:

  • Session constraints — e.g. "max 3 calls to delete_record per session"
  • Rate limits — e.g. "max 10 calls per minute"
  • Cross-tool constraints — e.g. "if read_file was called, block send_email"

Server-side LLM

An LLM evaluates the tool call against natural language policies. Use this for checks that can't be expressed as static constraints:

  • Semantic evaluation against a policy description
  • Exception lists (e.g. "deny transfers to external accounts, except for verified vendors")
  • Complex multi-argument relationships
  • Context-dependent decisions

Three decisions

The cloud can return three decisions:

DecisionWhat happens
allowTool call proceeds
denyToolCallDeniedError is thrown
require_approvalSDK pauses and polls until a human approves or denies in the dashboard

Policy cache

Policies are cached with stale-while-revalidate:

WindowDurationBehavior
Fresh0–60sServe from cache
Stale60s–5minServe from cache, refresh in background
Expired>5minFall through to server

Policy changes in the dashboard propagate to all connected SDKs within 60 seconds.

Event webhooks

You can optionally emit webhook notifications after key validation outcomes:

events:
  webhook:
    url: "https://hooks.example.com/veto"
    on: ["deny", "require_approval", "budget_exceeded"]
    min_severity: "high"
    format: "slack"  # slack | pagerduty | generic | cef

Webhook delivery is fire-and-forget and does not block validation responses. If webhook delivery fails, Veto logs a warning and returns the original validation decision.

For payload formats and end-to-end examples, see Event Webhooks.

API mode

Sends validation requests to a self-hosted endpoint. Use this when you want full control over the validation backend.

validation:
  mode: "api"
  api:
    url: "http://localhost:8080"
    endpoint: "/tool/call/check"

The endpoint receives the tool name and arguments as JSON and must return { decision: "allow" | "deny" }.

Custom mode

Calls an LLM provider directly from the SDK. No server needed. Rules are evaluated using the LLM with the YAML rules in your veto/rules/ directory.

validation:
  mode: "custom"

custom:
  provider: "openai"     # openai | anthropic | gemini
  model: "gpt-4o-mini"
ProviderModelsEnv variable
openaigpt-4o, gpt-4o-miniOPENAI_API_KEY
anthropicclaude-sonnet-4-5-20250929ANTHROPIC_API_KEY
geminigemini-3-flash-previewGEMINI_API_KEY

Best for development and testing when you don't need the dashboard or audit trails.

Kernel mode

Uses a local Ollama model for fully offline validation. Zero external API calls.

validation:
  mode: "kernel"

kernel:
  url: "http://localhost:11434/v1"
  model: "llama3"

Requires Ollama running locally. Best for air-gapped environments.

Operating modes

Orthogonal to validation mode, Veto has three operating modes that control what happens when a tool call is denied:

mode: "strict"  # or "log" or "shadow"
ModeBehavior
strictBlocks denied calls — throws ToolCallDeniedError
logLogs denied calls but allows execution to continue
shadowPreserves real decisions for wrapped calls but never blocks execution

Use shadow during initial rollout to observe what would be blocked without affecting execution. Switch to strict once you're confident in your policies.