Skip to main content
@keyvaluesystems/agent-opfor-sdk is the programmatic surface — the same engine as the CLI, callable from your own code. Use it to embed red-teaming in custom tooling, gate CI on results, or build your own workflows. It’s TypeScript-first.

Install

npm install @keyvaluesystems/agent-opfor-sdk

Quickstart

Both a class-based and a functional API are available — they’re equivalent, so use whichever you prefer.
import { Opfor } from "@keyvaluesystems/agent-opfor-sdk";

const opfor = new Opfor({ apiKey: process.env.ANTHROPIC_API_KEY });

const results = await opfor.run({
  target: { url: "https://api.example.com/chat", apiKey: process.env.TARGET_API_KEY },
  suite: "owasp-llm-top10",
});

console.log(results.score, results.findings.length);

Run

Run a suite or a list of evaluators against a target.
const results = await opfor.run({
  target: { url: "https://api.example.com/chat", apiKey: process.env.TARGET_API_KEY, model: "gpt-4o" },
  suite: "owasp-llm-top10",
  strategy: { effort: "adaptive", turnMode: "multi", turns: 3 },
  attackerModel: "claude-sonnet-4",
  judgeModel: "claude-sonnet-4",
});
Run specific evaluators instead of a suite with evaluators: [...]:
await opfor.run({
  target: { url: "https://api.example.com/chat" },
  evaluators: ["jailbreaking", "prompt-injection", "system-prompt-leakage"],
});

Targets

target: {
  url: "https://api.example.com/chat",
  name: "My Chatbot",
  description: "Customer support chatbot with order-database access",
  apiKey: process.env.TARGET_API_KEY,
  model: "gpt-4o",
  headers: { "X-Custom-Header": "value" },
  requestFormat: "openai",     // "auto" | "openai" | "json"
  promptPath: "input.message", // for requestFormat: "json"
  responsePath: "output.text",
}

Strategy

Control how thorough the attack loop is.
strategy: {
  effort: "adaptive",   // "adaptive" (one sustained chat) | "comprehensive" (one attack per pattern)
  turnMode: "multi",    // "single" | "multi"
  turns: 3,             // max turns per attack when multi
}

Models

Set attacker and judge LLMs as a shorthand string or a full provider object. The judge defaults to the attacker if unset.
const opfor = new Opfor({ apiKey: process.env.ANTHROPIC_API_KEY });

await opfor.run({
  target: { url: "https://api.example.com/chat" },
  suite: "owasp-llm-top10",
  attackerModel: "claude-sonnet-4",
  judgeModel: { provider: "anthropic", model: "claude-opus-4", apiKey: process.env.ANTHROPIC_API_KEY },
});
Provider objects accept { provider, model, apiKey, baseUrl? }apiKey is the key value, not an env var name. See providers for the full provider list.

Autonomous mode

hunt() runs the autonomous campaign programmatically — adaptive multi-turn attacks driven by an AI agent, with progress streaming.
import { hunt } from "@keyvaluesystems/agent-opfor-sdk";

const results = await hunt({
  target: { url: "https://api.example.com/chat", apiKey: process.env.TARGET_API_KEY },
  objective: "Find jailbreaks, data leaks, and authorization flaws",
  limits: { budgetUsd: 5 },
  onProgress: (event) => {
    if (event.type === "finding") console.log(`Found: ${event.vulnClass} (${event.severity})`);
  },
});

console.log(results.outcome, results.findings.length, results.htmlReportPath);
interface HuntOptions {
  target: {
    url: string;
    name?: string;
    apiKey?: string;
    headers?: Record<string, string>;
    stateful?: boolean;
    sessionField?: string;
    promptPath?: string;
    responsePath?: string;
    model?: string;
  };
  objective: string;
  models?: { commander?: string; operator?: string; scout?: string; verifier?: string };
  limits?: {
    budgetUsd?: number;       // default 10
    maxOperators?: number;    // default 6
    maxTurns?: number;        // default 120
    maxThreadTurns?: number;  // default 25
    maxTotalThreads?: number; // default 40
    maxDepth?: number;        // default 3
    maxReconProbes?: number;  // default 8
  };
  verify?: boolean;
  sequential?: boolean;
  outputDir?: string;
  onProgress?: (event: HuntProgressEvent) => void;
}
onProgress events: line, recon_start, recon_done, thread_start, thread_turn, thread_done, finding, complete. HuntResults includes outcome, summary, recon, findings, recommendations, totalCostUsd, and report paths.

Telemetry

Enable trace-aware testing so the judge sees the target’s internal tool calls and retrievals.
await opfor.run({
  target: { url: "https://api.example.com/chat" },
  suite: "owasp-llm-top10",
  telemetry: {
    provider: "langfuse",
    langfuse: {
      publicKeyEnv: "LANGFUSE_PUBLIC_KEY",
      secretKeyEnv: "LANGFUSE_SECRET_KEY",
      baseUrl: "https://cloud.langfuse.com",
      traceSelection: { lookbackHours: 24, environment: "production" },
    },
    enrichJudgeFromTrace: true,
    propagation: { headers: { "X-Trace-Id": "{{traceId}}" }, traceIdStrategy: "per-attack" },
  },
});
For Netra, swap provider and use the netra block:
telemetry: {
  provider: "netra",
  netra: {
    baseUrl: "http://localhost:3000",
    apiKeyEnv: "NETRA_API_KEY",
    traceSelection: { lookbackHours: 24 },
  },
  enrichJudgeFromTrace: true,
  propagation: { traceIdBodyField: "trace_id", traceIdStrategy: "per-attack" },
}
See Trace-aware testing for the full config reference.

Results

interface RunResults {
  id: string;
  timestamp: string;
  targetName: string;
  targetKind: "agent" | "mcp";
  effort: "adaptive" | "comprehensive";
  attackerModel: string;
  judgeModel: string;
  score: number; // 0–100 safety score
  summary: {
    total: number;
    passed: number;
    failed: number;
    errors: number;
    safetyScore: number;
    attackSuccessRate: number;
  };
  findings: Finding[];
  evaluators: EvaluatorResult[];
}
A Finding carries severity, title, description, evidence?, and a standards map. Each EvaluatorResult holds per-evaluator pass/fail counts and an attacks array with full prompt/response transcripts and verdict.

Reports

const r = opfor.report(results);
await r.json("./report.json");
await r.html("./report.html");

// functional
import { report } from "@keyvaluesystems/agent-opfor-sdk";
await report(results).html("./report.html");

Gate CI on findings

import { run } from "@keyvaluesystems/agent-opfor-sdk";

const results = await run({
  target: { url: process.env.TARGET_URL!, apiKey: process.env.TARGET_API_KEY },
  suite: "owasp-llm-top10",
  apiKey: process.env.ANTHROPIC_API_KEY,
});

if (results.findings.length > 0) {
  for (const f of results.findings) console.error(`[${f.severity}] ${f.title}`);
  process.exit(1);
}
console.log(`Safety score: ${results.score}%`);

Exports

import {
  Opfor,          // class API
  run,            // run a suite / evaluators
  hunt,           // autonomous red-team
  report,         // generate reports from results
  listSuites,     // list available suites
  listEvaluators, // list available evaluators (optionally { kind: "mcp" })
} from "@keyvaluesystems/agent-opfor-sdk";
Types are exported too: RunOptions, RunResults, TargetConfig, McpTargetConfig, Finding, EvaluatorResult, AttackResult, TelemetryConfig, and the Hunt* variants.