← Vetro Attest

Integrations

Whatever runs your agent, Vetro records each LLM call, tool call, cost and policy decision into a hash-chained, ed25519-signed ledger (.vetro/runs/*.vtl) that anyone can verify, and that we can countersign for your EU AI Act file. Every snippet below is taken from a working example we run in CI.

Install steps for @vetro/core and the CLI are on the quickstart. Framework adapters marked adapter file are a single dependency-free file you drop into your project: download it from the link in each section.

Anthropic SDK (Claude)

import Anthropic from '@anthropic-ai/sdk';
import { Vetro } from '@vetro/core';
import { wrapAnthropic } from '@vetro/anthropic';

const run = new Vetro().startRun({ name: 'my-agent' });
const client = wrapAnthropic(new Anthropic(), run); // the only change
// ... use client exactly as before, streaming included ...
run.end();

Records and policy-guards every Claude call: model, params, token usage, cost, content.

OpenAI SDK

import OpenAI from 'openai';
import { Vetro } from '@vetro/core';
import { wrapOpenAI } from '@vetro/openai';

const run = new Vetro().startRun({ name: 'my-agent' });
const client = wrapOpenAI(new OpenAI(), run); // the only change
run.end();

Covers chat.completions and responses.

Python (Anthropic, OpenAI)

import anthropic
from vetro import Vetro, wrap_anthropic   # or wrap_openai

run = Vetro().start_run(name="my-agent")
claude = wrap_anthropic(anthropic.Anthropic(), run)
run.end()

Sync and async clients, streaming included. Same ledger format as Node: vetro verify checks both.

Google Gemini (@google/genai) adapter file

import { GoogleGenAI } from '@google/genai';
import { Vetro, registerPrice } from '@vetro/core';
import { wrapGemini } from './gemini-adapter.mjs';

registerPrice('gemini-2.5-flash', { inputPerMTok: 0.3, outputPerMTok: 2.5 });
const run = new Vetro().startRun({ name: 'my-agent' });
const ai = wrapGemini(new GoogleGenAI({}), run);
await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: 'hi' });
run.end();

Wraps models.generateContent (non-streaming); usage comes from usageMetadata. Download gemini-adapter.mjs

Vercel AI SDK

npm i https://attest.piratefly.com/dl/vetro-core-0.1.0.tgz https://attest.piratefly.com/dl/vetro-vercel-ai-0.1.0.tgz
import { wrapLanguageModel, generateText } from 'ai';
import { Vetro } from '@vetro/core';
import { createVetroMiddleware } from '@vetro/vercel-ai';

const run = new Vetro().startRun({ name: 'my-agent' });
const model = wrapLanguageModel({
  model: yourModel,                   // any AI SDK LanguageModel
  middleware: createVetroMiddleware(run),
});
await generateText({ model, prompt: '…' });  // guarded + recorded
run.end();

Records generateText and streamText (model, params, usage, finish reason, content); a blocking policy rule stops the call before it is sent. Single-file version: vercel-ai-sdk-middleware.mjs

LangChain.js

npm i https://attest.piratefly.com/dl/vetro-core-0.1.0.tgz https://attest.piratefly.com/dl/vetro-langchain-0.1.0.tgz
import { Vetro } from '@vetro/core';
import { createVetroCallbackHandler } from '@vetro/langchain';

const run = new Vetro().startRun({ name: 'support-agent' });
await agent.invoke({ input }, { callbacks: [createVetroCallbackHandler(run)] });
run.end('completed');

Records llm.request/llm.response with token usage and cost, tool.call/tool.result, chain start/end (recordChains: false to skip) and errors. A block stops the chain. { recordContent: false } keeps prompts out of the ledger.

LlamaIndex.TS adapter file

import { Settings } from 'llamaindex';
import { Vetro } from '@vetro/core';
import { attachVetroCallbacks, wrapVetroTool } from './llamaindex-callback.mjs';

const run = new Vetro().startRun({ name: 'rag-agent' });
attachVetroCallbacks(Settings.callbackManager, run, { model: 'gpt-5' });
const guardedTool = wrapVetroTool(myTool, run);  // synchronous block on tool calls
run.end();

Records LLM start/end and tool call/result events. LlamaIndex callbacks are fire-and-forget, so wrap tools with wrapVetroTool when a policy must actually stop them. Download llamaindex-callback.mjs

Mastra adapter file

import { Agent } from '@mastra/core/agent';
import { Vetro } from '@vetro/core';
import { createVetroProcessor, wrapVetroTool } from './mastra-processor.mjs';

const run = new Vetro().startRun({ name: 'support-agent' });
const vetroProcessor = createVetroProcessor(run);
const agent = new Agent({
  id: 'support-agent',
  model: 'anthropic/claude-sonnet-4-5',
  inputProcessors: [vetroProcessor],   // processLLMRequest
  outputProcessors: [vetroProcessor],  // processOutputStep
  tools: { refund: wrapVetroTool(refundTool, run) },
});

Records each LLM request and step output; a blocking rule trips Mastra's TripWire. Download mastra-processor.mjs

OpenAI Agents SDK

npm i https://attest.piratefly.com/dl/vetro-core-0.1.0.tgz https://attest.piratefly.com/dl/vetro-openai-agents-0.1.0.tgz
import { addTraceProcessor } from '@openai/agents';
import { Vetro } from '@vetro/core';
import { createVetroTracingProcessor } from '@vetro/openai-agents';

const run = new Vetro().startRun({ name: 'my-agent' });
addTraceProcessor(createVetroTracingProcessor(run));
// ... run your agents as usual ...
run.end();

Generation spans become LLM events (usage normalized by @vetro/openai), function spans become tool calls, handoffs and guardrails are recorded too. Single-file version: openai-agents-tracer.mjs

Claude Code (hook) adapter file

Record every tool a coding agent uses, and block the ones your policy denies. Run vetro init in the project (it writes vetro.policy.json), save claude-code-hook.mjs next to it, then add to .claude/settings.json:

{
  "hooks": {
    "PreToolUse":  [{ "hooks": [{ "type": "command", "command": "node claude-code-hook.mjs" }] }],
    "PostToolUse": [{ "hooks": [{ "type": "command", "command": "node claude-code-hook.mjs" }] }],
    "Stop":        [{ "hooks": [{ "type": "command", "command": "node claude-code-hook.mjs" }] }]
  }
}

Tool calls and results are buffered per session and sealed into one signed ledger at Stop. tool.deny and content.regex rules block in real time (exit code 2); budget rules are evaluated at Stop. Try it without Claude Code: node claude-code-hook.mjs --demo.

n8n community node

A Vetro node for your AI agent workflows, with zero runtime dependencies. Record Ledger turns the input items into one hash-chained ledger (ed25519-signed if you add a PEM key to the credential), Verify Ledger catches any edited, dropped or reordered event, Attest Ledger returns a public verification link for your auditor. Self-hosted n8n:

mkdir -p ~/.n8n/nodes && cd ~/.n8n/nodes
npm i https://attest.piratefly.com/dl/vetro-n8n-nodes-vetro-0.1.0.tgz
# restart n8n, then search "Vetro" in the nodes panel

Docker: run the same npm i inside the volume mounted at /home/node/.n8n/nodes. Typical flow: AI Agent → Vetro: Record Ledger → Vetro: Attest Ledger → Slack / Email with the link. Record and Verify are free and run offline; Attest needs a vk_ key from the Continuous plan.

OpenTelemetry / OTLP

Already tracing with OpenTelemetry GenAI conventions (Langfuse, LangSmith, Arize Phoenix, Helicone, a Collector)? No SDK change: export the trace as OTLP/JSON and drop it on the verify box, or convert locally:

vetro otel import trace.json --out-dir .vetro/imported   # OTel GenAI trace -> ledger
vetro otel export .vetro/runs/run.vtl -o trace.json      # ledger -> OTLP/JSON spans

Programmatic: importOtlpToLedgers(payload) and exportLedgerToOtlp(events) from @vetro/otel. Step-by-step exports: Langfuse · LangSmith · Arize Phoenix · Helicone.

MCP server: EU AI Act tools

A local stdio MCP server (no API key, no network) with classify_high_risk, penalty_estimate, gpai_obligations, log_retention and verify_ledger, for Claude Desktop, Claude Code, Cursor and any MCP client:

{ "mcpServers": { "eu-ai-act": { "command": "npx", "args": ["-y", "@vetro/mcp-ai-act"] } } }
claude mcp add eu-ai-act -- npx -y @vetro/mcp-ai-act

GitHub Action

Fail the build when any committed agent ledger has a broken hash chain or signature; optionally get each one countersigned:

# .github/workflows/agent-ledger.yml
name: agent-ledger
on: [push, pull_request]
jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: vetro/verify-action@v1
        with:
          ledger-glob: '.vetro/runs/*.vtl'
          # anchor-file: '.vetro/anchors.jsonl'
          # attest-api-key: ${{ secrets.VETRO_ATTEST_KEY }}

Then: verify free, countersign for your auditor

Any ledger from any of these integrations verifies with vetro verify .vetro/runs/*.vtl or on the home page. When it verifies, you can get the EU AI Act record-keeping report: a third-party countersignature, a PDF mapping the log to Art. 12, 14, 26 and 86, and a public link anyone can check.

See a sample ledger verifiedQuickstartPricing

Pricing