@sovr/gate
AI Execution Control Plane — Intercept, audit, and control AI agent actions before they execute.

Why SOVR Gate?
AI agents are powerful but dangerous. They can:
- Send emails without review
- Process payments without approval
- Delete data without confirmation
- Execute irreversible actions automatically
SOVR Gate is the missing control layer between AI decision and real-world execution.
Without SOVR Gate:
AI Agent → Direct Execution → 💥 Irreversible Error
With SOVR Gate:
AI Agent → SOVR Gate → Human Approval → Safe Execution ✓
Installation
npm install @sovr/gate
yarn add @sovr/gate
pnpm add @sovr/gate
Quick Start
import { createGate } from '@sovr/gate';
const gate = createGate({
defaultDeny: true,
irreversibleActions: [
'send_email',
'process_payment',
'delete_user',
],
});
async function executeAction(action) {
const result = await gate.check({
type: action.type,
resource: action.resource,
params: action.params,
});
if (result.allowed) {
return performAction(action);
}
if (result.requiresApproval) {
console.log(`Waiting for approval: ${result.pendingApprovalId}`);
return { status: 'pending_approval', id: result.pendingApprovalId };
}
throw new Error(`Action blocked: ${result.reason}`);
}
Core Concepts
1. Action Types
Every action has a type that determines how it's handled:
| Read | get_user, list_orders | ✅ Always allowed |
| Write | create_order, update_user | ⚠️ Logged |
| Irreversible | delete_user, process_payment | 🛑 Requires approval |
2. Gate Verdicts
ALLOW | Action can proceed |
DENY | Action is blocked |
PENDING_APPROVAL | Waiting for human approval |
3. Kill Switch
Emergency stop all AI actions:
gate.enableKillSwitch('Security incident detected');
const result = await gate.check({ type: 'any_action', resource: 'any' });
gate.disableKillSwitch();
LangChain Integration
Wrap Individual Tools
import { createGate, wrapTool } from '@sovr/gate';
import { SerpAPI } from 'langchain/tools';
const gate = createGate();
const searchTool = wrapTool(new SerpAPI(), gate);
Callback Handler (Recommended)
import { createGate, createCallbackHandler } from '@sovr/gate';
import { AgentExecutor } from 'langchain/agents';
const gate = createGate({
defaultDeny: true,
approvalRequired: ['send_email', 'execute_code'],
});
const handler = createCallbackHandler(gate, {
blockOnDeny: true,
contextProvider: async () => ({
userId: getCurrentUserId(),
tenantId: getTenantId(),
}),
});
const agent = new AgentExecutor({
callbacks: [handler],
});
LCEL Middleware
import { createGate, gateMiddleware } from '@sovr/gate';
import { RunnableSequence } from 'langchain/runnables';
const gate = createGate();
const chain = RunnableSequence.from([
gateMiddleware(gate, 'process_data'),
myDataProcessor,
gateMiddleware(gate, 'send_notification'),
notificationSender,
]);
Human Approval Flow
const gate = createGate({
irreversibleActions: ['process_refund'],
webhooks: {
onPendingApproval: 'https://your-app.com/webhooks/approval',
},
});
const result = await gate.check({
type: 'process_refund',
resource: 'payment',
params: { amount: 1000, orderId: 'ord_123' },
});
console.log(result.requiresApproval);
console.log(result.pendingApprovalId);
await gate.approve(result.pendingApprovalId, 'admin@company.com', 'Verified refund request');
Configuration
const gate = createGate({
tenantId: 'my-company',
enabled: true,
defaultDeny: true,
allowList: ['get_status', 'list_items'],
blockList: ['delete_database', 'shutdown_server'],
approvalRequired: ['send_bulk_email', 'publish_content'],
irreversibleActions: [
'process_payment',
'delete_user',
'send_email',
],
riskThresholds: {
maxAmount: 100000,
highRiskAmount: 10000,
blockedCountries: ['XX', 'YY'],
},
webhooks: {
onPendingApproval: 'https://your-app.com/webhooks/approval',
onDecision: 'https://your-app.com/webhooks/decision',
},
});
Custom Storage
By default, SOVR Gate uses in-memory storage. For production, implement your own:
import { createGate, StorageAdapter } from '@sovr/gate';
class PostgresStorage implements StorageAdapter {
async saveDecision(decision) {
await db.insert('sovr_decisions', decision);
}
async getDecision(decisionId) {
return db.findOne('sovr_decisions', { id: decisionId });
}
}
const gate = createGate({
storage: new PostgresStorage(),
});
Evidence Trail
Every decision creates an immutable evidence bundle:
const result = await gate.check({ type: 'send_email', resource: 'email' });
console.log(result.evidence);
API Reference
createGate(config?)
Create a new gate instance.
gate.check(action, context?)
Check if an action is allowed.
gate.approve(approvalId, approvedBy, reason?)
Approve a pending action.
gate.reject(approvalId, rejectedBy, reason?)
Reject a pending action.
gate.enableKillSwitch(reason)
Emergency stop all actions.
gate.disableKillSwitch()
Resume normal operation.
gate.listPendingApprovals(tenantId?)
List all pending approvals.
License
MIT © SOVR
Questions? docs.sovrapp.com | Discord | hello@sovrapp.com