
Research
/Security News
PolinRider Spreads Through Compromised GitHub Accounts and Packagist
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.
@blacklake-systems/sdk
Advanced tools
TypeScript SDK for BlackLake Surface — agent governance infrastructure
TypeScript SDK for BlackLake Surface — agent governance infrastructure.
npm install @blacklake-systems/sdk
import { BlackLake } from '@blacklake-systems/sdk';
const bl = new BlackLake({
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
}
Sign up at console.blacklake.systems to get your API key. The console also provides a dashboard for managing agents, tools, policies, and reviewing the audit trail.
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.agentsawait 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.toolsawait bl.tools.create({ name, risk_classification, description? });
await bl.tools.list();
await bl.tools.get(id);
bl.policiesawait 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.evaluationsawait bl.evaluations.list({ agent_id?, tool_id?, outcome?, limit?, offset? });
await bl.evaluations.get(id);
bl.organisationawait 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.apiKeysawait 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.approvalsawait 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.webhooksawait 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.
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);
}
}
Full documentation at blacklake.systems/docs.
FAQs
TypeScript SDK for BlackLake Surface — agent governance infrastructure
We found that @blacklake-systems/sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.

Security News
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.

Company News
Allow myself to introduce... myself.