Integration Guide
Vercel AI SDK
Connect Vercel AI SDK to DashClaw and get your first governed action into /decisions in under 20 minutes.
Instance URL detected: https://your-dashclaw-instance.example.com
Deploy DashClaw
Get a running instance. Click the Vercel deploy button or run locally.
Already have an instance? Skip to Step 2.
Install the DashClaw Node SDK and the AI SDK
Add the packages to your project.
Terminal
npm install dashclaw ai zod dotenv
Set environment variables
Create a .env file with your DashClaw connection details. No LLM API key required for the example.
.env
DASHCLAW_BASE_URL=https://your-dashclaw-instance.example.com DASHCLAW_API_KEY=oc_live_...
Write a governed() wrapper for tool execute functions
One generic higher-order function turns any AI SDK tool execute into a governed one: guard before, record intent, pause for approval when required, report the outcome after.
governance.mjs
import { tool } from 'ai';
import { z } from 'zod';
import { DashClaw } from 'dashclaw';
const claw = new DashClaw({
baseUrl: process.env.DASHCLAW_BASE_URL,
apiKey: process.env.DASHCLAW_API_KEY,
agentId: 'vercel-ai-support-agent',
});
// Wrap any AI SDK execute function in the DashClaw governance loop.
function governed({ actionType, riskScore, systemsTouched, goal }, execute) {
return async (input) => {
const declaredGoal = typeof goal === 'function' ? goal(input) : goal;
// 1. GUARD: policy check before executing
const { decision, reasons } = await claw.guard({
action_type: actionType,
declared_goal: declaredGoal,
risk_score: riskScore,
systems_touched: systemsTouched,
});
if (decision === 'block') {
return `BLOCKED: ${(reasons || []).join(', ')}`;
}
// 2. RECORD: declare intent
const { action } = await claw.createAction({
action_type: actionType,
declared_goal: declaredGoal,
risk_score: riskScore,
systems_touched: systemsTouched,
});
// 3. HITL: wait for approval if required
if (decision === 'require_approval') {
try {
await claw.waitForApproval(action.action_id, { timeout: 120000 });
} catch (err) {
await claw.updateOutcome(action.action_id, {
status: 'cancelled',
error_message: String(err?.message || err),
});
return `DENIED: ${err?.message || err}`;
}
}
// 4. EXECUTE + OUTCOME
try {
const result = await execute(input);
await claw.updateOutcome(action.action_id, {
status: 'completed',
output_summary: typeof result === 'string' ? result : JSON.stringify(result),
});
return result;
} catch (err) {
await claw.updateOutcome(action.action_id, {
status: 'failed',
error_message: String(err?.message || err),
});
throw err;
}
};
}The guard decision drives the flow: 'block' returns early, 'require_approval' pauses for a human click on /approvals, 'allow' proceeds straight to execution. Note the Node SDK's waitForApproval takes milliseconds.
Define tools with governed execute functions
Wrap each tool at definition time, then hand the tools to generateText or streamText as usual: governance rides every model-initiated call.
agent.mjs
const refundOrder = tool({
description: 'Issue a refund for a customer order',
inputSchema: z.object({
orderId: z.string().describe('The order to refund'),
amountUsd: z.number().describe('Refund amount in USD'),
}),
execute: governed(
{
actionType: 'financial',
riskScore: 70,
systemsTouched: ['stripe'],
goal: ({ orderId, amountUsd }) => `Refund $${amountUsd} for order ${orderId}`,
},
async ({ orderId, amountUsd }) => `Refunded $${amountUsd} for order ${orderId}.`,
),
});
// Hand the tools to generateText / streamText — every tool call the model
// makes runs through the governance wrapper first.
import { generateText, isStepCount } from 'ai';
const { text } = await generateText({
model: 'anthropic/claude-sonnet-4-6',
tools: { refundOrder, lookupOrder },
stopWhen: isStepCount(5),
prompt: 'Customer 8841 wants a refund on order ord_1289 for $129.',
});Run the governed example
Execute the example and watch the governance flow: a low-risk lookup (allowed) and a high-risk refund (may require approval).
Terminal
npm start
No LLM API key needed: the example invokes the governed tools directly, exactly the way the model-driven tool-call step would. Only the DashClaw SDK calls are real.
Clone the full example
The complete runnable example is in the DashClaw repo.
Terminal
git clone https://github.com/ucsandman/DashClaw.git cd DashClaw/examples/vercel-ai-governed npm install npm start
What success looks like
Go to /decisions: you should see two actions in the ledger for agent_id 'vercel-ai-support-agent': the read lookup completed, and the financial refund either completed (after approval) or pending.
Navigate to /decisions in your DashClaw instance. Your action should appear in the ledger within seconds of the agent run.
Governance as Code
guardrails.yml is a policy-as-code template. Import it into your instance — POST the YAML to /api/policies/importor call the Python SDK's import_policies — and DashClaw evaluates these rules at the guard step before any action executes.
guardrails.yml
version: 1
project: my-ai-sdk-agent
description: >
Governance policy for an AI SDK support agent.
Financial actions require approval.
Read-only lookups are auto-allowed.
policies:
- id: approve_financial_actions
description: Refunds and charges require human approval
applies_to:
action_types:
- financial
systems:
- stripe
rule:
require: approval
- id: allow_reads
description: Read-only lookups are low risk
applies_to:
action_types:
- read
rule:
allow: true