SDK Modes
Three runtime modes — local, cloud, and self-hosted — with automatic detection at init.
The SDK auto-detects which mode to use based on what you pass to Veto.init(). No explicit mode configuration is needed.
Mode detection precedence
The SDK checks these in order and uses the first match:
| Priority | Condition | Mode |
|---|---|---|
| 1 | options.endpoint is set | Self-hosted |
| 2 | options.apiKey is set | Cloud |
| 3 | config.validation.mode is set explicitly | Uses that mode |
| 4 | VETO_API_KEY env var is set | Cloud |
| 5 | config.cloud.baseUrl is a non-default URL | Self-hosted |
| 6 | Nothing | Local (default) |
On startup, the SDK logs which mode was selected:
[VETO] INFO Veto running in local modeLocal mode (default)
Zero network calls. Rules are loaded from ./veto/rules/*.yaml and evaluated in-process.
const veto = await Veto.init();What it does:
- Reads YAML rules from
./veto/rules/ - Evaluates all condition operators locally (expression-based and legacy field/operator)
- Logs decisions to stdout
- No API key, no account, no network traffic
Best for: Development, CI pipelines, air-gapped environments, getting started.
Cloud mode
Activated by providing an API key. Policies are managed in the Veto dashboard and cached locally with stale-while-revalidate.
// Via options
const veto = await Veto.init({ apiKey: "veto_..." });
// Via environment variable
// export VETO_API_KEY=veto_...
const veto = await Veto.init();
// Via config file
// cloud:
// apiKey: "veto_..."
const veto = await Veto.init();What it does:
- Fetches policies from the cloud and caches them locally
- Deterministic policies run client-side (~1-5ms)
- LLM policies route through the server (~500-2000ms)
- Approval workflows pause until a human resolves
- Decisions logged to the dashboard for audit
Best for: Production teams needing visibility, approval workflows, and analytics.
Self-hosted mode
Activated by providing an endpoint URL pointing to your own Veto server.
// Your own Veto server
const veto = await Veto.init({
endpoint: "https://veto.internal.corp.com",
});
// Self-hosted with API key authentication
const veto = await Veto.init({
endpoint: "https://veto.internal.corp.com",
apiKey: "veto_...",
});The server is available as a container image:
docker pull ghcr.io/vulnzap/veto-server:latest
docker run -p 8080:8080 -e DATABASE_URL=postgres://... ghcr.io/vulnzap/veto-server:latestWhat it does:
- Runs the validation server (deterministic + LLM policies) on your infrastructure
- The
apiKeyauthenticates against your self-hosted server - All data stays within your network
- Decision logging to your own PostgreSQL database
Not included: The self-hosted server is the validation API only. The dashboard, analytics UI, and approval management UI are available through Veto Cloud. You can query decisions and manage approvals programmatically via the Server API.
Best for: Enterprises with data residency requirements who need server-side validation on their own infrastructure.
If both endpoint and apiKey are provided, the SDK logs a warning and uses self-hosted mode with the API key for authentication.
Init options reference
interface VetoOptions {
configDir?: string; // default: "./veto"
mode?: "strict" | "log" | "shadow";
apiKey?: string; // triggers cloud mode
endpoint?: string; // triggers self-hosted mode
logLevel?: string;
sessionId?: string;
agentId?: string;
validators?: Validator[];
cloudClient?: VetoCloudClient;
onApprovalRequired?: (context: ValidationContext, approvalId: string) => void;
}Config file examples
Local (default)
No validation.mode needed — this is the default:
version: "1.0"
mode: "strict"Cloud
version: "1.0"
mode: "strict"
validation:
mode: "cloud"
cloud:
apiKey: "veto_..."Self-hosted
version: "1.0"
mode: "strict"
validation:
mode: "cloud"
cloud:
baseUrl: "https://veto.internal.corp.com"Operating modes
Orthogonal to the runtime mode, Veto has three operating modes that control what happens when a tool call is denied:
| Mode | Behavior |
|---|---|
strict | Blocks denied calls — throws ToolCallDeniedError |
log | Logs denied calls but allows execution to continue |
shadow | Preserves real decisions for wrapped calls but never blocks execution |
Use shadow during initial rollout to observe production impact, then switch to strict once policies are tuned.
License
The Veto SDK and server are released under the Apache 2.0 license. You can use, modify, and distribute the code freely. Apache 2.0 does not grant rights to the Veto trademark or logo — the "Veto" name and branding remain the property of VulnZap.