Getting started

Install the SDK and run your first security check.


Prerequisites

  • Security Layer CLI installed and initialized (sl init)
  • Node.js 18+ or Bun 1.0+

Installation

npm install @securitylayerai/sdk
yarn add @securitylayerai/sdk
pnpm add @securitylayerai/sdk
bun add @securitylayerai/sdk

Basic setup

import { createSecurityLayer } from "@securitylayerai/sdk";

// Initialize with default config (reads ~/.securitylayer/)
const sl = await createSecurityLayer();

// Or with explicit configuration
const sl = await createSecurityLayer({
  configDir: "/path/to/.securitylayer",
  sessionId: "session-123",
});

Your first check

Every tool call your agent makes should pass through sl.check() before execution:

async function runTool(tool: string, params: Record<string, unknown>) {
  const result = await sl.check(tool, params);

  switch (result.decision) {
    case "ALLOW":
      // Safe to execute
      return executeToolCall(tool, params);

    case "DENY":
      // Structurally blocked — do not execute
      throw new Error(`Security Layer: ${result.reason}`);

    case "REQUIRE_APPROVAL":
      // Needs human approval before proceeding
      const approved = await sl.waitForApproval(result.approvalId as string);
      if (!approved) throw new Error("Approval denied or timed out");
      return executeToolCall(tool, params);
  }
}

You can also override the session ID for a specific check:

const result = await sl.check("exec", { command: "ls" }, {
  sessionId: "different-session",
});

Understanding decisions

Every check returns a CheckResult with the decision and detailed layer results:

const result = await sl.check("exec", { command: "git push --force" });

// The overall decision
console.log(result.decision); // "ALLOW" | "DENY" | "REQUIRE_APPROVAL"
console.log(result.reason);   // Human-readable explanation

// Which layer blocked it?
console.log(result.layers.capability); // { allowed: true }
console.log(result.layers.rules);     // { decision: "DENY", reason: "Force push" }
console.log(result.layers.llm);       // { decision: "NORMAL", confidence: 0.9 }

// Performance
console.log(result.timing.total);     // 12 (ms)
console.log(result.degraded);         // false (all layers executed)

Tracking taint

When your agent reads external content, update the taint tracker:

// After reading a web page
const webContent = await fetch("https://example.com").then(r => r.text());
sl.ingestContent(webContent, {
  source: "web",
  url: "https://example.com",
});

// After reading an untrusted file
const fileContent = await readFile("/tmp/downloaded-project/config.js", "utf-8");
sl.ingestContent(fileContent, {
  source: "file",
  path: "/tmp/downloaded-project/config.js",
});

// After receiving skill output
sl.ingestContent(skillOutput, { source: "skill", path: "summarize" });

// After loading from memory
sl.ingestContent(memoryData, { source: "memory" });

// Check the current taint level
const taint = sl.getSessionTaint(); // "web" (elevated from "owner")

Taint only escalates — once a session sees web content, it stays at web taint or higher for the rest of the session.

Scanning outbound content

Before your agent sends data externally, scan for leaked secrets:

const message = agent.generateResponse();

const scan = sl.scanEgress(message);
if (!scan.clean) {
  console.error("Secrets detected:", scan.findings.map(f => f.type));
  // Don't send the message — it contains sensitive data
}

Listening to events

Subscribe to security events for logging, monitoring, or custom logic:

// Listen for security decisions
const unsub = sl.on("action.evaluated", (event) => {
  console.log(`${event.action}: ${event.decision}`);
});

// Later, unsubscribe
unsub();

Cleanup

Always call destroy() when you're done to release resources:

sl.destroy();

This resolves any pending approval requests and clears event handlers.

Error handling

The SDK throws typed errors you can catch:

import {
  createSecurityLayer,
  ConfigError,
  InitializationError,
} from "@securitylayerai/sdk";

try {
  const sl = await createSecurityLayer({ configDir: "/bad/path" });
} catch (err) {
  if (err instanceof ConfigError) {
    console.error("Config problem:", err.message, err.configPath);
  } else if (err instanceof InitializationError) {
    console.error("Pipeline init failed:", err.message, err.cause);
  }
}

Next steps

On this page