Skip to main content
Install the TypeScript SDK:
npm install @memoryos/sdk

Clients

  • Tenant-scoped client: MemoryOS
  • Universal cross-agent client: UniversalMemoryOS
import { MemoryOS, UniversalMemoryOS } from "@memoryos/sdk";

const client = new MemoryOS(process.env.MEMORYOS_API_KEY!);
Use MemoryOS for normal workspace memory inside your tenant. Use UniversalMemoryOS only after a user has granted your global agent access through Memory Passport. There is no separate SDK for domain schemas. If your tenant enables EdTech or Support, add() and get() remain the main integration path. Optional domain helper methods expose structured profile data for dashboards.

How domain schemas work with the SDK

Domain schemas are configured on the tenant, not in SDK code. That means this code stays the same:
import { MemoryOS } from "@memoryos/sdk";

const client = new MemoryOS(process.env.MEMORYOS_API_KEY!);

await client.add(
  messages,
  "customer-123",
  "support-bot",
  { source: "chat" },
);

const result = await client.get(
  "How should the assistant answer?",
  "customer-123",
);
What changes is the tenant setting:
Tenant settingWhat add() doesWhat get() returns
General EngineGeneric memory extractionGeneric prompt-ready memory
EdTech SchemaGeneric memory + EdTech overlayGeneric memory + tutoring/student context
Customer Support SchemaGeneric memory + Support overlayGeneric memory + support/customer context
For Support, systemPromptAddition can include current issue, support history, resolution preference, sentiment risk, and safety rules. Your own tools still provide live truth such as order status, invoice status, refunds, or ticket updates. Use the same SDK methods for all three modes.

add()

const result = await client.add(
  [{ role: "user", content: "I prefer concise technical explanations." }],
  "customer-123",
  "support-bot",
  { source: "chat" },
);

Parameters

ParameterTypeRequiredNotes
messagesConversationMessage[]YesAt least one message
externalUserIdstringYesEnd-user identifier inside your tenant
agentIdstring | undefinedNoOptional agent identifier
metadataRecord<string, unknown> | undefinedNoOptional metadata

Return fields

FieldTypeMeaning
jobIdstring | nullExtraction job id when queued
statusstringCurrent add outcome
blockedReasonstring | nullReason when blocked
retryAfterSecondsnumber | nullRetry hint for L1 blocks
budgetRemainingPctnumber | nullRemaining tenant budget percentage
quotaMode"FULL" | "PASSTHROUGH" | "DEGRADED_RETRIEVE" | "BLOCKED"Quota mode from headers
processingEtaSecondsnumber | nullQueue ETA when delayed
processingStatus"normal" | "delayed"Background ingestion health
circuitStatus"HEALTHY" | "DEGRADED" | "CRITICAL"Platform dependency status

Status outcomes

status valueMeaningTypical action
queuedRequest accepted and job queuedTrack the job if needed
passthroughWrites are bypassed in the current quota modeContinue without persistence
L1Per-user rate limit exceededRetry after retryAfterSeconds
L2Low-quality input was blockedImprove message quality
L3Duplicate query was blockedAvoid near-identical writes
L4Budget governance blocked the requestUpgrade or wait for reset
blockedInternal gate fallbackRetry later

get()

const memories = await client.get(
  "How should I answer this user?",
  "customer-123",
  5,
  ["preference", "goal"],
);

Parameters

ParameterTypeRequiredNotes
querystringYesNatural-language retrieval query
externalUserIdstringYesEnd-user identifier inside your tenant
limitnumberNoDefault 10
categoriesMemoryCategory[] | undefinedNoOptional category filter
timeFilterDaysnumber | undefinedNoReturn only memories from the last N days
format"bullets" | "json" | "xml"NoFormat for systemPromptAddition
contextMaxTokensnumberNoPrompt context token budget, default 500

Return fields

FieldTypeMeaning
itemsMemoryItem[]Retrieved memories
cachedbooleanWhether the result came from the hot cache
systemPromptAdditionstringPrompt-ready context block
contextTokenCountnumberTokens used by systemPromptAddition
memoriesFromHotTiernumberNumber of returned memories served from hot tier
quotaMode"FULL" | "PASSTHROUGH" | "DEGRADED_RETRIEVE" | "BLOCKED"Quota mode
isPassthroughbooleanSkip memory context when true
isDegradedbooleanRetrieval is degraded when true
circuitStatus"HEALTHY" | "DEGRADED" | "CRITICAL"Platform dependency status

UniversalMemoryOS

import { UniversalMemoryOS } from "@memoryos/sdk";

const universal = new UniversalMemoryOS(
  process.env.MEMORYOS_AGENT_API_KEY!,
  userUuiToken,
);
The universal client is independent from MemoryOS. It uses agent credentials and a user UUI token:
  • Authorization: ApiKey agent_sk_...
  • X-MemoryOS-UUI: uui_...

UniversalMemoryOS.consentUrl()

const consentUrl = UniversalMemoryOS.consentUrl(
  "your_global_agent_id",
  null,
  userSessionId,
  ["preference", "goal"],
);
Redirect users to this URL when they click a control such as “Connect shared memory”. If you pass null for the callback, MemoryOS shows a hosted completion page after approval. The fourth argument preselects categories for this consent link. Users can still add or remove categories before approving. If you omit it, MemoryOS uses the global agent’s default categories. Pass a callback only if your app needs to update its own UI automatically:
const consentUrl = UniversalMemoryOS.consentUrl(
  "your_global_agent_id",
  "https://yourapp.com/integrations/memoryos/callback",
  secureRandomStateToken,
  ["preference", "fact"],
);

universal.add()

const result = await universal.add(
  [{ role: "user", content: "I prefer short technical answers." }],
  { source: "chat" },
);

universal.get()

const result = await universal.get("How should I personalize this answer?", 5);
Universal retrieve responses include the normal retrieve fields plus:
FieldTypeMeaning
categoriesAvailablestring[]Memory categories the user granted this agent
permissionStatusstring | nullPermission status, such as no_grant_for_user, when no active grant exists

Degradation handling pattern

const result = await client.get(
  "What should I remember about this user?",
  "customer-123",
);

const promptAddition = result.hasContext
  ? result.systemPromptAddition
  : "";

Domain profile helpers

For domain-aware tenants, normal get() already includes domain-aware context. Use profile helpers only when your product needs structured UI data. EdTech example:
const profile = await client.getEdTechProfile("student_123");

if (profile?.hasExamContext) {
  console.log(profile.examName, profile.examDate);
}

console.log(profile?.weakTopics.slice(0, 3));

delete()

const deleted = await client.delete(
  "1c5d5ab6-73c8-4b12-90e9-0f7f9db8db4f",
  "customer-123",
  false,
);

list()

const page = await client.list("customer-123", { limit: 50 });

for (const memory of page.items) {
  console.log(memory.content);
}
Returns:
  • items
  • nextCursor
  • limit
  • total

export()

const bundle = await client.export("customer-123");
Returns a MemoryExport object with:
  • user
  • memories
  • apiKeys
  • agents
export() currently maps to the user export endpoint, not a tenant-wide export endpoint.

getUsage() and deleteUser()

The current TypeScript SDK does not expose getUsage() or deleteUser(). Use the REST API directly for those operations:
  • tenant usage: GET /v1/tenant/usage
  • current user deletion: DELETE /v1/users/me
  • tenant proxy-user deletion: DELETE /v1/users/{external_user_id}
For the product flow and consent UX, see: