@vigil/sdk Documentation

Instrument your LLM applications in under 5 minutes. Capture traces, monitor costs, detect hallucinations, and gain full observability over every model call, tool invocation, and agent workflow.

Installation

Install the SDK with your preferred package manager.

bun
1bun add @vigil/sdk
npm
1npm install @vigil/sdk

Quick Start

Four lines to full observability. Initialize Vigil, instrument your LLM client, make calls as usual, and flush before exit.

quick-start.ts
1import { Vigil } from '@vigil/sdk';
2import Anthropic from '@anthropic-ai/sdk';
3
4// 1. Initialize Vigil
5const vigil = new Vigil({
6 apiKey: process.env.VIGIL_API_KEY,
7 projectId: 'my-project',
8});
9
10// 2. Instrument the Anthropic client
11const anthropic = new Anthropic();
12vigil.instrument('anthropic', anthropic);
13
14// 3. Make calls as usual -- Vigil captures everything
15const message = await anthropic.messages.create({
16 model: 'claude-sonnet-4-20250514',
17 max_tokens: 1024,
18 messages: [{ role: 'user', content: 'Explain quantum computing' }],
19});
20
21// 4. Flush before process exit (serverless / scripts)
22await vigil.flush();

Auto-Instrumentation

Wrap your existing SDK clients with a single call. Vigil intercepts all API requests and captures traces automatically -- no code changes to your business logic.

Anthropic SDK

anthropic
1import Anthropic from '@anthropic-ai/sdk';
2
3const anthropic = new Anthropic();
4vigil.instrument('anthropic', anthropic);
5
6// All messages.create() and messages.stream() calls
7// are automatically traced with:
8// - Model name, provider
9// - Token counts (prompt + completion)
10// - Cost (USD), computed from built-in pricing table
11// - Latency (ms)
12// - Full prompt and completion text

OpenAI SDK

openai
1import OpenAI from 'openai';
2
3const openai = new OpenAI();
4vigil.instrument('openai', openai);
5
6// Traces chat.completions.create(), responses.create(),
7// and streaming variants automatically.

MCP Client

Differentiator

Vigil is the first observability SDK to treat MCP tool calls as first-class citizens. Every tool invocation is captured with full input/output payloads, server identity, and parent span linkage -- so you can see exactly which LLM call triggered which tool, and how long each tool took.

mcp-client
1import { Client } from '@modelcontextprotocol/sdk/client/index.js';
2
3const mcpClient = new Client({
4 name: 'my-app',
5 version: '1.0.0',
6});
7
8vigil.instrument('mcp', mcpClient);
9
10// Every MCP tool call is now traced:
11// - Tool name and server identity
12// - Input arguments and output results
13// - Latency per tool invocation
14// - Parent span linkage (which LLM call triggered this tool?)
15//
16// This is the only observability SDK that treats
17// MCP tool calls as first-class spans.

Vercel AI SDK

vercel-ai
1import { generateText, streamText } from 'ai';
2
3vigil.instrument('vercel-ai', { generateText, streamText });
4
5// Works with any Vercel AI SDK provider:
6// anthropic, openai, google, mistral, etc.
7// Traces model, tokens, cost, and latency.

Manual Tracing

For full control over your trace hierarchy, use the manual tracing API. Create traces, then attach typed spans for LLM calls, tool invocations, agent workflows, or arbitrary operations.

MethodSpan KindUse Case
trace.span()genericAny custom operation
trace.llm()llmLLM API calls with token/cost tracking
trace.tool()toolTool or MCP tool invocations
trace.agent()agentAgent workflows (wraps child spans)
manual-tracing.ts
1// Create a trace for a multi-step workflow
2const trace = vigil.trace('research-workflow');
3
4// LLM span
5const llmSpan = trace.llm('generate-outline', {
6 model: 'claude-sonnet-4-20250514',
7 provider: 'anthropic',
8});
9llmSpan.setInput({ messages: [{ role: 'user', content: '...' }] });
10// ... make the actual LLM call ...
11llmSpan.setOutput({ completion: '...' });
12llmSpan.setTokens({ prompt: 150, completion: 420 });
13llmSpan.end();
14
15// Tool span
16const toolSpan = trace.tool('web-search', {
17 toolName: 'brave_search',
18 toolServer: 'brave-mcp',
19});
20toolSpan.setInput({ query: 'latest AI research' });
21// ... execute the tool call ...
22toolSpan.setOutput({ results: ['...'] });
23toolSpan.end();
24
25// Agent span (wraps other spans)
26const agentSpan = trace.agent('research-agent', {
27 agentType: 'orchestrator',
28});
29// ... agent logic with nested llm() and tool() spans ...
30agentSpan.end();
31
32// Generic span for custom operations
33const span = trace.span('post-processing');
34// ... any custom logic ...
35span.end();
36
37trace.end();

Hallucination Detection

Vigil includes built-in hallucination detection that runs on every LLM span. Enable context grounding to score responses against your RAG source documents, or self-consistency to catch internal contradictions. Scores are attached to spans and surfaced in the dashboard.

Context Grounding

Compares LLM output against provided context chunks. Measures what percentage of response claims are supported by source documents.

Requires passing context via span.setContext()

Self-Consistency

Detects internal contradictions within a single response using rule-based NLI patterns. No external model required.

Always available, no configuration needed

hallucination-detection.ts
1vigil.setHallucinationDetector({
2 // Compare LLM output against provided RAG context.
3 // Scores how much of the response is grounded in source docs.
4 contextGrounding: true,
5
6 // Detect internal contradictions within a single response.
7 // Uses rule-based NLI patterns (no external model needed).
8 selfConsistency: true,
9
10 // Flag responses with a hallucination score above this value.
11 // Range: 0.0 (no hallucination) to 1.0 (fully hallucinated).
12 threshold: 0.7,
13});
14
15// When context grounding is enabled, pass context with your traces:
16const span = trace.llm('rag-answer', {
17 model: 'claude-sonnet-4-20250514',
18 provider: 'anthropic',
19});
20span.setContext([
21 'Source document chunk 1...',
22 'Source document chunk 2...',
23]);
24span.setInput({ messages: [{ role: 'user', content: '...' }] });
25// ... LLM call ...
26span.setOutput({ completion: '...' });
27span.end();
28// Hallucination score is computed automatically and attached to the span.

Configuration

All available options for the Vigil constructor. Only apiKey and projectId are required.

vigil-config.ts
1import { Vigil, type VigilConfig } from '@vigil/sdk';
2
3const vigil = new Vigil({
4 // Required
5 apiKey: process.env.VIGIL_API_KEY,
6 projectId: 'my-project',
7
8 // Endpoint (default: https://api.vigil.dev)
9 endpoint: 'https://api.vigil.dev',
10
11 // Batching: flush traces in batches for efficiency
12 batchSize: 10, // Spans per batch (default: 10)
13 flushInterval: 5000, // Auto-flush interval in ms (default: 5000)
14
15 // Sampling: control trace volume in production
16 sampleRate: 1.0, // 0.0 to 1.0 (default: 1.0 = capture all)
17
18 // Payload limits
19 maxPayloadSize: 4096, // Bytes before offloading to R2 (default: 4096)
20
21 // Debug mode: logs SDK activity to console
22 debug: false, // (default: false)
23
24 // Hallucination detection (can also use setHallucinationDetector)
25 hallucination: {
26 contextGrounding: false,
27 selfConsistency: false,
28 threshold: 0.7,
29 },
30});

Self-Hosting

Run the full Vigil stack on your own infrastructure with Docker Compose. The self-hosted version uses SQLite for storage and MinIO as an S3-compatible blob store.

docker-compose.yml
1# docker-compose.yml
2version: '3.8'
3
4services:
5 vigil-api:
6 image: ghcr.io/vigil-dev/api:latest
7 ports:
8 - '8787:8787'
9 environment:
10 - DATABASE_URL=/data/vigil.db
11 - STORAGE_BACKEND=minio
12 - MINIO_ENDPOINT=minio:9000
13 - MINIO_ACCESS_KEY=vigil
14 - MINIO_SECRET_KEY=vigilsecret
15 - MINIO_BUCKET=vigil-traces
16 volumes:
17 - vigil-data:/data
18 depends_on:
19 - minio
20
21 vigil-dashboard:
22 image: ghcr.io/vigil-dev/dashboard:latest
23 ports:
24 - '3000:3000'
25 environment:
26 - VIGIL_API_URL=http://vigil-api:8787
27 - NEXTAUTH_SECRET=your-secret-here
28 - NEXTAUTH_URL=http://localhost:3000
29
30 minio:
31 image: minio/minio:latest
32 command: server /data --console-address ":9001"
33 ports:
34 - '9000:9000'
35 - '9001:9001'
36 environment:
37 - MINIO_ROOT_USER=vigil
38 - MINIO_ROOT_PASSWORD=vigilsecret
39 volumes:
40 - minio-data:/data
41
42volumes:
43 vigil-data:
44 minio-data:
usage
1# Start the stack
2docker compose up -d
3
4# Point your SDK to the self-hosted API
5const vigil = new Vigil({
6 apiKey: 'your-self-hosted-key',
7 projectId: 'my-project',
8 endpoint: 'http://localhost:8787',
9});

API Reference

The Vigil REST API. All endpoints require a Bearer token in the Authorization header.

MethodEndpointDescription
POST/v1/tracesIngest a batch of traces and spans
GET/v1/tracesList traces with filtering and pagination
GET/v1/traces/:traceIdGet a single trace with all its spans
GET/v1/traces/:traceId/spansGet spans for a specific trace
GET/v1/analytics/costsCost analytics grouped by model, agent, or tool
GET/v1/analytics/hallucinationsHallucination score trends and flagged spans
POST/v1/promptsCreate a new prompt version
GET/v1/prompts/:name/versionsList all versions of a named prompt
api-usage.ts
1// All endpoints require Bearer token authentication
2const response = await fetch('https://api.vigil.dev/v1/traces', {
3 method: 'GET',
4 headers: {
5 'Authorization': 'Bearer YOUR_API_KEY',
6 'Content-Type': 'application/json',
7 },
8});
9
10const { traces, total } = await response.json();
11
12// Query parameters for GET /v1/traces:
13// project_id (required) Your project ID
14// limit (optional) Results per page (default: 50)
15// offset (optional) Pagination offset (default: 0)
16// model (optional) Filter by model name
17// status (optional) Filter by status: 'ok' | 'error'
18// min_cost (optional) Minimum cost in USD
19// max_cost (optional) Maximum cost in USD
20// from (optional) Start datetime (ISO 8601)
21// to (optional) End datetime (ISO 8601)

Built by the Vigil team. Source on GitHub.