Skip to main content
Forking is how you start from a shape that already exists instead of from a blank draft. shape_workbench_open with mode: "fork" creates a separate derived shape, with the source’s types, properties, and relationships copied in as a starting point. You edit the copy; the original is untouched. This is the right move when a system shape is close to what you want but not exact, the memory and research shapes being the common ones. You inherit a working model, then cull, add, and rename until it fits your domain.

Fork mode vs. edit mode

shape_workbench_open has four modes. Two of them look similar but do opposite things:
ModeWhat it does
editOpens an existing shape and changes it in place. Same shape, new version.
forkCopies a shape into a new, separate shape. Source unchanged.
newStarts a blank draft.
inspectReads a shape without opening an editable session.
Use fork, not edit, when you want to keep the original intact. Editing a system shape like memory in place changes it for everything that relies on it. Forking gives you a private variant and leaves the system shape as-is.

Worked example: a domain-specific memory shape

The default memory shape ships with one type, memory, whose kind field takes preference, decision, fact, lesson, observation, or signal, plus content, domain, scope, date_observed, source_context, and expiry. It also wires ABOUT and SUPERSEDED_BY edges. That is a lot of working structure to inherit rather than rebuild. Say you run sales and want memory tuned to deals: fewer generic kinds, a couple of fields the default does not have.
1

Fork the memory shape

Open the system memory shape in fork mode against your project. You get a new draft that already contains the memory type, its fields, and its edges.
shape_workbench_open
  mode: "fork"
  source: the system "memory" shape
  project: your project
2

Retune the types

Cull the kinds you do not use, add the ones you do, and add fields. Each is a single tool call against the forked draft.
  • shape_workbench_edit_type to narrow the kind enum (drop signal, add objection and commitment).
  • shape_workbench_edit_property to add a deal_stage field.
  • shape_workbench_add_type if your domain needs a second entity type.
  • shape_workbench_rename_property if an inherited name does not fit.
3

Compile and check the surface

Compile the draft, then preview what the runtime will see.
  • shape_workbench_compile returns the structure, denotative, and operative views plus version hashes. A clean compile means the model is coherent.
  • shape_workbench_preview_operating_surface shows exactly the tools and fields runtime agents and generated tools will get from this shape. Check it before materializing.
4

Materialize it to the project

shape_workbench_materialize commits the compiled shape to its project. It is now a live shape the runtime can read and write against, separate from the system memory shape it was forked from.
5

Point pb.memory at it

Pass your forked shape’s id as shapeId. pb.memory.remember now stages entities that conform to your shape instead of the default.
import { createPenumbra } from "@penumbra-systems/platform";

const pb = createPenumbra({ apiKey: process.env.PENUMBRA_API_KEY });

await pb.memory.remember({
  type: "memory",
  shapeId: "shp_sales_memory", // your forked shape
  kind: "objection",
  content: "Procurement, not price, is where enterprise deals stall.",
  apply: false, // stage while testing; drop to commit
});
Recall reads the memory plane as usual; the entities it returns now carry your shape’s fields.
const memory = await pb.memory.recall({
  query: "what blocks enterprise deals?",
  limit: 5,
});
console.log(memory.toMarkdown());
shapeId is what selects your variant. Without it, pb.memory uses the default memory shape; with it, writes and reads conform to the shape you forked and materialized.

What you inherit, what you change

A fork copies the source as it stands at fork time. After that, the two shapes are independent: changes to your variant do not propagate back, and later changes to the system shape do not flow into your fork. You own the copy. The Workbench tools work on the forked draft the same way they work on any other draft, so the authoring flow applies in full: model, diff, version, plan migrations.
ToolUse on a fork
shape_workbench_diffCompare your draft against its committed state.
shape_workbench_version_graphSee the variant’s version history.
shape_workbench_plan_migrationPlan a migration when you change a live variant.
shape_workbench_inspectRead the variant’s current state.
Fork when the default is 80% right. You spend your effort deleting the kinds you do not need and adding the two fields you do, instead of rebuilding a memory model from nothing.

Next

Authoring

The full Workbench tool surface for modeling, compiling, and versioning.

Materialize

Commit a compiled shape to a project so the SDK can use it.