Skip to main content
A team brain is a shared graph your whole team — and its agents — read and write. You research your domain into it as structured findings, and you give it memory so agents remember what they learn across sessions. This build wires both: ingest a domain through the Research shape, then add a memory layer with pb.memory. Everything here runs through the SDK. Install and create a client once.
npm install @penumbra-systems/platform
client.ts
import { createPenumbra } from "@penumbra-systems/platform";

const pb = createPenumbra({ apiKey: process.env.PENUMBRA_API_KEY });
The client talks to https://pnbr.io/v1. Set PENUMBRA_API_KEY in your environment before running any of the snippets below.

Part 1 — Research a domain into the graph

Every project ships with a preloaded system shape called Research. You do not design anything to start — your agent captures into it out of the box. It gives the team brain a consistent structure for everything it ingests.
TypeCaptures
inquiryA line of investigation.
sourceWhere evidence comes from.
evidenceA specific observation drawn from a source.
findingA conclusion supported by evidence.
open_questionA gap still to resolve.
research_noteFreeform context.

Stage research through a delta

Writes to the graph stage through a delta — a reviewable batch you build up, preview, then commit. Capture the entities your research produced, wire their relationships, preview the diff, and apply.
1

Open a delta and add findings

Create a delta, then add the research entities as typed Research entities.
research.ts
const delta = await pb.deltas.create({
  label: "Discovery research: litigation paralegals",
});

await pb.deltas.addEntities(delta.id, [
  {
    type: "inquiry",
    properties: { title: "How do expert paralegals organize discovery?" },
  },
  {
    type: "source",
    properties: { title: "Interview: senior litigation paralegal" },
  },
  {
    type: "evidence",
    properties: {
      content: "They tag every document by custodian before review.",
    },
  },
  {
    type: "finding",
    properties: {
      content: "Custodian-first tagging is the backbone of discovery prep.",
    },
  },
]);
2

Wire the relationships

Connect the entities so the finding traces back to its evidence and source.
research.ts
await pb.deltas.addRelationships(delta.id, [
  { from: "evidence-1", type: "DRAWN_FROM", to: "source-1" },
  { from: "finding-1", type: "SUPPORTED_BY", to: "evidence-1" },
]);
3

Preview before committing

plan() returns the diff the delta would produce. Use it to review before anything lands in the shared graph.
research.ts
const diff = await pb.deltas.plan(delta.id);
console.log(diff);
4

Apply

Commit the delta. The research is now structured graph data the whole team queries — not a document in a folder.
research.ts
await pb.deltas.apply(delta.id);
You can also let an agent do the legwork. Point it at a domain — “research how expert litigation paralegals organize discovery, and capture inquiries, sources, evidence, and findings into the Research shape” — and it stages the same delta through the Penumbra MCP.

Read it back

Once applied, the research is queryable. Search across the findings the team brain now holds.
research.ts
const findings = await pb.search("how paralegals organize discovery", {
  types: ["finding", "evidence"],
});
Capture and extraction stage into a delta. Pass apply: false when you want to stage without committing, plan() to preview the diff, and revert() to undo an applied delta. The delta is your review gate before anything joins the shared graph.

Part 2 — Give the brain memory

Research gives the team brain knowledge. pb.memory gives it memory — the things your agents learn and should carry forward across sessions. It stores and recalls with no setup.
memory.ts
await pb.memory.remember({
  type: "memory",
  kind: "decision",
  content: "We capture custodian metadata at intake, not during review.",
  scope: "commons",
});

const memory = await pb.memory.recall({
  query: "what should the team know before discovery prep?",
  limit: 5,
});
console.log(memory.toMarkdown());
The default memory shape captures:
FieldWhat it holds
contentThe memory in natural language (required).
kindpreference · decision · fact · lesson · observation · signal
domainThe area it applies to (“discovery prep”, “sales process”).
scopeagent · commons · project — who the memory is shared with.
date_observedWhen it was learned.
source_contextWhere it came from.
expiryOptional TTL, for memory that goes stale.
It also wires an ABOUT edge to the subject a memory concerns, and a SUPERSEDED_BY edge when a newer memory replaces an older one.
For a team brain, set scope: "commons" so the memory is shared across the team rather than scoped to a single agent.

Fork the memory shape for your domain

When the default does not fit, fork the memory shape and make it yours. It is a normal shape, so you get the full Workbench: cull the kinds you do not use, add the fields you do, rename what does not fit.
1

Fork the default memory shape

In the Workbench, fork the memory shape into a new draft. You inherit its fields and edges as a starting point rather than building memory from scratch.
2

Retune it

Cull the enum values you do not need, add domain-specific ones, or add fields (a client_id, a matter_number, whatever your domain remembers). Compile to check it.
3

Materialize it

Materialize your memory shape to the project so it is live.
4

Point pb.memory at it

Pass your shape’s id, and memory now conforms to your shape.
memory.ts
await pb.memory.remember({
  type: "memory",
  shapeId: "shp_your_memory_shape",
  kind: "lesson",
  content: "Enterprise matters stall in conflicts review, not on scope.",
  scope: "commons",
});

How the two halves compose

Research and memory live in the same graph but on different planes. Research findings land on the semantic plane — the default canonical graph the team queries. pb.memory writes and reads on the memory plane, and recall defaults there. The two reinforce each other: research teaches the brain a domain, and memory keeps what your agents learn while operating on it. Both halves are shape-governed. The Research shape and the memory shape are shapes like any other — you can inspect, fork, compile, and materialize them in the Workbench, which is how you bend the team brain to your domain.

Design shapes

Fork the Research and memory shapes into a domain model.

Connect an agent

Wire an agent so it researches and remembers into the team brain.