Veto/docs

YAML Rule Format

Complete reference for Veto's YAML rule syntax.

Each policy file (e.g. veto/rules/policy.yaml) can contain:

  • extends to inherit from a built-in policy pack
  • rules for pre-execution input validation
  • output_rules for post-execution output validation/redaction

For end-to-end examples, see Output Validation & Redaction. For business-hour policies, see Time-Based Conditions. For built-in packs, see Policy Packs.

Full schema

version: "1.0"                  # [Required] Policy schema version
extends: "@veto/coding-agent"   # [Optional] Inherit built-in pack rules

rules:
  - id: unique-rule-id           # [Required] Unique identifier
    name: Human readable name    # [Required] Descriptive name for logging
    enabled: true                # [Optional] Default: true
    severity: high               # [Optional] critical, high, medium, low, info
    action: block                # [Required] block, warn, log, allow, require_approval

    # Scope: which tools does this rule apply to?
    tools:                       # [Optional] List of tool names
      - make_payment             # If omitted, applies to ALL tools

    # Optional agent scope:
    # - list form: include-only
    # - object form: exclude listed agents
    agents:
      - support-agent
      - ops-agent
    # OR
    # agents:
    #   not:
    #     - internal-auditor

    # Static conditions (optional):
    # Evaluated locally before LLM validation
    conditions:
      - field: arguments.amount  # Dot notation for nested args
        operator: greater_than   # See operators table below
        value: 1000
      - field: context.time
        operator: outside_hours
        value:
          start: "09:00"
          end: "17:00"
          timezone: "America/New_York"
          days: ["mon", "tue", "wed", "thu", "fri"]

    # Condition groups (optional):
    # OR-of-ANDs — use instead of `conditions` for compound logic
    condition_groups:
      - - field: arguments.amount
          operator: greater_than
          value: 10000
      - - field: arguments.currency
          operator: not_in
          value: ["USD", "EUR"]
        - field: arguments.amount
          operator: greater_than
          value: 1000

    # Cross-tool sequence constraints (optional):
    # Evaluate prior calls in this session history.
    blocked_by:
      - tool: read_file
        conditions:
          - field: arguments.path
            operator: starts_with
            value: "/etc/secrets"

    requires:
      - tool: verify_identity
        within: 300            # Optional time window in seconds
        conditions:
          - field: arguments.level
            operator: equals
            value: strong

    # Description (optional):
    # Natural language guidance for the validation LLM
    description: "Ensure the payment recipient is a verified vendor."

output_rules:
  - id: unique-output-rule-id    # [Required] Unique identifier
    name: Human readable name     # [Required] Descriptive name
    enabled: true                 # [Optional] Default: true
    severity: high                # [Optional] critical, high, medium, low, info
    action: redact                # [Required] block, redact, log

    # Scope: which tools does this output rule apply to?
    tools:
      - make_payment              # If omitted, applies to ALL tools

    # Output conditions (optional):
    # Same operators as input conditions
    output_conditions:
      - field: output.receipt.email
        operator: matches
        value: "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"

    # Output condition groups (optional):
    # OR-of-ANDs for output checks
    output_condition_groups:
      - - field: output.secret
          operator: contains
          value: token
      - - field: output.card
          operator: matches
          value: "\\d{16}"

    # Replacement text for redact action
    redact_with: "[REDACTED]"

    description: "Prevent sensitive data from leaving the tool boundary."

Policy file fields

FieldRequiredDescription
versionYesSchema version. Use "1.0"
extendsNoBuilt-in pack name to inherit from (for example @veto/coding-agent)
rulesNo*Input validation rules
output_rulesNo*Output validation and redaction rules

* A policy file must define at least one of: extends, rules, or output_rules.

When extends is used, Veto loads the pack first, then merges your rules on top:

  • Same rule ID: your rule fully overrides the pack rule
  • New rule ID: your rule is appended

Input rule fields (rules)

FieldRequiredDefaultDescription
idYesUnique identifier for the rule
nameYesHuman-readable name for logging
enabledNotrueWhether the rule is active
severityNomediumcritical, high, medium, low, info
actionYesblock, warn, log, allow, require_approval
toolsNoAll toolsList of tool names this rule applies to
agentsNoAll agentsAgent scope for local matching: include list ([a,b]) or exclusion ({ not: [a,b] })
conditionsNoStatic constraint checks (AND logic)
condition_groupsNoCompound constraint checks (OR-of-ANDs logic)
blocked_byNoSequence constraint(s): trigger when any listed prior call exists
requiresNoSequence constraint(s): trigger when any listed prerequisite call is missing
descriptionNoNatural language guidance for LLM validation

Output rule fields (output_rules)

FieldRequiredDefaultDescription
idYesUnique identifier for the output rule
nameYesHuman-readable output rule name
enabledNotrueWhether the output rule is active
severityNomediumcritical, high, medium, low, info
actionYesblock, redact, log
toolsNoAll toolsList of tool names this output rule applies to
output_conditionsNoOutput checks (AND logic)
output_condition_groupsNoOutput checks (OR-of-ANDs logic)
redact_withNo[REDACTED]Replacement text used for redact
descriptionNoHuman-readable reason (used in logs/block reason)

Condition operators

These operators apply to both conditions and output_conditions.

OperatorTypeDescriptionExample
equalsanyExact matchvalue: "admin"
not_equalsanyMust not equalvalue: "admin"
containsstringSubstring matchvalue: "password"
not_containsstringMust NOT containvalue: "secret"
starts_withstringPrefix matchvalue: "/etc"
ends_withstringSuffix matchvalue: ".exe"
matchesstringRegex pattern (max 256 chars, ReDoS-safe)value: "^[^@]+@company\\.com$"
instring/numberValue in allowlistvalue: ["USD", "EUR"]
not_instring/numberValue NOT in denylistvalue: ["admin", "root"]
greater_thannumberNumeric > comparisonvalue: 1000
less_thannumberNumeric < comparisonvalue: 0
within_hoursobjectTime is inside windowvalue: { start: "09:00", end: "17:00", timezone: "UTC" }
outside_hoursobjectTime is outside windowvalue: { start: "09:00", end: "17:00", timezone: "UTC" }

For within_hours and outside_hours, value must include:

  • start (HH:MM, 24-hour)
  • end (HH:MM, 24-hour)
  • timezone (IANA timezone, e.g. America/New_York)
  • optional days array (mon, tue, wed, thu, fri, sat, sun)

Virtual context fields

Conditions can reference runtime context fields (not just tool arguments):

FieldTypeDescription
context.timestringCurrent timestamp (ISO string), typically used with within_hours / outside_hours
context.day_of_weekstringCurrent lowercase day abbreviation (sun..sat)

Example weekend lock rule:

rules:
  - id: weekend-lockdown
    name: Restrict prod deploys on weekends
    action: block
    tools: [deploy]
    conditions:
      - field: context.day_of_week
        operator: in
        value: ["sat", "sun"]

Condition groups (OR logic)

When you need compound logic beyond simple AND, use condition_groups instead of conditions. Each group is an array of conditions joined with AND, and groups are joined with OR.

Only use one of conditions or condition_groups per rule. If both are set, conditions takes precedence.

rules:
  - id: restrict-high-risk-transfers
    name: Block high-risk financial transfers
    action: block
    tools:
      - transfer_funds
    condition_groups:
      # Group 1: Large transfers to any destination
      - - field: arguments.amount
          operator: greater_than
          value: 50000

      # Group 2: Any transfer to a non-approved currency AND amount > 1000
      - - field: arguments.currency
          operator: not_in
          value: ["USD", "EUR", "GBP"]
        - field: arguments.amount
          operator: greater_than
          value: 1000

This rule triggers if either group matches:

  • Amount exceeds 50,000 (any currency), OR
  • Amount exceeds 1,000 in a non-approved currency

Sequence constraints (blocked_by, requires)

Use sequence constraints when rule decisions depend on earlier tool calls in the same session history.

  • blocked_by: rule triggers if any listed historical call matches.
  • requires: rule triggers if any listed requirement is not found.
  • Historical conditions / condition_groups are evaluated against the prior call context (use arguments.* fields).
  • within is optional and measured in seconds from the current call time.
  • Only retained history entries are checked (default history size is 100).
rules:
  - id: prevent-data-exfiltration
    name: Block send after sensitive read
    action: block
    tools: [send_email, upload_file]
    blocked_by:
      - tool: read_file
        conditions:
          - field: arguments.path
            operator: starts_with
            value: "/etc/secrets"

  - id: require-auth-before-transfer
    name: Require recent verification
    action: block
    tools: [transfer_funds]
    requires:
      - tool: verify_identity
        within: 300

Sequence constraints are currently enforced in local YAML validation mode.

Agent scoping (agents)

Use agents when a rule should only apply for certain agent identities.

Include-only

rules:
  - id: scoped-rule
    name: Applies only to selected agents
    action: block
    tools: [deploy]
    agents:
      - deploy-bot
      - ci-agent

Exclusion

rules:
  - id: excluded-rule
    name: Applies to everyone except excluded agents
    action: require_approval
    tools: [transfer_funds]
    agents:
      not:
        - internal-auditor

Matching rules:

  • no agents field: applies to all agents
  • agents: [a, b]: applies only for a or b
  • agents: { not: [a, b] }: applies for everyone except a or b

Input rule matching logic

1. Rule selection

Veto selects rules based on tools, then applies any agents scope:

  • Tool-specific rules: If a rule lists specific tools (e.g. tools: [make_payment]), it only applies when those tools are called
  • Global rules: If tools is missing or empty [], the rule activates for every tool call
  • Agent-scoped rules: If agents is present, the rule is further filtered by current agent identity before evaluating conditions

2. Validation execution

For each intercepted tool call, Veto aggregates all applicable rules (global + specific) and validates:

  1. Static conditions — if conditions are defined, they're checked first. If a condition matches, the rule triggers immediately
  2. Semantic validation — if no static conditions match (or none exist), the rule's name and description are sent to the LLM for semantic evaluation

Output rule matching logic

For each executed tool result, Veto aggregates all applicable output rules (global + specific) and evaluates output_conditions / output_condition_groups.

Action resolution order:

  1. If any matched output rule has action: block, the output is rejected.
  2. Otherwise, matched action: redact rules apply regex replacements using redact_with.
  3. Matched action: log rules emit warnings and pass output through.

When block and redact both match, block takes precedence.

Examples

Block large financial transfers

rules:
  - id: limit-transfers
    name: Limit large transfers
    action: block
    severity: critical
    tools:
      - transfer_funds
      - send_payment
    conditions:
      - field: arguments.amount
        operator: greater_than
        value: 10000

Prevent file access outside project

rules:
  - id: restrict-file-paths
    name: Restrict file access to project directory
    action: block
    severity: high
    tools:
      - read_file
      - write_file
    conditions:
      - field: arguments.path
        operator: starts_with
        value: "/etc"

Global policy via LLM

rules:
  - id: no-pii-disclosure
    name: Prevent PII disclosure
    action: block
    severity: critical
    description: >
      Block any tool call that would expose personally identifiable
      information such as social security numbers, credit card numbers,
      or home addresses to external services.