Quickstart — Node / TypeScript
When you’re already running a Node app and you don’t want another process,
embed Mnemosyne directly. @mnemosyne/core is the same engine the standalone
server uses — just imported as a library.
Install
pnpm add @mnemosyne/core @mnemosyne/client-tsPoint it at a Postgres
import { createMnemoClient, createDrizzleStorage } from "@mnemosyne/core";
const storage = createDrizzleStorage({
databaseUrl: process.env.DATABASE_URL!, // postgres://...
applyMigrations: true, // safe to call on boot
});
export const mnemo = createMnemoClient({ storage });The first call applies every migration to your Postgres if they aren’t already there. Subsequent boots are a no-op.
Remember + recall
await mnemo.remember({
workspaceId: "demo",
content: "Lucas prefers espresso to filter coffee",
tags: ["preferences", "coffee"],
});
const hits = await mnemo.recall({
workspaceId: "demo",
query: "coffee preferences",
topK: 3,
});
console.log(hits);Drop the API on a route (optional)
If you want other services to talk HTTP, mount @mnemosyne/server on the
same process:
import { Hono } from "hono";
import { mountMnemosyne } from "@mnemosyne/server";
const app = new Hono();
mountMnemosyne(app, { client: mnemo, basePath: "/v1" });
export default app;Now your existing app exposes /v1/facts, /v1/recall, etc., with the same
behaviour as the standalone server.
Embedded vs sidecar vs standalone
| Mode | When to pick it |
|---|---|
| Embedded | One Node app, one process, in-process function calls. Lowest latency. |
| Sidecar | Same VM, separate process, talks HTTP on localhost. Decoupled deploys. |
| Standalone | Multi-VM, multi-tenant, talks HTTP across the network. Shared instance. |
The data layer is identical. Switching modes is a config change.
Optional: enable embeddings
import { createOpenAIEmbedder } from "@mnemosyne/llm-providers";
export const mnemo = createMnemoClient({
storage,
// BYO key. Pass any provider with the right signature — OpenAI, Voyage,
// Cohere, a local Ollama, or your own function.
embedder: createOpenAIEmbedder({ apiKey: process.env.OPENAI_API_KEY! }),
});Mnemosyne never reads OPENAI_API_KEY on its own — you wire it in
explicitly. That keeps credentials owned by your app, not by Mnemosyne.
Don’t have an embeddings provider? Skip this step. Recall falls back to full-text search and stays useful. You can enable vectors later without data loss.