Skip to main content
Rules define restrictions on tool calls and agent behavior. They’re written in YAML and loaded from the ./veto/rules/ directory.

Rule structure

A rule file contains a rule set with metadata and an array of rules:
version: "1.0"
name: financial-rules
description: Guardrails for payment and transfer operations

rules:
  - id: block-large-transfers
    name: Block large transfers
    description: Transfers over $10,000 require manual approval
    enabled: true
    severity: critical
    action: block
    tools: [transfer_funds]
    conditions:
      - field: arguments.amount
        operator: greater_than
        value: 10000

Rule fields

Required fields

id
string
required
Unique identifier for the rule. Used in audit logs and CLI output.
name
string
required
Human-readable name displayed in logs and error messages.
action
string
required
Action to take when the rule matches. See Actions below.

Optional fields

description
string
Detailed explanation of what the rule does and why it exists.
enabled
boolean
default:"true"
Whether the rule is active. Set to false to disable without deleting.
severity
string
default:"medium"
Severity level: critical, high, medium, low, or info.
tools
string[]
Array of tool names this rule applies to. Omit or leave empty for a global rule that applies to all tools.
agents
string[] | object
Scope this rule to specific agents. See Agent scoping.
conditions
RuleCondition[]
Array of conditions that must all match (AND logic). See Conditions.
condition_groups
RuleCondition[][]
Array of condition groups with OR logic between groups. See Condition groups.
blocked_by
RuleSequenceConstraint[]
Trigger this rule if a matching historical call exists. See Sequential rules.
requires
RuleSequenceConstraint[]
Trigger this rule when a required historical call is missing. See Sequential rules.
tags
string[]
Tags for categorization and filtering (e.g., ["compliance", "payments"]).
metadata
object
Additional metadata for custom integrations and reporting.

Actions

The action field determines what happens when a rule matches:
block
action
Denies the tool call and throws a ToolCallDeniedError.
- id: block-large-transfers
  action: block
  tools: [transfer_funds]
  conditions:
    - field: arguments.amount
      operator: greater_than
      value: 10000
allow
action
Allows the tool call to proceed. Useful for explicitly whitelisting patterns.
- id: allow-read-operations
  action: allow
  tools: [get_balance, list_transactions]
require_approval
action
Routes to human approval workflow. The call is paused until a human approves or denies it.
- id: require-approval-production
  action: require_approval
  tools: [deploy]
  conditions:
    - field: arguments.environment
      operator: equals
      value: production
See Human-in-the-loop for setup details.
warn
action
Logs a warning but allows the tool call to proceed.
- id: warn-external-api
  action: warn
  conditions:
    - field: arguments.url
      operator: starts_with
      value: "https://external."
log
action
Logs an info message and allows the tool call to proceed.
- id: log-all-database-queries
  action: log
  tools: [query_database, execute_sql]

Conditions

Conditions define when a rule should trigger. All conditions in the conditions array must match (AND logic).

Condition format

conditions:
  - field: arguments.amount    # Field to check (dot notation)
    operator: greater_than     # Comparison operator
    value: 1000                # Value to compare against

Field paths

Use dot notation to access nested fields:
  • arguments.amount — Direct argument
  • arguments.recipient.account_id — Nested object
  • context.user_id — Context data
  • context.time — Request timestamp

Operators

equals
operator
Exact match (strict equality)
- field: arguments.environment
  operator: equals
  value: production
not_equals
operator
Not equal to
- field: arguments.confirmed
  operator: not_equals
  value: true
contains
operator
String contains substring
- field: arguments.query
  operator: contains
  value: "DROP TABLE"
not_contains
operator
String does not contain substring
starts_with
operator
String starts with prefix
- field: arguments.path
  operator: starts_with
  value: "/etc/secrets"
ends_with
operator
String ends with suffix
matches
operator
Regular expression match
- field: arguments.query
  operator: matches
  value: "(?i)(drop|delete|truncate)\\s+table"
greater_than
operator
Numeric greater than
- field: arguments.amount
  operator: greater_than
  value: 1000
less_than
operator
Numeric less than
greater_than_or_equal
operator
Numeric greater than or equal
less_than_or_equal
operator
Numeric less than or equal
in
operator
Value is in array
- field: arguments.currency
  operator: in
  value: ["USD", "EUR", "GBP"]
not_in
operator
Value is not in array
- field: arguments.currency
  operator: not_in
  value: ["BTC", "ETH"]
length_greater_than
operator
Array/string length exceeds value
- field: arguments.recipients
  operator: length_greater_than
  value: 5
outside_hours
operator
Current time is outside the specified window
- field: context.time
  operator: outside_hours
  value:
    start: "09:00"
    end: "17:00"
    timezone: "America/New_York"
    days: ["mon", "tue", "wed", "thu", "fri"]
within_hours
operator
Current time is within the specified window

Condition groups

Use condition_groups for OR logic between groups:
condition_groups:
  # Group 1: force flag is true
  - - field: arguments.force
      operator: equals
      value: true
  
  # OR Group 2: skip_checks is true
  - - field: arguments.skip_checks
      operator: equals
      value: true
  
  # OR Group 3: skip_tests is true AND env is production
  - - field: arguments.skip_tests
      operator: equals
      value: true
    - field: arguments.env
      operator: equals
      value: production
The rule triggers if any group has all conditions met (OR of ANDs).

Expression conditions

For complex logic, use expression-based conditions:
conditions:
  - expression: "arguments.amount > 10000"
  - expression: "arguments.to_account starts_with 'EXT-'"
Expressions support:
  • Arithmetic: +, -, *, /, %
  • Comparisons: >, <, >=, <=, ==, !=
  • String operations: starts_with, ends_with, contains
  • Logical: and, or, not

Sequential rules

Use blocked_by and requires to create rules based on call history.

blocked_by

Trigger the rule if a matching historical call exists:
- id: block-send-after-secret-read
  name: Block email after reading secrets
  action: block
  tools: [send_email]
  blocked_by:
    - tool: read_file
      within: 3600  # seconds
      conditions:
        - field: arguments.path
          operator: starts_with
          value: "/etc/secrets"
This blocks send_email if the agent read a secret file in the last hour.

requires

Trigger the rule when a required historical call is missing:
- id: require-auth-before-transfer
  name: Require verification before transfer
  action: block
  tools: [transfer_funds]
  requires:
    - tool: verify_identity
      within: 300  # 5 minutes
This blocks transfer_funds unless verify_identity was called in the last 5 minutes.

Agent scoping

Restrict rules to specific agents:
# Include-only list
agents:
  - analyst-agent
  - support-agent

# Exclude list
agents:
  not:
    - internal-auditor

Real-world examples

Financial guardrails

version: "1.0"
name: financial-pack
rules:
  - id: financial-transfer-limit
    name: Enforce per-transaction transfer limit
    enabled: true
    severity: high
    action: require_approval
    tools: [transfer_funds, wire_transfer, send_money]
    conditions:
      - field: arguments.amount
        operator: greater_than
        value: 10000

  - id: financial-currency-allowlist
    name: Restrict transfer currencies
    enabled: true
    severity: high
    action: block
    tools: [transfer_funds, wire_transfer]
    conditions:
      - field: arguments.currency
        operator: not_in
        value: ["USD", "EUR", "GBP"]

Deployment guardrails

version: "1.0"
name: deployment-pack
rules:
  - id: deploy-require-approval-production
    name: Require approval for production deploys
    enabled: true
    severity: critical
    action: require_approval
    tools: [deploy, publish, release]
    condition_groups:
      - - field: arguments.environment
          operator: equals
          value: production
      - - field: arguments.env
          operator: equals
          value: prod

  - id: deploy-block-force-push
    name: Block force deployments
    enabled: true
    severity: high
    action: block
    tools: [deploy, publish]
    condition_groups:
      - - field: arguments.force
          operator: equals
          value: true
      - - field: arguments.skip_checks
          operator: equals
          value: true

Data access guardrails

version: "1.0"
name: data-access-pack
rules:
  - id: data-access-block-sql-injection
    name: Block SQL injection patterns
    enabled: true
    severity: critical
    action: block
    tools: [query_database, execute_sql]
    condition_groups:
      - - field: arguments.query
          operator: contains
          value: " OR 1=1"
      - - field: arguments.query
          operator: contains
          value: " UNION SELECT"
      - - field: arguments.query
          operator: contains
          value: ";--"

  - id: data-access-limit-rows
    name: Limit query row count
    enabled: true
    severity: high
    action: block
    tools: [query_database]
    conditions:
      - field: arguments.limit
        operator: greater_than
        value: 10000

Output rules

Output rules validate and transform tool results after execution:
output_rules:
  - id: redact-email
    name: Redact email addresses
    enabled: true
    severity: medium
    action: redact
    tools: [query_database, fetch_customer]
    output_conditions:
      - field: output.email
        operator: matches
        value: '^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$'
    redact_with: "[REDACTED_EMAIL]"
Output actions:
  • redact — Replace matched fields with redact_with value
  • block — Throw error if output matches conditions
  • log — Log info message if output matches

Rule inheritance

Extend built-in policy packs:
version: "1.0"
name: custom-financial-rules
extends: "financial-pack"  # Built-in pack

rules:
  # Your custom rules here
  - id: custom-rule
    action: block
    # ...

Next steps

How it works

Understand the validation flow

Writing rules

Best practices for rule design

Policy packs

Pre-built rule collections

Testing policies

Test your rules with the CLI

Build docs developers (and LLMs) love