Skip to main content

TypeScript SDK

The TypeScript SDK communicates with membraned over gRPC and mirrors the public protobuf service:

  • captureMemory / capture_memory
  • retrieveGraph / retrieve_graph
  • retrieveById / retrieve_by_id
  • revision, reinforcement, and metrics methods

Installation

npm install @bennettschwartz/membrane

Quick Start

import {
MembraneClient,
Sensitivity,
SourceKind,
} from "@bennettschwartz/membrane";

const client = new MembraneClient("localhost:9090", {
apiKey: "your-api-key",
});

const capture = await client.captureMemory(
{
ref: "src/auth.ts",
text: "Refactored auth middleware and verified package tests",
file: "src/auth.ts",
},
{
sourceKind: SourceKind.EVENT,
reasonToRemember: "Keep the auth refactor available for future debugging",
summary: "Refactored auth middleware",
sensitivity: Sensitivity.LOW,
tags: ["auth", "typescript"],
}
);

const graph = await client.retrieveGraph("debug auth", {
trust: {
max_sensitivity: Sensitivity.MEDIUM,
authenticated: true,
actor_id: "agent-1",
scopes: [],
},
memoryTypes: ["entity", "semantic", "competence", "episodic"],
rootLimit: 10,
nodeLimit: 25,
edgeLimit: 100,
maxHops: 1,
});

console.log(capture.primary_record.id, graph.nodes.length);
client.close();

Client Options

new MembraneClient(addr?: string, options?: MembraneClientOptions)
addrstringdefault: localhost:9090

gRPC address of the Membrane daemon.

options.tlsboolean

Use TLS transport.

options.tlsCaCertPathstring

Optional CA certificate path for TLS verification.

options.apiKeystring

Bearer token sent in gRPC metadata.

options.timeoutMsnumber

Per-call timeout in milliseconds.

options.transportRpcTransport

Custom transport used by tests or advanced integrations.

const client = new MembraneClient("membrane.example.com:443", {
tls: true,
tlsCaCertPath: "/path/to/ca.pem",
apiKey: process.env.MEMBRANE_API_KEY,
timeoutMs: 10_000,
});

Capture

async captureMemory(
content: unknown,
options?: CaptureMemoryOptions
): Promise<CaptureMemoryResult>

Captures a rich memory candidate. content is encoded as google.protobuf.Value; the response contains typed memory records and graph edges.

contentunknownrequired

JSON-compatible content to capture.

options.sourcestringdefault: typescript-client

Actor or system that produced the content.

options.sourceKindSourceKind | stringdefault: agent_turn

Capture shape: event, tool_output, observation, working_state, or agent_turn.

options.contextunknown

Optional JSON-compatible execution context.

options.reasonToRememberstring

Reason this content should be retained.

options.proposedTypeMemoryType | string

Optional requested memory type: episodic, working, semantic, competence, plan_graph, or entity.

options.summarystring

Short summary for the primary record.

options.tagsstring[]

Free-form labels.

options.scopestring

Visibility scope.

options.sensitivitySensitivity | stringdefault: low

Sensitivity classification.

options.timestampstring

RFC 3339 timestamp. Defaults to current UTC time.

const capture = await client.captureMemory(
{
tool_name: "go test",
args: { packages: ["./pkg/auth"] },
result: { exit_code: 0 },
},
{
sourceKind: SourceKind.TOOL_OUTPUT,
source: "auth-agent",
summary: "Auth package tests passed",
tags: ["auth", "tests"],
scope: "project-auth",
sensitivity: Sensitivity.LOW,
}
);

console.log(capture.primary_record.id);
console.log(capture.created_records.length);
console.log(capture.edges.length);

capture_memory is an alias for callers that prefer snake_case.


Retrieve Graph

async retrieveGraph(
taskDescriptor: string,
options?: RetrieveGraphOptions
): Promise<RetrieveGraphResult>

Retrieves ranked root memories and a bounded graph neighborhood around them.

taskDescriptorstringrequired

Natural-language task or query.

options.trustTrustContext

Trust context controlling sensitivity and scope visibility. Defaults to unauthenticated low-sensitivity access.

options.memoryTypesArray<MemoryType | string>

Optional filter: episodic, working, semantic, competence, plan_graph, entity.

options.minSaliencenumber

Minimum salience threshold.

options.rootLimitnumberdefault: 10

Maximum number of root records.

options.nodeLimitnumberdefault: 25

Maximum total graph nodes.

options.edgeLimitnumberdefault: 100

Maximum graph edges.

options.maxHopsnumberdefault: 1

Graph expansion depth from each root.

const graph = await client.retrieveGraph("debug auth retry failures", {
trust: {
max_sensitivity: Sensitivity.MEDIUM,
authenticated: true,
actor_id: "auth-agent",
scopes: ["project-auth"],
},
memoryTypes: ["entity", "semantic", "competence", "episodic"],
rootLimit: 8,
nodeLimit: 20,
maxHops: 1,
});

const roots = graph.nodes
.filter((node) => node.root)
.map((node) => node.record);

retrieve_graph is the snake_case alias.


Retrieve By ID

async retrieveById(
recordId: string,
options?: { trust?: TrustContext }
): Promise<MemoryRecord>
const record = await client.retrieveById(recordId, {
trust: {
max_sensitivity: Sensitivity.HIGH,
authenticated: true,
actor_id: "support-agent",
scopes: ["project-auth"],
},
});

retrieve_by_id is the snake_case alias.


Revision

await client.supersede(oldId, newRecord, "agent", "updated fact");
await client.fork(sourceId, forkedRecord, "agent", "different in staging");
await client.retract(recordId, "agent", "no longer accurate");
await client.merge([id1, id2], mergedRecord, "agent", "deduplicated");
await client.contest(recordId, conflictingRef, "agent", "conflicting evidence");

newRecord, forkedRecord, and mergedRecord may be plain JSON objects matching the MemoryRecord wire shape or MemoryRecord values.

Reinforcement

await client.reinforce(recordId, "agent", "used successfully");
await client.penalize(recordId, 0.2, "agent", "not useful for this task");

Metrics

const metrics = await client.getMetrics();
console.log(metrics.total_records);

get_metrics is the snake_case alias.


Types And Enums

The SDK exports constants and TypeScript types for the public schema:

import {
MemoryType,
Sensitivity,
SourceKind,
EntityType,
BuiltinEntityTypes,
GraphPredicate,
type CaptureMemoryResult,
type RetrieveGraphResult,
type MemoryRecord,
type EntityPayload,
} from "@bennettschwartz/membrane";

Memory types:

MemoryType.EPISODIC;
MemoryType.WORKING;
MemoryType.SEMANTIC;
MemoryType.COMPETENCE;
MemoryType.PLAN_GRAPH;
MemoryType.ENTITY;

Built-in entity ontology constants are open-ended. Use EntityType.OTHER or any project-specific string when none of the built-ins fit.


Error Handling

Failed RPCs reject with MembraneError.

import { MembraneError } from "@bennettschwartz/membrane";

try {
await client.retrieveById("missing");
} catch (err) {
if (err instanceof MembraneError) {
console.error(err.codeName, err.details);
}
}

MembraneError exposes:

FieldDescription
codeNumeric gRPC status code when available
codeNameSymbolic status such as UNAUTHENTICATED
detailsgRPC details string
metadataResponse metadata normalized to string arrays

Development

cd clients/typescript
npm install
npm run check:proto-sync
npm run typecheck
npm test
npm run build