JSPM

@blacklake-systems/surface-sdk

0.1.5
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 11
  • Score
    100M100P100Q11189F
  • License MIT

TypeScript SDK for BlackLake Surface — agent governance infrastructure

Package Exports

  • @blacklake-systems/surface-sdk

Readme

@blacklake-systems/sdk

TypeScript SDK for BlackLake Surface — integrate governance directly into custom agent code.

Note: If you are routing tool calls through the MCP proxy, you do not need this SDK. The proxy handles governance automatically. Use the SDK when you want to call the governance API directly from your own code.

Install

npm install @blacklake-systems/sdk

Quick Start

Local Surface (self-hosted)

Run npx @blacklake-systems/cli first to start Surface on your machine, then point the SDK at it:

import { BlackLake } from '@blacklake-systems/sdk';

const bl = new BlackLake({
  baseUrl: 'http://localhost:3100',
  apiKey: process.env.BLACKLAKE_API_KEY!,
});

// Evaluate governance before executing a tool call
const result = await bl.govern({
  agent: 'expense-bot',
  tool: 'payments.send',
  action: { amount: 4200, vendor: 'Acme Corp' },
});

if (result.decision === 'allow') {
  // proceed with tool call
}

Cloud Surface

Sign up at console.blacklake.systems to get your API key:

import { BlackLake } from '@blacklake-systems/sdk';

const bl = new BlackLake({
  apiKey: process.env.BLACKLAKE_API_KEY!,
  // baseUrl defaults to https://api.blacklake.systems
});

API Reference

new BlackLake(config)

Option Type Default Description
apiKey string Your BlackLake API key (required)
baseUrl string https://api.blacklake.systems API base URL. Override only for local development (e.g. http://localhost:3100).

bl.govern(request)

Evaluate whether an agent is allowed to invoke a tool.

const result = await bl.govern({
  agent: 'expense-bot',       // agent name
  tool: 'payments.send',      // tool name
  action: { amount: 4200 },   // optional: tool invocation payload
  context: { ip: '10.0.0.1' } // optional: request metadata
});

// result.decision: 'allow' | 'deny' | 'approval_required' | 'default_deny'
// result.evaluation_id: string
// result.policy_id: string | null
// result.reason: string
// result.evaluated_at: string (ISO 8601)
// result.approval_id: string | undefined (set when decision === 'approval_required')

bl.agents

await bl.agents.create({ name, environment, risk_classification, description?, approval_mode? });
await bl.agents.list({ environment?, status? });
await bl.agents.get(id);
await bl.agents.update(id, { name?, description?, environment?, risk_classification?, status?, approval_mode? });
await bl.agents.suspend(id);
await bl.agents.activate(id);
await bl.agents.bindTool(agentId, toolId);
await bl.agents.listTools(agentId);   // returns ToolBinding[] — each item has { binding_id, binding_created_at, tool: Tool }
await bl.agents.unbindTool(agentId, toolId);

bl.tools

await bl.tools.create({ name, risk_classification, description? });
await bl.tools.list();
await bl.tools.get(id);

bl.policies

await bl.policies.create({ name, priority, outcome, agent_selector?, tool_selector?, enabled? });
await bl.policies.list();
await bl.policies.get(id);
await bl.policies.update(id, { name?, priority?, outcome?, agent_selector?, tool_selector?, enabled? });
await bl.policies.delete(id);

bl.evaluations

await bl.evaluations.list({ agent_id?, tool_id?, outcome?, limit?, offset? });
await bl.evaluations.get(id);

bl.organisation

await bl.organisation.get();                  // fetch the current organisation (derived from the API key)
await bl.organisation.delete(confirmation);   // permanently delete the organisation; pass the organisation's exact name as confirmation

bl.apiKeys

await bl.apiKeys.list();              // returns { keys: ApiKey[] } — each item has { id, name, key_suffix, created_at, revoked_at }
await bl.apiKeys.create('prod-key');  // returns { id, name, key, created_at, warning } — the raw key is shown ONCE; store it securely
await bl.apiKeys.revoke(id);          // sets revoked_at on the key; the API rejects revoking the key in use

bl.approvals

await bl.approvals.list({ status?, agent_id?, tool_id?, limit?, offset? });  // returns PaginatedResponse<Approval>
await bl.approvals.get(id);
await bl.approvals.status(id);                                               // returns ApprovalStatusResponse — lightweight poll target
await bl.approvals.approve(id, { decided_by, reason });
await bl.approvals.reject(id, { decided_by, reason });
await bl.approvals.wait(id, { interval?, timeout? });                        // polls status until approved/rejected/expired; throws BlackLakeError on timeout

wait() defaults to polling every 2 000 ms with a 5-minute total timeout. Returns the fully-populated Approval once the status leaves 'pending'.

bl.webhooks

await bl.webhooks.list();                                          // returns { webhooks: Webhook[] }
await bl.webhooks.create({ url, events, enabled? });              // returns CreatedWebhook — the raw signing secret is shown ONCE; store it securely
await bl.webhooks.get(id);
await bl.webhooks.update(id, { url?, events?, enabled? });
await bl.webhooks.delete(id);
await bl.webhooks.listDeliveries(id, { limit?, offset? });        // returns PaginatedResponse<WebhookDelivery>

Webhooks fire on 'approval.created', 'approval.approved', and 'approval.rejected'. Each request is signed with HMAC-SHA256; the signature is sent in the X-BlackLake-Signature header.

Error Handling

import { BlackLake, BlackLakeError } from '@blacklake-systems/sdk';

try {
  await bl.govern({ agent: 'unknown', tool: 'unknown' });
} catch (err) {
  if (err instanceof BlackLakeError) {
    console.error(err.status, err.code, err.message);
  }
}

Documentation

Full documentation at blacklake.systems/docs.