Writing Rules
Veto uses a priority-based rule engine to evaluate tool calls. Rules are checked before AI scoring — a matching rule returns a decision immediately without calling the AI model.
Rule fields
| Field | Type | Required | Description |
|---|---|---|---|
rule_type | "whitelist" or "blacklist" | Yes | Whitelist → allow, Blacklist → deny |
tool_pattern | string (regex) | Yes | Regex matched against the tool name using fullmatch |
content_pattern | string (regex) | No | Regex matched against tool input using search |
description | string | No | Human-readable note shown in the dashboard |
priority | integer | No (default: 0) | Higher priority rules are evaluated first |
enabled | boolean | No (default: true) | Disabled rules are skipped |
How matching works
- Rules are sorted by priority descending (highest first)
- For each enabled rule:
tool_patternis tested withre.fullmatch()— the entire tool name must match- If
content_patternis set, it's tested withre.search()— a substring match is enough - If both match, the rule fires
- First match wins — no further rules are evaluated
- If no rule matches → AI scoring (if enabled) → fail policy
Content extraction
When checking content_pattern, Veto extracts a single string from the tool input by checking these keys in order:
command → file_path → pattern → url → query → (full JSON stringified input)
For a Bash tool call, the command field is checked. For Read/Write/Edit, the file_path is checked.
Examples
Allow all read-only tools
{
"rule_type": "whitelist",
"tool_pattern": "Read|Glob|Grep",
"description": "Allow all read-only tools",
"priority": 10
}
Allow Bash but only for tests
{
"rule_type": "whitelist",
"tool_pattern": "Bash",
"content_pattern": "^(npm test|pytest|uv run pytest)",
"description": "Allow test commands",
"priority": 20
}
Block destructive Bash commands
{
"rule_type": "blacklist",
"tool_pattern": "Bash",
"content_pattern": "rm\\s+-rf|sudo|chmod\\s+777|:(){ :|:& };:",
"description": "Block dangerous shell commands",
"priority": 100
}
High priority ensures this is checked before any whitelist that might allow Bash.
Block writes to sensitive files
{
"rule_type": "blacklist",
"tool_pattern": "Write|Edit",
"content_pattern": "\\.(env|pem|key)$|/etc/|credentials",
"description": "Block writes to sensitive files",
"priority": 50
}
Allow everything (escape hatch)
{
"rule_type": "whitelist",
"tool_pattern": ".*",
"description": "Allow all tools (disables enforcement)",
"priority": 0
}
Low priority so other rules take precedence.
Session whitelisting
Sometimes you need to temporarily bypass all rules for a specific Claude Code session — for example, during an urgent hotfix or a trusted pair-programming session. Session whitelisting allows exactly this.
How it works
A session whitelist is a special high-priority rule (priority 1000) that automatically allows all tool calls within a single session for a limited duration. It:
- Applies only to the specific session — other sessions are unaffected
- Expires automatically after the chosen duration (1h, 4h, 8h, or 24h)
- Can be revoked manually at any time from the dashboard
- Is logged in the audit trail like any other rule match
Creating a session whitelist
From the dashboard, go to Sessions and find the active session you want to whitelist. Click Whitelist and choose a duration:
| Duration | Use case |
|---|---|
| 1 hour | Quick hotfix or debugging session |
| 4 hours | Extended development session |
| 8 hours | Full workday session |
| 24 hours | Long-running autonomous task |
Under the hood
When you whitelist a session, Veto creates a rule with:
tool_pattern: ".*"— matches every toolpriority: 1000— evaluated before all other rulessession_id— scoped to the target session onlyexpires_at— automatic expiration
Because it has the highest priority and matches all tools, it short-circuits the entire evaluation flow for that session. Once expired or revoked, normal rules apply again.
Revoking a whitelist
From the Sessions page, click Revoke on any whitelisted session. The whitelist is removed immediately and subsequent tool calls go through normal rule evaluation.
Evaluation flow
Tool call received
→ Check rules (priority order, first match wins)
→ Whitelist match? → ALLOW (logged as "whitelist")
→ Blacklist match? → DENY (logged as "blacklist")
→ No match?
→ AI scoring enabled? → Call AI model → ALLOW/DENY/ASK
→ AI scoring fails? → Apply fail policy
→ No AI scoring? → Apply fail policy
Rule templates
When setting up Veto for the first time, you can apply a built-in template from the onboarding wizard:
Safe Defaults
Read-only tools allowed, Bash restricted to common safe commands. Good starting point for most teams.
Strict Mode
Only Read, Glob, and Grep are allowed. Everything else requires AI scoring or manual approval.
AI-Powered
Read tools and task tools allowed, plus AI scoring enabled for everything else. The AI model evaluates risk on a 0–100 scale.
Tips
- Use high priority blacklist rules for dangerous patterns — they'll be checked first
- Use
content_patternto scope broadtool_patternmatches tool_patternusesfullmatch:Bashmatches onlyBash, notBashExtra— useBash.*for prefix matchingcontent_patternusessearch:testmatches anywhere — use^test$for exact match- Rules with invalid regex patterns are silently skipped
- You can manage rules via the dashboard UI, the API, or import/export as JSON
API
| Method | Endpoint | Description |
|---|---|---|
GET | /api/v1/rules | List all rules (ordered by priority) |
POST | /api/v1/rules | Create a rule |
PUT | /api/v1/rules/:id | Update a rule |
DELETE | /api/v1/rules/:id | Delete a rule |
POST | /api/v1/rules/bulk | Bulk create/update rules |
POST | /api/v1/rules/simulate | Test a tool call against rules without logging |
All endpoints require authentication (API key or JWT).