--- title: "Quickstart" description: "Ingest a conversation and a document, then use document search, memory graph traversal, and profiles — and wire it into a chat harness." icon: "play" --- By the end of this page you will: 1. **Ingest a conversation** (how personal memory actually arrives) 2. **Ingest a document** (how knowledge for RAG arrives) 3. **Retrieve three ways** — document search (RAG), memory graph traversal, and user profile 4. **Drop it into a chat harness** that remembers across restarts Same `containerTag` for everything. One engine, three ways out. ## Get an API key Grab a key from the [developer console](https://console.supermemory.ai) — **API Keys → Create API Key**. **console.supermemory.ai** is where keys and usage live. **app.supermemory.ai** is the consumer product on the same engine — not where you mint API keys. ```bash TypeScript npm install supermemory export SUPERMEMORY_API_KEY="sm_..." ``` ```bash Python pip install supermemory export SUPERMEMORY_API_KEY="sm_..." ``` ```bash curl export SUPERMEMORY_API_KEY="sm_..." ``` ## 1. Ingest a conversation Real apps do not push four isolated one-liners as separate “memories.” They send **conversation turns** — often the full session — under a stable `customId` so the pipeline can extract facts and link entities. We’ll use one user (`user_4f8a`) and one chat session. The turns never say “Sarah *is* my VP of Product” — that connection is what the graph should resolve later. ```typescript TypeScript import Supermemory from "supermemory"; const client = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY }); const user = "user_4f8a"; const conversation = ` user: Just got back from Tokyo — the team offsite went great. assistant: Glad it went well! Anything stand out? user: Sarah presented the Q3 roadmap at the offsite. assistant: Sounds like a big moment for her. user: She's being promoted to VP of Product. assistant: Congrats to Sarah — that's huge. user: I need a gift idea for my VP of Product. assistant: Happy to help brainstorm something personal. `.trim(); const conv = await client.add({ content: conversation, containerTag: user, customId: "chat_offsite_2026", // one session → one document metadata: { type: "conversation" }, dreaming: "instant", // process this document now — see note below }); console.log(conv.id, conv.status); // e.g. "queued" ``` ```python Python from supermemory import Supermemory client = Supermemory() user = "user_4f8a" conversation = """ user: Just got back from Tokyo — the team offsite went great. assistant: Glad it went well! Anything stand out? user: Sarah presented the Q3 roadmap at the offsite. assistant: Sounds like a big moment for her. user: She's being promoted to VP of Product. assistant: Congrats to Sarah — that's huge. user: I need a gift idea for my VP of Product. assistant: Happy to help brainstorm something personal. """.strip() conv = client.add( content=conversation, container_tag=user, custom_id="chat_offsite_2026", metadata={"type": "conversation"}, dreaming="instant", # process this document now — see note below ) print(conv.id, conv.status) ``` ```bash curl curl -X POST "https://api.supermemory.ai/v3/documents" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "content": "user: Just got back from Tokyo — the team offsite went great.\nassistant: Glad it went well! Anything stand out?\nuser: Sarah presented the Q3 roadmap at the offsite.\nassistant: Sounds like a big moment for her.\nuser: She is being promoted to VP of Product.\nassistant: Congrats to Sarah — that is huge.\nuser: I need a gift idea for my VP of Product.\nassistant: Happy to help brainstorm something personal.", "containerTag": "user_4f8a", "customId": "chat_offsite_2026", "metadata": { "type": "conversation" }, "dreaming": "instant" }' ``` `add` returns immediately with `status: "queued"`. Processing is still **async** — wait until `done` before searching. **`dreaming: "instant"`** — By default, dreaming is `"dynamic"`: Supermemory may batch related documents so memories form from coherent units, which can lag after `status: "done"`. For this quickstart (and any path where you need memories/profiles right away), pass **`dreaming: "instant"`** so the document is processed on its own as soon as it finishes indexing. That bills one extra operation per document. See [Processing Modes](/ingestion/add-memories#processing-modes). ## 2. Ingest a document Now add **knowledge** the agent should ground on — a short internal note the conversation never fully spelled out. This is the SuperRAG / document path. ```typescript TypeScript const handbook = ` # Team notes — gifts & recognition When someone is promoted to VP or above, the company recommends a thoughtful gift in the $75–$150 range. Experiences tied to recent team milestones land better than generic swag. For product leadership, books on platform strategy or a dinner near the last offsite city are common picks. Tokyo offsites often inspire travel-themed gifts. `.trim(); const doc = await client.add({ content: handbook, containerTag: user, customId: "doc_gift_policy", metadata: { type: "document", source: "handbook" }, taskType: "superrag" }); console.log(doc.id, doc.status); ``` ```python Python handbook = """ # Team notes — gifts & recognition When someone is promoted to VP or above, the company recommends a thoughtful gift in the $75–$150 range. Experiences tied to recent team milestones land better than generic swag. For product leadership, books on platform strategy or a dinner near the last offsite city are common picks. Tokyo offsites often inspire travel-themed gifts. """.strip() doc = client.add( content=handbook, container_tag=user, custom_id="doc_gift_policy", metadata={"type": "document", "source": "handbook"}, task_type="superrag" ) print(doc.id, doc.status) ``` ```bash curl curl -X POST "https://api.supermemory.ai/v3/documents" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "content": "# Team notes — gifts & recognition\n\nWhen someone is promoted to VP or above, the company recommends a thoughtful gift in the $75–$150 range. Experiences tied to recent team milestones land better than generic swag.\n\nFor product leadership, books on platform strategy or a dinner near the last offsite city are common picks. Tokyo offsites often inspire travel-themed gifts.", "containerTag": "user_4f8a", "customId": "doc_gift_policy", "metadata": { "type": "document", "source": "handbook" }, "taskType": "superrag" }' ``` ## 3. Wait until both are `done` Poll document status. With **`dreaming: "instant"`**, once status is `done` the document is indexed **and** memories for that document should be available for search and profiles (`queued → extracting → … → done`). > Note that the preferred way is to have `dreaming: dynamic`. supermemory charges one extra operation for instant dreaming. Instant is good for one off tests, setup, debugging and benchmarking. ```typescript TypeScript async function waitUntilDone(id: string) { for (;;) { const d = await client.documents.get(id); if (d.status === "done" || d.status === "failed") return d; await new Promise((r) => setTimeout(r, 1500)); } } await waitUntilDone(conv.id); await waitUntilDone(doc.id); console.log("ready to search"); ``` ```python Python import time def wait_until_done(doc_id: str): while True: d = client.documents.get(doc_id) if d.status in ("done", "failed"): return d time.sleep(1.5) wait_until_done(conv.id) wait_until_done(doc.id) print("ready to search") ``` ```bash curl # replace DOC_ID with each document id from the add responses curl "https://api.supermemory.ai/v3/documents/DOC_ID" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" # repeat until "status": "done" ``` Short text with instant dreaming usually finishes in a few seconds. Larger PDFs take longer. If you omit `dreaming` (default `"dynamic"`), document RAG can work after `done` while memory extraction may still be batching — use `"instant"` when the next step is memory search or profiles. ## 4. Three ways to get context back ### A. Document search (RAG) Chunk-level retrieval over raw knowledge — use when you need **what the docs say**. ```typescript TypeScript const rag = await client.search({ q: "gift ideas for a VP promotion after a Tokyo offsite", containerTag: user, searchMode: "documents", limit: 3, }); for (const hit of rag.results) { console.log(hit.title ?? hit.id); for (const chunk of hit.chunks ?? []) { console.log(" ", chunk.content?.slice(0, 160)); } } ``` ```python Python rag = client.search.memories( q="gift ideas for a VP promotion after a Tokyo offsite", container_tag=user, search_mode="documents", limit=3, ) for hit in rag.results: print(getattr(hit, "title", None) or hit.id) for chunk in hit.chunks or []: print(" ", (chunk.content or "")[:160]) ``` ```bash curl curl -X POST "https://api.supermemory.ai/v3/search" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "q": "gift ideas for a VP promotion after a Tokyo offsite", "containerTag": "user_4f8a", "searchMode": "documents", "limit": 3 }' ``` You should see chunks from the handbook (budget range, Tokyo offsite angle) — **document grounding**, not personal facts. Switch `searchMode` to `"hybrid"` to get extracted memories and document chunks together: ```typescript await client.search({ q: "gift ideas for a VP promotion after a Tokyo offsite", containerTag: user, searchMode: "hybrid", limit: 5, }); ``` ### B. Memory graph traversal Search **extracted memories** with related edges. This is the entity-chain moment: gift → VP of Product → Sarah → Tokyo offsite. ```typescript TypeScript const memories = await client.search({ q: "What gift should I get, and why?", containerTag: user, searchMode: "memories", include: { relatedMemories: true }, limit: 5, }); console.log(JSON.stringify(memories, null, 2)); ``` ```python Python memories = client.search.memories( q="What gift should I get, and why?", container_tag=user, search_mode="memories", include={"relatedMemories": True}, limit=5, ) print(memories) ``` ```bash curl curl -X POST "https://api.supermemory.ai/v4/search" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "q": "What gift should I get, and why?", "containerTag": "user_4f8a", "searchMode": "memories", "include": { "relatedMemories": true }, "limit": 5 }' ``` Abbreviated shape: ```json { "results": [ { "memory": "Sarah is being promoted to VP of Product", "similarity": 0.81, "context": { "parents": [ { "memory": "Sarah presented the Q3 roadmap at the Tokyo offsite", "relation": "extends" } ], "children": [ { "memory": "User needs a gift idea for their VP of Product, Sarah", "relation": "derives" } ] } } ], "timing": 287 } ``` You never wrote “Sarah is my VP of Product” as one sentence. The graph connected sessions of speech. Deep dive: [graph memory](/concepts/graph-memory). ### C. User profile Profiles are the **always-on** summary (static + recent dynamic) of an entity (or a `containerTag`) - what you inject every turn without re-searching the world. ```typescript TypeScript const { profile, searchResults } = await client.profile({ containerTag: user, q: "gift for the person being promoted", // optional: also run search }); console.log("static:", profile.static); console.log("dynamic:", profile.dynamic); console.log("search hits:", searchResults?.results?.length ?? 0); ``` ```python Python result = client.profile( container_tag=user, q="gift for the person being promoted", ) print("static:", result.profile.static) print("dynamic:", result.profile.dynamic) print("search hits:", len(result.search_results.results) if result.search_results else 0) ``` ```bash curl curl -X POST "https://api.supermemory.ai/v4/profile" \ -H "Authorization: Bearer $SUPERMEMORY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "containerTag": "user_4f8a", "q": "gift for the person being promoted" }' ``` > There is a lot more to profiles - with [Buckets](/user-profiles/buckets), for example, you can make supermemory learn and categorize incoming information for learning specific things. | Path | Use when | |---|---| | **Document search** | Ground in policies, docs, handbooks | | **Memory + related** | Personal facts, entity links, “what’s true about this user” | | **Profile** | Cheap always-on context every LLM turn | Same `containerTag` → same context pool. See [Memory vs RAG](/concepts/memory-vs-rag). ## 5. Put it in a harness There is no single required harness. The pattern is the same wherever you run the model: **read** context (profile / search / docs), generate, **write** the turn back under a stable `customId` so the session stays one document. Here are two example shapes — pick whatever matches your stack. ### Example: explicit profile + search + add ```typescript TypeScript // npm install supermemory openai import Supermemory from "supermemory"; import OpenAI from "openai"; import * as readline from "node:readline/promises"; const memory = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY }); const llm = new OpenAI(); const user = "user_4f8a"; const sessionId = "chat_live_session"; const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); while (true) { const question = await rl.question("you: "); const { profile, searchResults } = await memory.profile({ containerTag: user, q: question, }); // optional: also pull document chunks for grounding const rag = await memory.search({ q: question, containerTag: user, searchMode: "documents", limit: 3, }); const docBits = rag.results .flatMap((r) => r.chunks ?? []) .map((c) => c.content) .filter(Boolean) .slice(0, 3); const context = [ "## Profile (static)", ...profile.static, "## Profile (dynamic)", ...profile.dynamic, "## Related memories", ...(searchResults?.results?.map((m) => m.memory).filter(Boolean) ?? []), "## Docs", ...docBits, ].join("\n"); const res = await llm.chat.completions.create({ model: "gpt-4o", messages: [ { role: "system", content: `You help this user. Context:\n${context}` }, { role: "user", content: question }, ], }); const answer = res.choices[0].message.content ?? ""; console.log(`assistant: ${answer}`); // append this turn into the same conversation document await memory.add({ content: `user: ${question}\nassistant: ${answer}`, containerTag: user, customId: sessionId, }); } ``` ```python Python # pip install supermemory openai from supermemory import Supermemory from openai import OpenAI memory = Supermemory() llm = OpenAI() user = "user_4f8a" session_id = "chat_live_session" while True: question = input("you: ") result = memory.profile(container_tag=user, q=question) rag = memory.search.memories( q=question, container_tag=user, search_mode="documents", limit=3 ) doc_bits = [] for hit in rag.results: for chunk in hit.chunks or []: if chunk.content: doc_bits.append(chunk.content[:300]) if len(doc_bits) >= 3: break memories = result.search_results.results if result.search_results else [] context = "\n".join( [ "## Profile (static)", *result.profile.static, "## Profile (dynamic)", *result.profile.dynamic, "## Related memories", *[m.memory for m in memories if m.memory], "## Docs", *doc_bits, ] ) res = llm.chat.completions.create( model="gpt-4o", messages=[ {"role": "system", "content": f"You help this user. Context:\n{context}"}, {"role": "user", "content": question}, ], ) answer = res.choices[0].message.content or "" print(f"assistant: {answer}") memory.add( content=f"user: {question}\nassistant: {answer}", container_tag=user, custom_id=session_id, ) ``` ### Example: Vercel AI SDK Same pattern, wrapped: `withSupermemory` injects context and can save the conversation for you. Details: [AI SDK integration](/integrations/ai-sdk). ```typescript // npm install ai @ai-sdk/openai @supermemory/tools import { generateText } from "ai"; import { openai } from "@ai-sdk/openai"; import { withSupermemory } from "@supermemory/tools/ai-sdk"; import * as readline from "node:readline/promises"; const model = withSupermemory(openai("gpt-4o"), { containerTag: "user_4f8a", customId: "chat_live_session", // keep stable for the whole session mode: "full", // profile + query search }); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); while (true) { const prompt = await rl.question("you: "); const { text } = await generateText({ model, prompt }); console.log(`assistant: ${text}`); } ``` Try: ``` you: What gift should I get for the person being promoted? assistant: You're looking for something for Sarah — she's being promoted to VP of Product after presenting the Q3 roadmap in Tokyo. Your handbook suggests $75–$150 and something tied to the offsite; a Tokyo-inspired experience or platform-strategy book would fit… ``` ### Kill it, restart it Ctrl+C the process, start again with the **same** `containerTag` (and optional same `customId` for the live session). Ask: ``` you: who's getting promoted? assistant: Sarah — she's being promoted to VP of Product. ``` Nothing was reloaded from your process. Memory and docs live in supermemory. ## Mental model ``` INGEST WAIT RETRIEVE ────── ──── ──────── Conversation (customId) → status === done → Memory graph (+ related) Document (customId) → status === done → Document search (RAG) → Profile (static + dynamic) │ ▼ Chat harness ``` ## Where next Conversations, files, URLs, customId updates, and status. Hybrid vs memories, filters, thresholds, rerank. How relations and entity chains are produced. Static vs dynamic, and when to inject a profile every turn. withSupermemory modes, customId, addMemory. Isolation for multi-tenant products.