Integrate Veto guardrail system to validate and control AI agent tool calls with rule-based security policies. Intercepts tool calls before execution and enforces safety rules via configurable YAML policies and validation API.
Integrate Veto, a guardrail system that intercepts and validates AI agent tool calls before execution. Enforce security policies through rule-based validation without modifying tool schemas.
This skill helps you set up and configure Veto SDK to:
Veto operates transparently - the AI model sees unchanged tool definitions while validation happens behind the scenes.
Use this skill when you need to:
Install the package in the project:
```bash
npm install veto
```
Run the init command to create configuration structure:
```bash
npx veto init
```
This creates:
Edit `veto/veto.config.yaml` to set operating mode and validation API:
```yaml
version: "1.0"
mode: "strict" # "strict" blocks calls, "log" only logs them
api:
baseUrl: "http://localhost:8080"
endpoint: "/tool/call/check"
timeout: 10000
retries: 2
logging:
level: "info" # debug, info, warn, error, silent
rules:
directory: "./rules"
recursive: true
```
**Operating Modes:**
Create rule files in `veto/rules/` directory. Each rule file uses YAML format:
```yaml
rules:
- id: block-system-paths
name: Block system path access
description: Prevent access to sensitive system directories
enabled: true
severity: critical # critical, high, medium, low, info
action: block # block, warn, log, allow
tools: # empty list = applies to all tools
- read_file
- write_file
conditions: # all conditions must match
- field: arguments.path
operator: starts_with
value: /etc
- field: arguments.path
operator: not_contains
value: /etc/myapp
- id: block-credential-files
name: Block credential file access
enabled: true
severity: critical
action: block
tools:
- read_file
conditions:
- field: arguments.path
operator: matches
value: ".*(credentials|secrets|\.env).*"
```
**Available Condition Operators:**
Create a validation API endpoint that Veto will call. The API receives tool call context and applicable rules, then returns pass/block decision.
**Request Format (POST /tool/call/check):**
```json
{
"context": {
"call_id": "call_abc123",
"tool_name": "read_file",
"arguments": { "path": "/etc/passwd" },
"timestamp": "2024-01-15T10:30:00Z",
"call_history": []
},
"rules": [
{
"id": "block-system-paths",
"name": "Block system path access",
"severity": "critical",
"conditions": [
{
"field": "arguments.path",
"operator": "starts_with",
"value": "/etc"
}
]
}
]
}
```
**Response Format:**
```json
{
"should_pass_weight": 0.1,
"should_block_weight": 0.9,
"decision": "block",
"reasoning": "Access to /etc is blocked by security policy"
}
```
The `decision` field must be `"pass"` or `"block"`.
Modify your tool execution code to wrap tools with Veto:
**For Anthropic Claude:**
```typescript
import { Veto, ToolCallDeniedError } from 'veto';
import Anthropic from '@anthropic-ai/sdk';
// Define tools with handlers
const tools = [
{
name: 'read_file',
description: 'Read a file from the filesystem',
inputSchema: {
type: 'object',
properties: {
path: { type: 'string', description: 'File path to read' }
},
required: ['path']
},
handler: async (args) => {
return fs.readFileSync(args.path, 'utf-8');
}
},
{
name: 'write_file',
description: 'Write content to a file',
inputSchema: {
type: 'object',
properties: {
path: { type: 'string' },
content: { type: 'string' }
},
required: ['path', 'content']
},
handler: async (args) => {
fs.writeFileSync(args.path, args.content);
return 'OK';
}
}
];
// Initialize Veto and wrap tools
const veto = await Veto.init();
const { definitions, implementations } = veto.wrapTools(tools);
// Use definitions with Anthropic (no handlers, just schemas)
const anthropic = new Anthropic();
const response = await anthropic.messages.create({
model: 'claude-3-opus-20240229',
tools: definitions, // Tool schemas without handlers
messages: [{ role: 'user', content: 'Read /home/user/file.txt' }]
});
// Execute tool calls using wrapped implementations
for (const block of response.content) {
if (block.type === 'tool_use') {
try {
// Validation happens automatically here
const result = await implementations[block.name](block.input);
console.log('Result:', result);
} catch (error) {
if (error instanceof ToolCallDeniedError) {
console.log('Blocked:', error.reason);
console.log('Rule violated:', error.ruleId);
} else {
throw error;
}
}
}
}
```
**For OpenAI:**
```typescript
import { Veto, toOpenAITools, ToolCallDeniedError } from 'veto';
import OpenAI from 'openai';
const veto = await Veto.init();
const { definitions, implementations } = veto.wrapTools(tools);
const openai = new OpenAI();
const response = await openai.chat.completions.create({
model: 'gpt-4',
tools: toOpenAITools(definitions),
messages: [{ role: 'user', content: 'Read the file' }]
});
for (const call of response.choices[0].message.tool_calls ?? []) {
const args = JSON.parse(call.function.arguments);
try {
const result = await implementations[call.function.name](args);
console.log('Result:', result);
} catch (error) {
if (error instanceof ToolCallDeniedError) {
console.log('Blocked:', error.reason);
}
}
}
```
Start in `log` mode to test rules without blocking:
```typescript
const veto = await Veto.init({ mode: 'log' });
```
Monitor logs to verify rules are triggering correctly, then switch to `strict` mode for enforcement.
Override configuration via environment variables:
Validate tool calls manually for custom execution flows:
```typescript
const result = await veto.validateToolCall({
id: 'call_123',
name: 'read_file',
arguments: { path: '/some/path' }
});
if (result.allowed) {
// Execute the tool
} else {
console.log('Blocked:', result.reason);
}
```
View all loaded rules programmatically:
```typescript
const rules = veto.getLoadedRules();
console.log('Loaded rules:', rules.length);
```
```typescript
const mode = veto.getMode(); // 'strict' or 'log'
console.log('Operating mode:', mode);
```
```yaml
rules:
- id: allow-workspace-only
name: Allow workspace directory only
enabled: true
severity: high
action: block
tools:
- read_file
- write_file
- delete_file
conditions:
- field: arguments.path
operator: not_starts_with
value: /workspace
```
```yaml
rules:
- id: block-dangerous-commands
name: Block dangerous shell commands
enabled: true
severity: critical
action: block
tools:
- execute_command
conditions:
- field: arguments.command
operator: matches
value: ".*(rm -rf|dd|mkfs|format|shutdown|reboot).*"
```
Implement rate limiting in your validation API by tracking call history and returning block decisions when limits are exceeded.
**Tools not being validated:**
**Validation API timeout:**
**Rules not loading:**
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/veto-sdk-agent-guardrails/raw