HomeConnectVercel AI SDK

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

1

Deploy DashClaw

Get a running instance. Click the Vercel deploy button or run locally.

Already have an instance? Skip to Step 2.

2

Install the DashClaw Node SDK and the AI SDK

Add the packages to your project.

Terminal

npm install dashclaw ai zod dotenv
3

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_...
4

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.

5

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.',
});
6

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.

7

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