--- title: 'stackbone.memory' description: 'Surface defined; runtime pending. Long-term memory for an agent, backed by mem0.' position: 12 --- # `stackbone.memory` > **Status: planned.** This surface is already on the ambient > [`stackbone`](/docs/sdk/reference/overview) client, but every method returns > `not_implemented` for now. The shape on this page is the contract you > can type against today. The backend will be > [mem0](https://docs.mem0.ai/) (`MEM0_API_KEY`, optional `MEM0_BASE_URL`), > and every method goes live once that wiring lands: no code change on > your side. `stackbone.memory` is the long-term memory store for an agent. You reach it through the ambient `stackbone` client from any [deep-agent tool](/docs/sdk/agents/overview) or durable [workflow step](https://workflow-sdk.dev/docs): ```ts import { stackbone } from '@stackbone/sdk'; await stackbone.memory.add('Prefers dark mode and Spanish UI.', { userId: 'user_42' }); ``` The backend will be the external [mem0](https://docs.mem0.ai/) service, so the store stands apart from the agent's own Postgres ([`stackbone.database`](/docs/sdk/data/database)). It needs no platform capability. The wiring reads a `MEM0_API_KEY` from the environment, and nothing supplies one yet. ### Memory vs. a deep-agent session A deep agent already remembers a conversation across turns inside a single **session**, and every [agent session](/docs/sdk/agents/overview) carries that durable buffer without you asking for it. `stackbone.memory` holds the explicit facts you want to persist **across sessions and across users** ("this customer is on the Pro plan", "prefers Spanish"). Use the session for the live conversation; use `stackbone.memory` for what should outlive it. ## Scopes Every memory belongs to a scope: | Scope | Lifetime | Use it for | | ----------- | --------------------------------------- | -------------------------------------------------------- | | `'user'` | Long-term (default). | Facts about a specific end-user of the agent. | | `'session'` | Short-lived; collapsed by `endSession`. | Conversation buffer while a single chat is in flight. | | `'agent'` | Shared across every user of the agent. | Global facts the agent should know regardless of caller. | `scope: 'session'` requires a `sessionId`. The other scopes do not. ## API Every method returns the standard `Result` envelope (`{ data, error: null } | { data: null, error: SdkError }`). You call them from inside a deep-agent tool or a workflow step, where the ambient `stackbone` handle is in scope. ### `add(content, request)` Stores a new memory. `content` is either a string (ingested verbatim) or an OpenAI-shaped `ChatCompletionMessageParam[]`: mem0 summarises message arrays into one or more facts. ```ts import { tool } from '@langchain/core/tools'; import { stackbone, z } from '@stackbone/sdk'; const rememberFact = tool( async ({ userId, fact }: { userId: string; fact: string }) => { const { error } = await stackbone.memory.add(fact, { userId }); return error ? 'Could not remember that.' : 'Remembered.'; }, { name: 'remember_fact', description: 'Remember a fact about the current user.', schema: z.object({ userId: z.string(), fact: z.string() }), }, ); ``` A message array, scoped to a single session: ```ts await stackbone.memory.add( [ { role: 'user', content: 'I need to switch my plan to Pro' }, { role: 'assistant', content: 'Sure, I will upgrade your account now.' }, ], { userId: 'user_42', sessionId: 'sess_abc', scope: 'session' }, ); ``` ### `search(query, options?)` Semantic search across the configured scopes. Returns hits sorted by descending cosine similarity, capped at `limit` (default 10) and filtered by `threshold` if provided. ```ts const { data } = await stackbone.memory.search('What plan is the user on?', { userId: 'user_42', limit: 5, threshold: 0.7, }); for (const hit of data) { console.log(hit.score.toFixed(2), hit.content); } ``` `filters` AND-merge metadata predicates onto the semantic match. `includeScopes` restricts the search (omit to search every scope). ### `get(memoryId)` Returns a single memory by id. ### `list(request)` Paginated list of memories for a `userId`. ```ts const { data } = await stackbone.memory.list({ userId: 'user_42', limit: 50 }); ``` ### `update(memoryId, options)` Updates the content and/or metadata of a memory. mem0 shallow-merges the metadata. ```ts await stackbone.memory.update('mem_123', { content: 'Prefers light mode now.' }); ``` ### `delete(memoryId)` Deletes a single memory. Resolves to `{ id }`: the id of the deleted memory. ### `deleteAll(request)` Deletes every memory for a `userId`. Resolves to `{ deleted }`: the number of memories removed. ```ts await stackbone.memory.deleteAll({ userId: 'user_42' }); ``` ### `history(memoryId)` Returns the audit trail for a memory: every `created`, `updated`, `accessed` or `deleted` event, with `before` and `after` content snapshots where applicable. ```ts const { data } = await stackbone.memory.history('mem_123'); for (const entry of data) { console.log(entry.event, '@', entry.at, 'by', entry.actor); } ``` ### `endSession(sessionId, options?)` Closes a session. By default, `endSession` promotes session-scoped memories to long-term (`'user'`) storage before it drops the session. Pass `{ persist: false }` to drop them outright. ```ts const { data } = await stackbone.memory.endSession('sess_abc'); console.log(data.persisted, 'session facts promoted'); ``` ## Configuration Nothing reads these yet. They are the keys the surface resolves once the mem0 wiring ships, and the runtime supplies them then: you will not wire a client by hand. | Config key | Falls back to env | Required when… | | ------------- | ----------------- | ---------------------------------------------------------------------------------------- | | `mem0ApiKey` | `MEM0_API_KEY` | Any `stackbone.memory.*` call. | | `mem0BaseUrl` | `MEM0_BASE_URL` | Optional. Point at a self-hosted mem0 deployment. Defaults to the mem0 cloud when unset. | ## Errors | Code | Meaning | | ------------------- | --------------------------------------------------- | | `not_implemented` | Returned by every call until the mem0 wiring ships. | | `mem0_unconfigured` | `mem0ApiKey` / `MEM0_API_KEY` is missing. | | `memory_not_found` | The `memoryId` does not exist or has been deleted. | Today only `not_implemented` is reachable. The other two codes arrive with the mem0 wiring. ## Where to go next - **[`stackbone.ai`](/docs/sdk/platform/ai)**: the LLM client memories feed into via the conversation summarisation flow. - **[`requestApproval()`](/docs/sdk/workflows/overview)**: erasing a user's memory on request ("right to be forgotten") is a good fit for a workflow-level human approval gate rather than a fire-and-forget `deleteAll`. See **[`stackbone.approval`](/docs/sdk/humans/approval)** for the underlying surface. - **[`stackbone.database`](/docs/sdk/data/database)**: the Postgres the rest of the agent uses; mem0 lives outside it. - **[Concepts → Agents and sessions](/docs/sdk/agents/overview)**: how a deep agent's built-in session memory complements long-term memory.