cd /news/ai-agents/user-scoped-memory-in-deep-agents-wh… Β· home β€Ί topics β€Ί ai-agents β€Ί article
[ARTICLE Β· art-101186] src=dev.to β†— pub= topic=ai-agents verified=true sentiment=Β· neutral

User-Scoped Memory in Deep Agents: What It Is and Why You Need It

Deep Agents introduced user-scoped memory to isolate long-term memory per user in shared AI agents, preventing preference leakage between users. The implementation uses a namespace based on the user ID, ensuring each user's memory files remain separate, as demonstrated with Alice and Bob receiving distinct responses.

read6 min views1 publishedAug 18, 2026

Imagine you build one AI agent and 1,000 people use it.

Alice tells the agent:

"I prefer Python examples and concise answers."

Later, Bob asks:

"How do I read a CSV file?"

Bob should not suddenly receive a short Python-focused answer just because Alice used the agent before.

This is exactly the problem user-scoped memory solves.

User-scoped memory means giving each user their own separate long-term memory.

The same agent can be shared by many users, but the memory belonging to one user is isolated from everyone else.

For example:

                    One AI Agent
                         |
          +--------------+--------------+
          |              |              |
       Alice            Bob          Charlie
          |              |              |
     Alice's memory  Bob's memory  Charlie's memory

Alice might have:

- Likes concise answers
- Prefers Python

Bob might have:

- Likes detailed explanations
- Prefers TypeScript

When Alice talks to the agent, the agent reads Alice's memory. When Bob talks to it, the agent reads Bob's memory.

Deep Agents implements this using a namespace. The namespace can be based on the user's ID, such as:

namespace=lambda current_runtime: (
    current_runtime.context.user_id,
)

This makes the user's ID the boundary between their memories. LangChain's documentation describes the same concept as user-scoped memory: each user gets an isolated copy of the memory files.

Without user-scoped memory, you can accidentally create shared memory.

Suppose your application has:

User A -> Agent -> preferences.md
User B -> Agent -> preferences.md

If both users access the same memory namespace, the agent could potentially read information written by the other user.

That can cause several problems.

Alice says:

"Always give me Python examples."

Bob could later receive Python examples even though he prefers TypeScript.

A memory file might contain information about a user's previous interactions, preferences, or other personal context.

If that memory is shared, one user's information could become available to another user.

Imagine 100 users are constantly teaching the same agent different preferences:

User A: Be concise.
User B: Give detailed explanations.
User C: Use Python.
User D: Use TypeScript.

If all of this goes into one shared memory, the agent has no reliable way to know whose preference it should follow.

There is an important distinction.

Short-term memory is generally associated with a conversation/thread. It helps the agent remember what is happening in the current conversation.

Long-term memory survives across conversations.

User-scoped long-term memory adds another layer:

Conversation 1 ─┐
Conversation 2 ─┼──> Alice's long-term memory
Conversation 3 β”€β”˜

So Alice can start a completely new conversation and the agent can still know her saved preferences.

Deep Agents uses memory files for long-term memory and a backend/store to control where those files are stored.

There are three important pieces in the example.

MEMORY_PATH = "/memories/preferences.md"

This tells the agent which memory file it should use.

Our application provides:

@dataclass(frozen=True)
class UserContext:
    user_id: str

For example:

user-alice
user-bob

The important part is:

namespace=lambda current_runtime: (
    current_runtime.context.user_id,
)

This means:

user-alice -> namespace ("user-alice",)
user-bob   -> namespace ("user-bob",)

The same /preferences.md

path can therefore exist independently for both users.

Conceptually:

Store
β”‚
β”œβ”€β”€ ("user-alice",)
β”‚   └── /preferences.md
β”‚
└── ("user-bob",)
    └── /preferences.md

The file has the same name, but it belongs to a different namespace.

LangChain recommends user scope when memory should belong to individual users, and specifically notes that user A's preferences should not leak into user B's conversations.

A good default is:

If memory does not need to be shared, make it user-scoped.

Shared memory should be used deliberately. LangChain's documentation also warns that allowing one user to write memory that another user can read can create security problems, including malicious instructions being inserted into shared state.

For shared organizational policies, read-only memory is often more appropriate.

The following example creates two users:

Both use the same agent, but their memories are isolated.

Install the required packages and set your NVIDIA_API_KEY

, then save the code as user_scoped_memory.py

and run:

uv run user_scoped_memory.py

The example uses NVIDIA's model through ChatNVIDIA

, while the memory isolation itself is handled by Deep Agents and InMemoryStore

.

"""Runnable user-scoped long-term memory example.

Run with ``uv run user_scoped_memory.py`` after setting `` NVIDIA_API_KEY`` in
the environment or in a ``.env`` file.

Each invocation supplies a user ID through the graph context. The backend uses
that ID as the store namespace, so users can share one agent without sharing
their preference files.
"""

import os
from dataclasses import dataclass

from dotenv import load_dotenv
from langchain_nvidia_ai_endpoints import ChatNVIDIA
from langgraph.store.memory import InMemoryStore
from requests.exceptions import Timeout

from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend
from deepagents.backends.utils import create_file_data

MEMORY_PATH = "/memories/preferences.md"
STORE_MEMORY_PATH = "/preferences.md"

@dataclass(frozen=True)
class UserContext:
    user_id: str

def build_model():
    """Create the chat model used by the demo."""
    if not os.getenv("NVIDIA_API_KEY"):
        raise RuntimeError(
            "Set NVIDIA_API_KEY in the environment or a .env file before "
            "running this example."
        )

    model_name = os.getenv(
        "NVIDIA_MODEL",
        "nvidia:nvidia/nemotron-3-ultra-550b-a55b",
    ).removeprefix("nvidia:")

    timeout_seconds = int(
        os.getenv("NVIDIA_TIMEOUT_SECONDS", "180")
    )

    max_completion_tokens = int(
        os.getenv("NVIDIA_MAX_COMPLETION_TOKENS", "1024")
    )

    return ChatNVIDIA(
        model=model_name,
        timeout=timeout_seconds,
        max_completion_tokens=max_completion_tokens,
        model_kwargs={"parallel_tool_calls": False},
    )

def seed_memory(store: InMemoryStore) -> None:
    """Create an isolated preference file for each demo user."""
    preferences = {
        "user-alice": """## Preferences
- Likes concise bullet points.
- Prefers Python examples.
""",
        "user-bob": """## Preferences
- Likes detailed explanations.
- Prefers TypeScript examples.
""",
    }

    for user_id, content in preferences.items():
        store.put(
            (user_id,),
            STORE_MEMORY_PATH,
            create_file_data(content),
        )

def build_backend(store: InMemoryStore) -> CompositeBackend:
    """Route memory to the namespace belonging to the current user."""
    return CompositeBackend(
        default=StateBackend(),
        routes={
            "/memories/": StoreBackend(
                store=store,
                namespace=lambda current_runtime: (
                    current_runtime.context.user_id,
                ),
            ),
        },
    )

def build_agent(store: InMemoryStore):
    return create_deep_agent(
        model=build_model(),
        memory=[MEMORY_PATH],
        backend=build_backend(store),
        context_schema=UserContext,
        store=store,
        name="user-scoped-memory-demo",
    )

def invoke_for_user(
    agent,
    user_id: str,
    thread_id: str,
    prompt: str,
) -> str:
    result = agent.invoke(
        {"messages": [{"role": "user", "content": prompt}]},
        config={"configurable": {"thread_id": thread_id}},
        context=UserContext(user_id=user_id),
    )

    return result["messages"][-1].content

def main() -> None:
    load_dotenv()

    store = InMemoryStore()
    seed_memory(store)
    agent = build_agent(store)

    prompt = (
        "How do I read a CSV file? Use only the preferences stored in "
        f"{MEMORY_PATH}. State which language and response style you used."
    )

    print("Alice's isolated memory")

    try:
        print(
            invoke_for_user(
                agent,
                user_id="user-alice",
                thread_id="alice-memory-thread",
                prompt=prompt,
            )
        )
    except Timeout:
        print(
            "The NVIDIA model timed out. The memory store is configured "
            "correctly; try NVIDIA_MODEL=meta/llama-3.2-3b-instruct or "
            "increase NVIDIA_TIMEOUT_SECONDS."
        )

    print("\nBob's isolated memory")

    try:
        print(
            invoke_for_user(
                agent,
                user_id="user-bob",
                thread_id="bob-memory-thread",
                prompt=prompt,
            )
        )
    except Timeout:
        print(
            "The NVIDIA model timed out. The memory store is configured "
            "correctly; try NVIDIA_MODEL=meta/llama-3.2-3b-instruct or "
            "increase NVIDIA_TIMEOUT_SECONDS."
        )

if __name__ == "__main__":
    main()

You do not need a separate agent for every user.

You can have:

One Agent
   |
   +-- User ID A -> Memory A
   |
   +-- User ID B -> Memory B
   |
   +-- User ID C -> Memory C

The user ID becomes the memory boundary.

That is the core idea behind user-scoped memory in Deep Agents.

For production applications, InMemoryStore

is only suitable for a simple demonstration. Deep Agents' documentation notes that a persistent/platform store should be used when deploying rather than relying on an in-memory store.

For the complete and current implementation details, see LangChain Deep Agents Memory documentation.

── more in #ai-agents 4 stories Β· sorted by recency
── more on @deep agents 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/user-scoped-memory-i…] indexed:0 read:6min 2026-08-18 Β· β€”