Skip to main content
@penumbra-systems/platform gives you typed access to a live knowledge graph. You operate against an ontology that already exists; the SDK reads and writes graph state, it does not author the schema.
Design time vs. run time. You author your shapes (types, properties, relationships) in the Shapes Workbench, an MCP server you connect to your AI client. This SDK is the run-time surface: it operates a graph governed by those shapes. Deciding what your knowledge looks like is the Workbench; putting knowledge in and getting it back out is the SDK.

Create a client

import { createPenumbra } from "@penumbra-systems/platform";

const pb = createPenumbra({ apiKey: process.env.PENUMBRA_API_KEY! });
OptionTypeDefaultDescription
apiKeystringrequiredYour pnbr- key.
baseUrlstringhttps://pnbr.io/v1Override for staging or self-hosted.

The surface

pb is organized into the verbs you run against a governed graph.
CallWhat it doesReference
pb.ontology(...)Read the active ontology.Ontology and shapes
pb.search(...)Hybrid, semantic, or lexical retrieval.Search
pb.capture(...)Stage a structured entity into the graph.Capture and extract
pb.extract(...)Run text through a shape to extract entities.Capture and extract
pb.memory.*Domain-typed memory: remember, observe, recall, synthesize, archive.Memory
pb.dq.*Decision quality: is this fit to act on?Decision quality
pb.types.*Read and manage entity types.Ontology and shapes
pb.shapes.*Read shapes, schemas, bindings, projections.Ontology and shapes
pb.deltas.*The staged-write primitive under capture and extract.Capture and extract
pb.context.*Discover, preview, and compile scoped context.Context and slices
pb.slices.*Named, reusable context views.Context and slices

Governed writes

Writes do not hit the graph directly. They stage through a delta, which you can inspect before it commits. Pass apply: false to capture or extract to stage without committing.
const receipt = await pb.capture({
  type: "Insight",
  properties: { content: "Enterprise buyers stall on procurement, not price." },
  apply: false,
});

console.log(receipt.status, receipt.deltaId); // "staged", "..."

Errors

Failed requests throw PenumbraPlatformError with status, code, and the raw response data.
import { PenumbraPlatformError } from "@penumbra-systems/platform";

try {
  await pb.search("...");
} catch (err) {
  if (err instanceof PenumbraPlatformError) {
    console.error(err.status, err.code, err.message);
  }
}