@fulcrum-governance/sdk
v0.1.5
Published
TypeScript SDK for Fulcrum - Intelligent AI Governance Platform
Maintainers
Readme
Fulcrum TypeScript SDK
Intelligent AI Governance for Enterprise Agents
Installation
npm install @fulcrum-governance/sdkQuick Start
Hosted Fulcrum uses the REST API and X-API-Key authentication:
import {
PolicyClient,
EnvelopeClient,
} from '@fulcrum-governance/sdk';
const apiBase = process.env.FULCRUM_API_BASE || 'https://api.fulcrumlayer.io';
const apiKey = process.env.FULCRUM_API_KEY!;
const policyClient = new PolicyClient({
baseUrl: apiBase,
apiKey,
});
const policies = await policyClient.list();
console.log(`Visible policies: ${policies.length}`);
const envelopes = new EnvelopeClient({
baseUrl: apiBase,
apiKey,
});
const envelope = await envelopes.create({
workflow_id: 'customer-support-bot',
metadata: { example: 'typescript-sdk' },
});
await envelopes.updateStatus({
envelope_id: envelope.envelope_id,
status: 'RUNNING',
});
// Run your agent work here, then close the envelope.
await envelopes.updateStatus({
envelope_id: envelope.envelope_id,
status: 'COMPLETED',
});Features
- Policy Enforcement: Real-time governance checks before agent actions
- Cost Tracking: Monitor and control LLM spending per workflow
- Audit Trail: Complete execution history for compliance
- Fail-Safe Modes: Configurable FAIL_OPEN or FAIL_CLOSED behavior
- TypeScript Support: Full type definitions included
Configuration
Client Options
import { FulcrumClient, FailureMode } from '@fulcrum-governance/sdk';
const client = new FulcrumClient({
host: 'localhost:50051', // Fulcrum server address
apiKey: 'your-api-key', // API key for authentication
tenantId: 'your-tenant-id', // Default tenant ID
onFailure: FailureMode.FAIL_OPEN, // FAIL_OPEN or FAIL_CLOSED
timeoutMs: 500, // Request timeout in milliseconds
enableTls: true, // Enable TLS encryption
caCertPath: '/path/to/ca.crt', // Custom CA certificate (optional)
});Environment Variables
export FULCRUM_API_KEY="your-api-key"
export FULCRUM_API_BASE="https://api.fulcrumlayer.io"
export FULCRUM_TIMEOUT_MS="500"The lower-level FulcrumClient gRPC API is still available for compatible
self-hosted or direct gRPC deployments. The hosted first-run path uses the REST
clients above.
API Reference
FulcrumClient
interface FulcrumClientOptions {
host: string; // gRPC server address (e.g., 'localhost:50051')
apiKey?: string; // Authentication key
tenantId?: string; // Default tenant ID
onFailure?: 'FAIL_OPEN' | 'FAIL_CLOSED'; // Behavior on errors
timeoutMs?: number; // Request timeout (default: 500ms)
enableTls?: boolean; // Enable TLS (default: false for localhost)
caCertPath?: string; // Custom CA certificate path
}Methods
| Method | Description |
|--------|-------------|
| envelope(options) | Create a governance envelope |
| evaluate(action, inputText, context) | Evaluate a policy decision |
| getCost(envelopeId) | Get cost for an envelope |
| listPolicies(tenantId) | List active policies |
| healthCheck() | Check server connectivity |
Envelope
interface EnvelopeOptions {
workflowId: string; // Identifier for the workflow
executionId?: string; // Auto-generated if not provided
tenantId?: string; // Defaults to client tenant
metadata?: Record<string, string>; // Additional context
}Methods
| Method | Signature | Description |
|--------|-----------|-------------|
| guard | (actionName: string, inputText: string, metadata?: Record<string, string>) => Promise<boolean> | Check if action is allowed |
| log | (eventType: string, payload: Record<string, any>) => void | Log event for audit |
| checkpoint | () => Promise<Checkpoint> | Create execution checkpoint |
| getCost | () => Promise<CostSnapshot> | Get current execution cost |
| complete | (result?: any) => Promise<void> | Mark envelope complete |
Error Handling
import { FulcrumClient } from '@fulcrum-governance/sdk';
import {
FulcrumError, // Base error class
PolicyViolationError, // Action blocked by policy
BudgetExceededError, // Budget limit reached
ConnectionError, // Server unreachable
AuthenticationError, // Invalid API key
TimeoutError, // Request timed out
} from '@fulcrum-governance/sdk/errors';
const client = new FulcrumClient({
host: 'localhost:50051',
apiKey: 'your-key'
});
try {
const envelope = client.envelope({ workflowId: 'my-agent' });
const allowed = await envelope.guard('send_email', 'Hello');
if (allowed) {
await sendEmail('Hello');
}
await envelope.complete();
} catch (error) {
if (error instanceof PolicyViolationError) {
console.log(`Policy violation: ${error.policyId}`);
console.log(`Reason: ${error.message}`);
console.log(`Matched rules: ${error.matchedRules.join(', ')}`);
} else if (error instanceof BudgetExceededError) {
console.log(`Budget exceeded: $${error.currentSpend} / $${error.budgetLimit}`);
} else if (error instanceof ConnectionError) {
console.log(`Cannot reach Fulcrum server: ${error.message}`);
// Handle based on failure mode
} else if (error instanceof TimeoutError) {
console.log('Request timed out');
} else {
throw error;
}
}Integration Examples
Vercel AI SDK
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { FulcrumClient } from '@fulcrum-governance/sdk';
const fulcrum = FulcrumClient.fromEnv();
export async function POST(req: Request) {
const { messages } = await req.json();
const lastMessage = messages[messages.length - 1].content;
const envelope = fulcrum.envelope({
workflowId: 'vercel-ai-chat',
metadata: { source: 'api' }
});
// Pre-check message
if (!await envelope.guard('process_message', lastMessage)) {
return new Response('Message blocked by policy', { status: 403 });
}
const result = await streamText({
model: openai('gpt-4'),
messages,
onFinish: async ({ usage }) => {
envelope.log('completion', {
inputTokens: usage.promptTokens,
outputTokens: usage.completionTokens,
});
await envelope.complete();
}
});
return result.toAIStreamResponse();
}LangChain.js Integration
import { ChatOpenAI } from '@langchain/openai';
import { AgentExecutor } from 'langchain/agents';
import { FulcrumClient } from '@fulcrum-governance/sdk';
const fulcrum = FulcrumClient.fromEnv();
async function runGovernedAgent(
agent: AgentExecutor,
query: string
): Promise<string> {
const envelope = fulcrum.envelope({
workflowId: 'langchain-agent'
});
// Check if query is allowed
if (!await envelope.guard('process_query', query)) {
throw new Error('Query blocked by policy');
}
// Run agent
const result = await agent.invoke({
input: query,
callbacks: [{
handleToolStart: async (tool, input) => {
const allowed = await envelope.guard(tool.name, JSON.stringify(input));
if (!allowed) {
envelope.log('tool_blocked', { tool: tool.name });
throw new Error(`Tool ${tool.name} blocked by policy`);
}
},
handleToolEnd: (output) => {
envelope.log('tool_executed', { output: output.substring(0, 100) });
}
}]
});
await envelope.complete({ result: result.output });
return result.output;
}Express Middleware
import express from 'express';
import { FulcrumClient } from '@fulcrum-governance/sdk';
const app = express();
const fulcrum = FulcrumClient.fromEnv();
// Governance middleware
const governanceMiddleware = (workflowId: string) => {
return async (req: express.Request, res: express.Response, next: express.NextFunction) => {
const envelope = fulcrum.envelope({
workflowId,
metadata: {
path: req.path,
method: req.method,
userId: req.headers['x-user-id'] as string,
}
});
// Attach to request for use in handlers
(req as any).fulcrumEnvelope = envelope;
// Check request
const inputText = JSON.stringify(req.body);
if (!await envelope.guard('api_request', inputText)) {
return res.status(403).json({ error: 'Request blocked by policy' });
}
// Complete envelope on response finish
res.on('finish', () => {
envelope.log('response', { status: res.statusCode });
envelope.complete();
});
next();
};
};
app.use('/api/agents', governanceMiddleware('agent-api'));Cost Tracking
const envelope = client.envelope({ workflowId: 'my-agent' });
// ... agent execution ...
const cost = await envelope.getCost();
console.log(`Total cost: $${cost.totalUsd.toFixed(4)}`);
console.log(`Input tokens: ${cost.inputTokens}`);
console.log(`Output tokens: ${cost.outputTokens}`);
console.log(`LLM calls: ${cost.llmCalls}`);
// Model breakdown
for (const [model, stats] of Object.entries(cost.modelBreakdown)) {
console.log(` ${model}: $${stats.cost.toFixed(4)} (${stats.calls} calls)`);
}Type Definitions
interface PolicyDecision {
allowed: boolean;
policyId?: string;
decision: 'ALLOW' | 'DENY' | 'WARN' | 'REQUIRE_APPROVAL';
matchedRules: RuleMatch[];
actions: PolicyAction[];
message?: string;
}
interface RuleMatch {
ruleId: string;
ruleName: string;
matchedConditions: string[];
}
interface CostSnapshot {
totalUsd: number;
inputTokens: number;
outputTokens: number;
llmCalls: number;
toolCalls: number;
modelBreakdown: Record<string, { calls: number; cost: number }>;
}
interface Checkpoint {
checkpointId: string;
version: number;
stateHash: string;
createdAt: Date;
}REST Clients
The SDK includes REST-based clients for managing Fulcrum resources through the Dashboard API. These clients are ideal for administrative tasks, dashboards, and browser environments.
PolicyClient
List governance policies visible to your API key. Create and edit hosted policies in the Fulcrum dashboard before using the API-key gateway.
import { PolicyClient } from '@fulcrum-governance/sdk';
const policyClient = new PolicyClient({
baseUrl: 'https://api.fulcrumlayer.io',
apiKey: 'your-api-key',
timeoutMs: 5000 // optional, default: 5000
});
// List all policies
const policies = await policyClient.list();
// List with filters
const activePolicies = await policyClient.list({
status: 'ACTIVE'
});
// Get a specific policy
const policy = await policyClient.get('policy-id');ApprovalClient
Manage human-in-the-loop approval workflows:
import { ApprovalClient } from '@fulcrum-governance/sdk';
const approvalClient = new ApprovalClient({
baseUrl: 'https://your-fulcrum-dashboard.com',
apiKey: 'your-api-key'
});
// List all pending approvals
const pending = await approvalClient.listPending();
// List with filters
const approvals = await approvalClient.list({
status: 'pending',
workflow_id: 'customer-support-bot'
});
// Get approval details
const approval = await approvalClient.get('approval-id');
// Approve a request
await approvalClient.approve('approval-id', 'Looks safe to proceed');
// Deny a request
await approvalClient.deny('approval-id', 'Contains sensitive information');
// Generic decision method
await approvalClient.decide('approval-id', {
decision: 'approved', // or 'denied'
comment: 'Reviewed and approved'
});BudgetClient
Manage AI spending budgets and limits:
import { BudgetClient } from '@fulcrum-governance/sdk';
const budgetClient = new BudgetClient({
baseUrl: 'https://your-fulcrum-dashboard.com',
apiKey: 'your-api-key'
});
// List all budgets with summary
const { budgets, summary } = await budgetClient.list();
console.log(`Total budgets: ${summary.total}`);
console.log(`Active: ${summary.active}, Exceeded: ${summary.exceeded}`);
// Filter by scope or status
const tenantBudgets = await budgetClient.listBudgets({ scope: 'TENANT' });
const exceededBudgets = await budgetClient.getExceeded();
const warningBudgets = await budgetClient.getWarnings();
// Get a specific budget
const budget = await budgetClient.get('budget-id');
// Create a new budget
const newBudget = await budgetClient.create({
name: 'Marketing Team Monthly',
scope: 'TENANT', // GLOBAL, TENANT, WORKFLOW, MODEL
scope_id: 'tenant-123',
limit_amount: 1000, // in dollars
period: 'MONTHLY', // DAILY, WEEKLY, MONTHLY, QUARTERLY
action: 'SOFT_LIMIT', // WARN, SOFT_LIMIT, HARD_LIMIT
alert_thresholds: [50, 75, 90]
});
// Update budget
await budgetClient.update('budget-id', {
limit_amount: 1500,
alert_thresholds: [60, 80, 95]
});
// Helper methods
const percentage = budgetClient.calculatePercentage(budget);
const isNearLimit = budgetClient.isAtThreshold(budget, 80);
// Delete a budget
await budgetClient.delete('budget-id');MetricsClient
Access platform metrics and audit logs:
import { MetricsClient } from '@fulcrum-governance/sdk';
const metricsClient = new MetricsClient({
baseUrl: 'https://your-fulcrum-dashboard.com',
apiKey: 'your-api-key' // optional for public metrics
});
// Public metrics (no auth required)
const metrics = await metricsClient.getPublicMetrics();
console.log(`Policies evaluated (24h): ${metrics.policiesEvaluated24h}`);
console.log(`Avg latency: ${metrics.avgLatencyMs}ms`);
console.log(`Blocked requests: ${metrics.blockedRequests24h}`);
// Cognitive layer metrics
const cognitive = await metricsClient.getCognitiveMetrics();
console.log(`Semantic Judge violations: ${cognitive.semanticJudgeViolations}`);
console.log(`Oracle savings: $${cognitive.oracleSavings}`);
// Audit logs (auth required)
const { logs, pagination, actors } = await metricsClient.getAuditLogs({
resource_type: 'Policy',
start_date: '2026-01-01',
end_date: '2026-01-31',
page: 1,
page_size: 50
});
// Convenience methods for audit logs
const policyLogs = await metricsClient.getLogsByResourceType('Policy');
const userLogs = await metricsClient.getLogsByUser('user-id');
const recentLogs = await metricsClient.getLogsByDateRange(
new Date('2026-01-01'),
new Date('2026-01-31')
);
const searchResults = await metricsClient.searchAuditLogs('budget exceeded');REST Client Types
// Policy types
interface Policy {
id: string;
org_id: string;
name: string;
description: string;
rules: PolicyRule[];
priority: number;
enabled: boolean;
status: 'active' | 'inactive' | 'draft';
created_at: string;
updated_at: string;
}
// Approval types
interface Approval {
id: string;
envelope_id: string;
workflow_id: string;
action_name: string;
input_text: string;
status: 'pending' | 'approved' | 'denied' | 'expired';
requested_at: string;
decided_at?: string;
decided_by?: string;
comment?: string;
}
// Budget types
type BudgetScope = 'GLOBAL' | 'TENANT' | 'WORKFLOW' | 'MODEL';
type BudgetPeriod = 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'QUARTERLY';
type BudgetAction = 'WARN' | 'SOFT_LIMIT' | 'HARD_LIMIT';
type BudgetStatus = 'active' | 'warning' | 'exceeded' | 'disabled';
interface Budget {
id: string;
name: string;
scope: BudgetScope;
scope_id: string | null;
limit_amount: number;
current_spend: number;
period: BudgetPeriod;
action: BudgetAction;
status: BudgetStatus;
percentage: number;
alert_thresholds: number[];
}
// Metrics types
interface PublicMetrics {
lastUpdated: string;
policiesEvaluated24h: number;
avgLatencyMs: number;
budgetAlerts24h: number;
activeTenants: number;
blockedRequests24h: number;
cognitiveLayer: CognitiveLayerMetrics;
}
interface CognitiveLayerMetrics {
semanticJudgeRequests: number;
semanticJudgeViolations: number;
oraclePredictions: number;
oracleSavings: number;
immunePoliciesGenerated: number;
}
type ResourceType = 'User' | 'Policy' | 'Budget' | 'APIKey' | 'Workflow' | 'Envelope' | 'Approval';
interface AuditLogEntry {
id: string;
timestamp: string;
actor_id: string;
actor_email: string;
action: string;
resource_type: ResourceType;
resource_id?: string;
resource_name?: string;
status: 'success' | 'failure';
changes?: Record<string, { old: unknown; new: unknown }>;
}Error Handling for REST Clients
Each REST client has its own error class:
import {
PolicyClient,
PolicyClientError,
ApprovalClient,
ApprovalClientError,
BudgetClient,
BudgetClientError,
MetricsClient,
MetricsClientError
} from '@fulcrum-governance/sdk';
try {
const policy = await policyClient.get('invalid-id');
} catch (error) {
if (error instanceof PolicyClientError) {
console.log(`Error: ${error.message}`);
console.log(`Status: ${error.statusCode}`); // e.g., 404, 401, 500
}
}Browser Support
For browser environments, use the REST clients which work with the standard fetch API:
import { PolicyClient, BudgetClient, MetricsClient } from '@fulcrum-governance/sdk';
// REST clients work in browsers
const policyClient = new PolicyClient({
baseUrl: 'https://your-fulcrum-dashboard.com',
apiKey: 'your-api-key'
});
// For real-time governance (gRPC), use the REST envelope wrapper
// (Coming soon)Documentation
Full documentation: https://docs.fulcrum.dev
Support
- Email: [email protected]
- Documentation: https://docs.fulcrum.dev
- Issues: Contact your account representative
