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
Unique identifier for the rule. Used in audit logs and CLI output.
Human-readable name displayed in logs and error messages.
Action to take when the rule matches. See Actions below.
Optional fields
Detailed explanation of what the rule does and why it exists.
Whether the rule is active. Set to false to disable without deleting.
Severity level: critical, high, medium, low, or info.
Array of tool names this rule applies to. Omit or leave empty for a global rule that applies to all tools.
Array of conditions that must all match (AND logic). See Conditions .
Trigger this rule when a required historical call is missing. See Sequential rules .
Tags for categorization and filtering (e.g., ["compliance", "payments"]).
Additional metadata for custom integrations and reporting.
Actions
The action field determines what happens when a rule matches:
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
Allows the tool call to proceed. Useful for explicitly whitelisting patterns.- id : allow-read-operations
action : allow
tools : [ get_balance , list_transactions ]
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.
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."
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).
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
Exact match (strict equality) - field : arguments.environment
operator : equals
value : production
Not equal to - field : arguments.confirmed
operator : not_equals
value : true
String contains substring - field : arguments.query
operator : contains
value : "DROP TABLE"
String does not contain substring
String starts with prefix - field : arguments.path
operator : starts_with
value : "/etc/secrets"
Regular expression match - field : arguments.query
operator : matches
value : "(?i)(drop|delete|truncate) \\ s+table"
Numeric greater than - field : arguments.amount
operator : greater_than
value : 1000
Numeric greater than or equal
Numeric less than or equal
Value is in array - field : arguments.currency
operator : in
value : [ "USD" , "EUR" , "GBP" ]
Value is not in array - field : arguments.currency
operator : not_in
value : [ "BTC" , "ETH" ]
Array/string length exceeds value - field : arguments.recipients
operator : length_greater_than
value : 5
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" ]
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