What you will be able to do
- Create a memory store, save an entry and recall it with the AgentKit SDK or the REST API
- Wire memory into an agent as tools while keeping actor_id under application control
- Choose an actor_id strategy and know that the store, not the actor, is the security boundary
- Recognize the legacy Unity Catalog memory API and diagnose common Lakebase memory failures
1.Create a store, save a memory, recall it
Setting up managed agent memory takes three operations: create a store, save an entry once the agent learns something durable, and search for it in a later conversation. You can use either of two clients. The AgentKit SDK is the Databricks Python client for agent APIs. It needs Python 3.10 or above, ships in the databricks-agentbricks package, and authenticates through the Databricks SDK's WorkspaceClient. The REST API lives under /api/2.0/agents/memory-stores and works from any language, authenticated with an OAuth token from the Databricks CLI.
pip install databricks-agentbricksNote the two names. The package you install is databricks-agentbricks, but the Python module you import from is databricks_agentkit. The client setup uses two imports: from databricks.sdk import WorkspaceClient and from databricks_agentkit import AgentKitClient. Then client = AgentKitClient(WorkspaceClient()) builds the client.
With the SDK, client.memory_stores.create("support-agent-memory") creates the store, and Databricks provisions its Lakebase storage. memory_store.add(...) saves an entry with an actor_id (whose memory it is), a path (where it sits under that actor), content, and a description that improves retrieval. A later conversation recalls the entry with a natural-language search scoped to the same actor. Over REST, the same steps are a POST to /memory-stores, a POST to /memory-stores/{name}/entries, and a POST to /entries:search.
Checkpoint 1 of 8· Put it in order
Put the steps for giving a support agent persistent memory with the AgentKit SDK in order
- 1.Install the databricks-agentbricks package
- 2.Save the user's preference with memory_store.add
- 3.Create a memory store with client.memory_stores.create
- 4.Recall it in a later conversation with memory_store.search
The SDK has to be installed before the client exists, and a store has to exist before entries can be added. Searching only makes sense once something has been saved.
“they create a memory store, save a user's preference, and recall it in a later conversation.”Source: docs.databricks.com
Checkpoint 2 of 8· Fill the gap
Which method recalls the user's memories with a natural-language query in a later conversation?
results = memory_store. ? (actor_id="user-123", query="communication preferences", limit=10)search ranks an actor's entries against a natural-language query. list only browses entries, optionally filtered by session_id or path prefix.
Source: docs.databricks.comSources1
2.Let the agent decide when to remember
For the agent itself to decide when to save and when to recall, wrap the store's operations as tools and use the system prompt to tell the agent when to call them. The documentation's example does this for the OpenAI Agents SDK. The same pattern works with the Claude Agent SDK and other frameworks: you wrap search and add as whatever tool type the framework uses.
What to save is the hand-off between session and memory. As a session accumulates, the agent (or your application) distills the durable facts out of it and writes them to memory. Memory is for facts that should still matter in a future, unrelated conversation, such as a user's stable preferences, a past decision, or an ongoing project. The session is later cleared or ages out, while the memory persists.
def make_memory_tools(memory_store, actor_id: str):
@function_tool
def search_memory(query: str) -> str:
"""Search long-term memory for relevant facts about the user."""
results = memory_store.search(actor_id=actor_id, query=query, limit=10)
return "\n\n".join(f"{r.memory.path}: {r.memory.content}" for r in results) or "No memory found."
@function_tool
def save_memory(path: str, content: str, description: str = "") -> str:
"""Save a durable, long-term memory about the user."""
memory_store.add(actor_id=actor_id, path=path, content=content, description=description)
return f"Saved memory at {path}"
return [search_memory, save_memory]The model supplies query, path, content and description. actor_id is captured when make_memory_tools is called and never appears in a tool signature. Your application code sets it from the verified end-user identity, so the model cannot decide whose memory it reads or writes.
Checkpoint 3 of 8· Check yourself
You want the agent to decide for itself when to save and recall memory. What does the documentation say to do?
The agent gets the store's search and add operations as tools, and the system prompt tells it when to call them. actor_id stays in application code.
“wrap the client operations as tools and instruct the agent on when to use them in its system prompt.”Source: docs.databricks.com
3.Partitioning with actor_id, isolating with stores
Inside a store, actor_id separates one subject's memories from another's. Every list and search is scoped to a single actor_id, so the value you choose decides what the agent remembers and who shares it:
- Private per-user memory: set actor_id to the verified end-user identity, for example a support agent that remembers one user's past tickets.
- Shared group memory: set it to a fixed team, project or organization key, for example a team agent's glossary of company terms.
- Custom split: build it from your own values, such as {tenant}:{user}, so each customer's users stay isolated from one another.
Always set actor_id in application code from trusted caller context. If your strategy depends on an end-user identity and a request arrives without one, reject the request. Do not fall back to a shared actor_id.
Managed memory stores are workspace-scoped. Any principal that can reach a store can read and write every entry in it, for every actor. The security boundary is the store, not the actor. For strict isolation between tenants or users, create a separate memory store for each boundary. To let another principal use a store, such as your agent's service principal, grant it access with memory_store.grant_permission(principal_id). The grant is made on a particular store, so with one store per boundary you grant each principal access only to the store it should use.
Checkpoint 4 of 8· Check yourself
A multi-tenant SaaS needs a guarantee that no tenant's agent memory can ever be read under another tenant's credentials. Which configuration meets that requirement?
A composite actor_id keeps recall separate but grants no access control. Strict isolation needs separate stores, because the store is the security boundary.
“For strict isolation between tenants or users, create a separate memory store per boundary.”Source: docs.databricks.com
Checkpoint 5 of 8· Exam question
An agent stores each user's long-term memory in a shared Lakebase table, and the team must ensure that one user's application connection can never read or modify another user's memory rows through the Data API. Which Lakebase feature should be configured to enforce this?
Correct answer: A — Row-level security policies that restrict which rows each Postgres role can access
Sources1
4.Recognizing the legacy memory store
Older material describes a different store, managed agent memory (legacy), which was governed by Unity Catalog. Its stores are Unity Catalog securables with three-level names (catalog.schema.memory_store_name), served from /api/2.1/unity-catalog/memory-stores. They are controlled by privileges such as CREATE MEMORY STORE, READ MEMORY STORE and WRITE MEMORY STORE. Entries are partitioned by a scope parameter instead of actor_id, and each entry's path must start with /memories/. Databricks says this API will be turned down soon and should not be used for new agents. Build new long-term memory on the current managed agent memory, served from /api/2.0/agents/memory-stores.
Checkpoint 6 of 8· Check yourself
A team is starting a new agent and finds a tutorial that creates a memory store with catalog_name and schema_name and passes ?scope=user-123. What should they do?
catalog_name/schema_name and scope belong to the legacy Unity Catalog memory API, which is being turned down. New agents should use the current managed agent memory.
“the legacy managed agent memory, which will be turned down soon. Don't build new agents on it.”Source: docs.databricks.com
Sources3
5.When Lakebase-backed memory doesn't persist
Some agents connect to a Lakebase instance directly instead of using the managed store. A LangGraph agent on Databricks Apps using AsyncDatabricksStore is one example. These agents have to set up their own wiring, and the failures that show up come from three places: tables that were never created, resource configuration, and how user identity is passed in.
| Symptom | Cause | Fix |
|---|---|---|
| relation 'store' does not exist | Memory tables not initialized | Run await store.setup() locally before deploying |
| Unable to resolve … instance (the Lakebase instance) | Wrong instance name or configuration | LAKEBASE_INSTANCE_NAME must use value (not valueFrom) in app.yaml and match instance_name in databricks.yml |
| permission denied for table store | Missing Lakebase permissions | Add a database resource in databricks.yml with permission CAN_CONNECT_AND_CREATE |
| Memory not persisting across conversations | Different user_id per request | Pass a consistent user_id in custom_inputs for each user |
import asyncio
from databricks_langchain import AsyncDatabricksStore
async def setup_memory():
async with AsyncDatabricksStore(
instance_name='your-lakebase-instance',
embedding_endpoint='databricks-gte-large-en',
embedding_dims=1024,
) as store:
await store.setup()
asyncio.run(setup_memory())Checkpoint 7 of 8· Fill the gap
Which permission lets the app connect to the Lakebase database and create the memory tables it needs?
resources:
apps:
my_agent:
resources:
- name: 'memory_database'
database:
instance_name: '<lakebase-instance-name>'
database_name: 'postgres'
permission: ' ? 'The fix for 'permission denied for table store' is a database resource in databricks.yml with CAN_CONNECT_AND_CREATE.
Source: docs.databricks.comThe last row in the table is the easiest to misread. If memory saves without errors but is never there in the next conversation, storage is usually fine. The likely problem is that each request carries a different user_id, so every conversation reads and writes a different partition. A related symptom is an agent that replies "Memory not available". That points to a request with no custom_inputs.user_id at all. This is the same rule as with managed stores: the identity that keys memory must be stable and must come from the application.
Checkpoint 8 of 8· Exam question
A team wants agent memory writes to be governed under the same permissions and audit model already used for the rest of their Databricks data estate, without standing up a separate access-control system just for the memory store. Which Lakebase characteristic supports this goal?
Correct answer: A — Native Unity Catalog integration, which brings Lakebase under the same governance layer as other Databricks assets
Sources4
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.Since the agent decides when to save and recall, it can also pass in the actor_id to read or write.Why is that wrong?
actor_id must come from trusted application code, built from the verified end-user identity. The model must never choose it.
Covered in Let the agent decide when to remember
2.Giving each tenant its own actor_id in a shared memory store keeps tenants securely isolated.Why is that wrong?
actor_id only partitions recall. Any principal that can reach the store can read every actor's entries, so strict isolation requires a separate store per boundary.
Covered in Partitioning with actor_id, isolating with stores
3.If memory doesn't carry across conversations, the Lakebase store must be losing writes.Why is that wrong?
The documented cause is a different user_id on each request. Pass a consistent user_id in custom_inputs for each user.
Covered in When Lakebase-backed memory doesn't persist
Practise it for real
Give a support agent cross-session memory using a managed memory store and the AgentKit SDK
1.Run pip install databricks-agentbricks in a Python 3.10+ environment that has Databricks credentials configured
Why: The AgentKit SDK is the Python client for the memory-store API and authenticates through WorkspaceClient. The package name is databricks-agentbricks, but the module you import is databricks_agentkit
You should see: from databricks_agentkit import AgentKitClient runs without errors
2.Run from databricks.sdk import WorkspaceClient and from databricks_agentkit import AgentKitClient, then create client = AgentKitClient(WorkspaceClient()) and call memory_store = client.memory_stores.create("support-agent-memory")
Why: Creating the store provisions its Lakebase storage automatically, so you don't run a database yourself
You should see: A memory store object you can call add and search on
3.Call memory_store.add(actor_id="user-123", path="/preferences/communication.md", content="Prefers email over phone. Timezone: PST. Enterprise subscription.", description="User 123 communication preferences")
Why: actor_id says whose memory this is, path organizes it under that actor, and description improves retrieval
You should see: The entry is stored under actor user-123
4.In a new Python session, call memory_store.search(actor_id="user-123", query="communication preferences", limit=10)
Why: A separate session simulates a later, unrelated conversation recalling durable memory
You should see: The communication-preferences entry comes back among the results
5.Repeat the search with actor_id="user-456"
Why: Every list and search is scoped to a single actor_id
You should see: The user-123 entry does not appear
Stuck? Get a nudge
If the search for user-456 returns nothing, partitioning is working. Remember that this is not access control: anyone with access to the store can still read every actor's entries.
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.
“The clients call the REST API under /api/2.0/agents/memory-stores.”
↩︎ Create a store, save a memory, recall it“distributed in the databricks-agentbricks package”
↩︎ Create a store, save a memory, recall it“wrap the client operations as tools and instruct the agent on when to use them in its system prompt.”
↩︎ Let the agent decide when to remember“Every list and search is scoped to a single actor_id”
↩︎ Partitioning with actor_id, isolating with stores“reject requests that don't carry one rather than falling back to a shared actor_id.”
↩︎ Partitioning with actor_id, isolating with stores“grant it access with the store's grant-permission operation”
↩︎ Partitioning with actor_id, isolating with stores“Never let the model choose whose memory to read or write.”
↩︎ Exam trap 1“The store, not the actor, is the security boundary.”
↩︎ Exam trap 2“they create a memory store, save a user's preference, and recall it in a later conversation.”
↩︎ Checkpoint“actor_id separates memories, but it is not an access control.”
↩︎ Prediction“For strict isolation between tenants or users, create a separate memory store per boundary.”
↩︎ Checkpoint - 2.
“an agent (or your application) distills the durable facts out of it and writes them to memory.”
↩︎ Let the agent decide when to remember - 3.
“A memory store is a Unity Catalog securable that acts as a container for memory entries.”
↩︎ Recognizing the legacy memory store“path is a soft path within that scope that must start with /memories/”
↩︎ Recognizing the legacy memory store“the legacy managed agent memory, which will be turned down soon. Don't build new agents on it.”
↩︎ Checkpoint - 4.
“Run await store.setup() locally before deploying to create required tables”
↩︎ When Lakebase-backed memory doesn't persist“Pass custom_inputs.user_id in the request payload”
↩︎ When Lakebase-backed memory doesn't persist“Ensure you pass a consistent user_id in custom_inputs for each user”
↩︎ Exam trap 3