TypeScript SDK
The TypeScript SDK communicates with membraned over gRPC and mirrors the public protobuf service:
captureMemory/capture_memoryretrieveGraph/retrieve_graphretrieveById/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:9090gRPC address of the Membrane daemon.
options.tlsbooleanUse TLS transport.
options.tlsCaCertPathstringOptional CA certificate path for TLS verification.
options.apiKeystringBearer token sent in gRPC metadata.
options.timeoutMsnumberPer-call timeout in milliseconds.
options.transportRpcTransportCustom 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.
contentunknownrequiredJSON-compatible content to capture.
options.sourcestringdefault: typescript-clientActor or system that produced the content.
options.sourceKindSourceKind | stringdefault: agent_turnCapture shape: event, tool_output, observation, working_state, or agent_turn.
options.contextunknownOptional JSON-compatible execution context.
options.reasonToRememberstringReason this content should be retained.
options.proposedTypeMemoryType | stringOptional requested memory type: episodic, working, semantic, competence, plan_graph, or entity.
options.summarystringShort summary for the primary record.
options.tagsstring[]Free-form labels.
options.scopestringVisibility scope.
options.sensitivitySensitivity | stringdefault: lowSensitivity classification.
options.timestampstringRFC 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.
taskDescriptorstringrequiredNatural-language task or query.
options.trustTrustContextTrust 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.minSaliencenumberMinimum salience threshold.
options.rootLimitnumberdefault: 10Maximum number of root records.
options.nodeLimitnumberdefault: 25Maximum total graph nodes.
options.edgeLimitnumberdefault: 100Maximum graph edges.
options.maxHopsnumberdefault: 1Graph 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:
| Field | Description |
|---|---|
code | Numeric gRPC status code when available |
codeName | Symbolic status such as UNAUTHENTICATED |
details | gRPC details string |
metadata | Response metadata normalized to string arrays |
Development
cd clients/typescript
npm install
npm run check:proto-sync
npm run typecheck
npm test
npm run build