Veto/docs

OpenClaw Integration

Use Veto with OpenClaw agents — plugin install, approval flows, and deterministic guardrails for real-world actions.

Veto integrates with OpenClaw at two levels. The plugin is the fast path: install it, run veto init, and your agent has hard guardrails, approval gates, and rule enforcement without touching a line of agent code. The SDK hooks are available for advanced use cases where you need direct control inside a custom plugin.

PathBest forCode changes?
Plugin (recommended)Any OpenClaw project — local or cloudNone in agent code
SDK hooksCustom plugins, non-standard tool routing, embedded control flowsRequires a plugin scaffold

If you are starting fresh, use the plugin. If you are building a custom OpenClaw plugin that needs to embed Veto policy logic directly, use the SDK hooks.


Installation and setup

Plugin install

openclaw plugins install openclaw-veto

Then initialize Veto configuration in your project:

cd your-project && veto init

Generated directory structure:

veto/
├── veto.config.yaml
└── rules/
    └── defaults.yaml

veto.config.yaml defaults to local mode. All validation runs in-process using your YAML rules — no API key, no network calls, no account required to start.

Upgrade to cloud mode

Add your API key to activate the Veto Cloud approval UI, dashboard, and LLM-backed policies:

export VETO_API_KEY=veto_xxx

Or set it directly in veto.config.yaml:

version: "1.0"
mode: "strict"
cloud:
  apiKey: veto_xxx

Approval modes

The plugin supports two approval modes. Set approvalMode in your Veto config or pass it explicitly at init time.

ModeHow approval requests are resolvedRequires cloud?
openclaw-nativeOpenClaw's built-in approval UI, local rule engineNo
veto-cloudVeto Cloud approval dashboard and audit logYes (VETO_API_KEY)

openclaw-native

Approval requests are resolved inside OpenClaw's own interface. Veto evaluates rules locally and signals OpenClaw to surface the approval prompt.

Loading diagram...

veto-cloud

Approval requests are polled against the Veto Cloud queue. The agent waits for a human decision in the Veto dashboard before the tool call proceeds.

Loading diagram...

What Veto guarantees

This is the most important section to understand before deploying to production.

CapabilityDeterministic?What it means
Block leverage above thresholdYesHard permission check — no model judgment, no bypass
Require approval before large tradeYesApproval gate is structural. The tool call cannot proceed until a human acts
Enforce session budget / open-position countYesStateful server/client checks evaluated before every tool call
Block calls to non-allowlisted exchanges or APIsYesRule fires on argument value, independent of model behavior
Judge whether agent reasoning is "sound"No — LLM-backedUseful signal, but not a substitute for structural rules
Evaluate whether a multi-step plan is safeNo — LLM-backedAdditive layer; don't treat it as a hard constraint

Veto is strongest when enforcing structured permissions on structured tool arguments. A rule like "block any trade with leverage above 5x" fires reliably because leverage is a discrete argument value — the rule is evaluated deterministically, every time, without model involvement.

LLM-backed policies are a real feature and they add meaningful coverage for cases that can't be expressed as static rules. But they are additive, not the foundation of financial safety. Build your critical guardrails on YAML rules first.


What is plug-and-play vs what needs tuning

Works immediately after install

  • Hard blocks — argument-value checks (greater_than, not_in, matches) fire without any configuration
  • Approval gatesrequire_approval works in both modes out of the box
  • Default pack thresholdsveto init --pack financial loads a pre-built rule set with sensible defaults for trading, transfers, and data access
  • Local YAML rules — any rule in veto/rules/*.yaml is evaluated in-process with zero setup

Requires configuration for your environment

  • Exchange-specific tool names — rules target tools by name; you need to map your agent's actual tool identifiers
  • Custom argument schemas — if your tools pass amounts in non-standard fields (e.g., qty instead of amount), update the condition field paths accordingly
  • Cloud-mode approvalsveto-cloud requires a VETO_API_KEY; approval routing and notification setup happens in the Veto dashboard
  • Semantic LLM policies — natural-language policy descriptions require an LLM provider API key and a veto compile run to generate their YAML equivalents

Example rules

All examples below use valid Veto YAML rule syntax. Place files in veto/rules/.

File access control

veto/rules/file-access.yaml
rules:
  - id: block-sensitive-paths
    name: Block access to sensitive file paths
    action: block
    severity: critical
    tools:
      - read_file
      - write_file
      - delete_file
    conditions:
      - field: arguments.path
        operator: matches
        value: "(\\.env|credentials|secrets|\\.ssh|/etc/passwd)"

Shell command approval

veto/rules/shell.yaml
rules:
  - id: require-approval-shell
    name: Require approval for shell command execution
    action: require_approval
    severity: high
    tools:
      - execute_command
      - run_shell
    conditions:
      - field: arguments.command
        operator: matches
        value: ".*"

  - id: block-destructive-commands
    name: Block destructive shell commands unconditionally
    action: block
    severity: critical
    tools:
      - execute_command
      - run_shell
    conditions:
      - field: arguments.command
        operator: matches
        value: "^(rm -rf|mkfs|dd if=|:(){ :|:& };:)"

External API allowlist

veto/rules/external-api.yaml
rules:
  - id: allowlist-external-apis
    name: Block calls to non-allowlisted external APIs
    action: block
    severity: high
    tools:
      - http_request
      - fetch_url
      - api_call
    conditions:
      - field: arguments.url
        operator: not_in
        value:
          - "https://api.exchange-a.com"
          - "https://api.exchange-b.com"
          - "https://data.market-feed.io"

Trading guardrails

veto/rules/trading.yaml
rules:
  - id: block-high-leverage
    name: Block trades with leverage above 5x
    action: block
    severity: critical
    tools:
      - place_order
      - open_position
    conditions:
      - field: arguments.leverage
        operator: greater_than
        value: 5

  - id: require-approval-large-trade
    name: Require approval for trades above $10,000 notional
    action: require_approval
    severity: high
    tools:
      - place_order
      - open_position
    conditions:
      - field: arguments.notional_usd
        operator: greater_than
        value: 10000

  - id: block-short-selling-disabled
    name: Block short positions when short-selling is disabled
    action: block
    severity: critical
    tools:
      - place_order
    conditions:
      - field: arguments.side
        operator: not_in
        value:
          - "buy"
          - "close"

SDK hooks (advanced)

Use the SDK integration directly inside a custom OpenClaw plugin when you need programmatic control over the hook lifecycle.

npm install veto-sdk
import { Veto } from 'veto-sdk';
import {
  createVetoBeforeToolCallHook,
  createVetoAfterToolCallHook,
} from 'veto-sdk/integrations/openclaw';

const veto = await Veto.init();

const beforeHook = createVetoBeforeToolCallHook(veto, {
  onAllow: (toolName, args) => {
    console.log(`[veto] allow: ${toolName}`);
  },
  onDeny: (toolName, args, reason) => {
    console.warn(`[veto] deny: ${toolName} — ${reason}`);
  },
  throwOnDeny: false,
});

const afterHook = createVetoAfterToolCallHook(veto, {
  onComplete: (toolName, args, result) => {
    // post-execution audit hook — no blocking
  },
});

// Register with your OpenClaw plugin
plugin.hooks.beforeToolCall(beforeHook);
plugin.hooks.afterToolCall(afterHook);

Hook options

OptionTypeDefaultDescription
onAllow(toolName, args) => voidCalled when a tool call passes validation
onDeny(toolName, args, reason) => voidCalled when a tool call is denied
throwOnDenybooleanfalseThrow ToolCallDeniedError instead of returning a denial result
approvalMode"openclaw-native" | "veto-cloud"From configOverride the approval mode for this hook instance
sessionIdstringAuto-generatedTie this hook to a specific session for budget and state tracking

How it works

Every tool call is intercepted before execution and evaluated against your loaded YAML rules. The outcome maps directly to an OpenClaw result:

Veto decisionOpenClaw behavior
allowTool call executes normally
deny{ block: true, reason: "..." } returned to agent
require_approvalApproval flow triggered (openclaw-native or veto-cloud depending on mode)

The agent receives denial and approval-pending results as structured responses. It does not see Veto's presence — the guardrail is transparent to agent logic.


A note on what Veto promises

Veto does not promise profitable trading. It does not guarantee that an agent will make good decisions.

What Veto does promise: every tool call that touches money, files, or external systems passes through an explicit, auditable policy check before it executes. Approvals are structural, not advisory. Hard blocks are deterministic. If you define a rule that blocks leverage above 5x, that rule fires every time — not most of the time.

This is the trust model: accountable actions, explicit approvals, and deterministic guardrails around agent behavior. Financial safety is built on rules you write and own, not on model judgment.


Exports

import {
  createVetoBeforeToolCallHook,
  createVetoAfterToolCallHook,
} from 'veto-sdk/integrations/openclaw';

import type {
  VetoOpenClawBeforeHookOptions,
  VetoOpenClawAfterHookOptions,
  VetoOpenClawDenyResult,
} from 'veto-sdk/integrations/openclaw';

  • YAML Rule Format — complete rule syntax, operators, severity levels, and extends
  • SDK Modes — local, cloud, and self-hosted mode differences
  • MCP Integration — Veto with Model Context Protocol tool definitions