All stateful features (memory, checkpoints, plans, evicted files) write to ctx.deps.backend. If two users share the same backend instance, they share all state. This page explains how to isolate per-user state in web applications.
By default, create_deep_agent() is single-user:
from pydantic_deep import create_deep_agent, DeepAgentDeps
from pydantic_ai_backends import StateBackend
agent = create_deep_agent(include_memory=True)
# One backend = one shared state
deps = DeepAgentDeps(backend=StateBackend()) # (1)!- If two users share this
deps, they share the same memory, plans, and evicted files.
Features that write to the backend:
| Feature | Storage Path | Risk |
|---|---|---|
| Memory | /.deep/memory/{agent}/MEMORY.md |
Users see each other's memories |
| Plans | /plans/{slug}-{uuid}.md |
Low — UUIDs prevent collisions, but users see all plans |
| Eviction | /large_tool_results/{call_id} |
Low — unique IDs, but files accumulate |
| Context files | /DEEP.md, /AGENTS.md |
None — typically read-only, shared by design |
| Checkpoints | CheckpointStore (separate) |
Users see each other's checkpoints |
Simplest approach. Each user/session gets its own in-memory backend:
from pydantic_deep import create_deep_agent, DeepAgentDeps, InMemoryCheckpointStore
from pydantic_ai_backends import StateBackend
agent = create_deep_agent(include_memory=True, include_checkpoints=True)
async def handle_request(user_id: str, message: str):
# Each session gets isolated state
deps = DeepAgentDeps(
backend=StateBackend(),
checkpoint_store=InMemoryCheckpointStore(),
)
result = await agent.run(message, deps=deps)
return result.outputPros: Full isolation, no setup. Cons: State lost between sessions — memory, files, and checkpoints don't persist.
Each user gets a separate directory on the host filesystem:
from pydantic_deep import create_deep_agent, DeepAgentDeps, FileCheckpointStore
from pydantic_ai_backends import LocalBackend
agent = create_deep_agent(include_memory=True, include_checkpoints=True)
async def handle_request(user_id: str, message: str):
deps = DeepAgentDeps(
backend=LocalBackend(root_dir=f"/workspaces/{user_id}"),
checkpoint_store=FileCheckpointStore(f"/checkpoints/{user_id}"),
)
result = await agent.run(message, deps=deps)
return result.outputPros: Isolation + persistence. Memory survives across sessions. Cons: No process-level sandboxing — agents can't run untrusted code safely.
Full isolation with per-user Docker containers. Best for production:
from pydantic_deep import create_deep_agent, DeepAgentDeps, FileCheckpointStore
from pydantic_ai_backends import DockerSandbox, SessionManager
agent = create_deep_agent(include_memory=True, include_checkpoints=True)
session_manager = SessionManager(workspace_root="/workspaces")
async def handle_request(user_id: str, message: str):
sandbox = await session_manager.get_or_create(user_id)
deps = DeepAgentDeps(
backend=sandbox,
checkpoint_store=FileCheckpointStore(f"/checkpoints/{user_id}"),
)
result = await agent.run(message, deps=deps)
return result.outputPros: Full isolation, persistence, sandboxed code execution. Cons: Requires Docker. Higher resource usage per user.
from contextlib import asynccontextmanager
from fastapi import FastAPI, Depends
from pydantic_deep import create_deep_agent, DeepAgentDeps, InMemoryCheckpointStore
from pydantic_ai_backends import LocalBackend
agent = create_deep_agent(
include_memory=True,
include_checkpoints=True,
)
# Store per-user message histories in memory
user_histories: dict[str, list] = {}
def get_deps(user_id: str) -> DeepAgentDeps:
"""Create isolated deps for each user."""
return DeepAgentDeps(
backend=LocalBackend(root_dir=f"/workspaces/{user_id}"),
checkpoint_store=InMemoryCheckpointStore(),
)
app = FastAPI()
@app.post("/chat/{user_id}")
async def chat(user_id: str, message: str):
deps = get_deps(user_id)
history = user_histories.get(user_id, [])
result = await agent.run(message, deps=deps, message_history=history)
user_histories[user_id] = result.all_messages()
return {"response": result.output}When building a multi-user application:
- Create a separate
backendper user (or per session) - Create a separate
CheckpointStoreper user if using checkpoints - Store message histories per user (don't share
message_historyacross users) - Consider whether memory should persist across sessions (Pattern B/C) or be ephemeral (Pattern A)
- Use DockerSandbox if agents execute untrusted code
- Memory — Persistent agent memory
- Checkpointing — Conversation checkpointing
- Backends — Backend options