agent-session-isolation
Skill0 starsChanged 6 months agoMITView on GitHub
Implements per-tenant and per-user session isolation for agent conversations using namespaced conversation IDs. Use when building multi-tenant applications where different users or tenants must have fully isolated conversation histories that cannot bleed into each other.
In this repository65 other files it gives its agents.
- AGENTS.mdAGENTS.md
- skills/building-agents/agents.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- llms-full.txtllms.txt
- llms.txtllms.txt
- adding-guardrailsSkill
- agent-health-timeoutSkill
- agent-permission-scopingSkill
- agent-step-loggingSkill
- agent-supervisor-routerSkill
- agent-telemetrySkill
- async-agent-backgroundSkill
- building-agentsSkill
- building-teamsSkill
- building-toolsSkill
- calendar-scheduling-toolSkill
- callback-tracing-handlerSkill
- chain-of-thought-promptingSkill
- chat-model-configurationSkill
- code-execution-sandboxSkill
- common-agent-patternsSkill
- context-window-managementSkill
- conversation-memorySkill
- conversation-state-dbSkill
- database-query-toolSkill
- document-loadersSkill
- document-rerankingSkill
- email-notification-toolSkill
- embedding-model-ingestionSkill
- fallback-model-chainSkill
- few-shot-injectionSkill
- filesystem-toolSkill
- human-in-the-loopSkill
- hybrid-searchSkill
- inspecting-streamsSkill
- integrating-with-laurenSkill
- json-schema-enforcementSkill
- llm-provider-connectionSkill
- llm-rate-limitingSkill
- long-term-vector-memorySkill
- managing-memorySkill
- migrating-to-lauren-aiSkill
- multi-agent-delegationSkill
- multi-tool-orchestrationSkill
- multi-turn-tool-stateSkill
- output-guardrailsSkill
- plan-and-execute-agentSkill
- prompt-injection-defenseSkill
- prompt-versioningSkill
- rag-pipelineSkill
- react-agent-loopSkill
- response-validation-retrySkill
- rest-api-toolSkill
- securing-agentsSkill
- semantic-cacheSkill
- streaming-response-handlerSkill
- structured-output-parsingSkill
- sub-agent-spawningSkill
- system-prompt-templatingSkill
- testing-agentsSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 72
When you only need user isolation (not tenant isolation), use the user ID directly as the conversation_id:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Use
codemap find "SymbolName"to locate any symbol before reading — it gives exact file + line range and is faster than grep across the whole repo.
Agent Session Isolation per User / Tenant
Overview
TenantIsolatedAgentRunner wraps AgentRunnerBase and prefixes every
conversation_id with "{tenant_id}:{user_id}". Each tenant gets its own
InMemoryConversationStore so histories cannot cross tenant boundaries.
Implementation
# isolation/tenant_runner.py
from __future__ import annotations
from lauren_ai import agent, ShortTermMemory
from lauren_ai._memory._stores import InMemoryConversationStore
class TenantIsolatedAgentRunner:
"""Wraps AgentRunner to namespace conversation IDs per tenant."""
def __init__(self, runner, agent_instance):
self._runner = runner
self._agent = agent_instance
self._stores: dict[str, InMemoryConversationStore] = {}
def _get_store(self, tenant_id: str) -> InMemoryConversationStore:
if tenant_id not in self._stores:
self._stores[tenant_id] = InMemoryConversationStore()
return self._stores[tenant_id]
async def run(self, tenant_id: str, user_id: str, prompt: str):
conversation_id = f"{tenant_id}:{user_id}"
store = self._get_store(tenant_id)
return await self._runner.run(
self._agent,
prompt,
conversation_id=conversation_id,
conversation_store=store,
)
def get_conversation_count(self, tenant_id: str) -> int:
store = self._stores.get(tenant_id)
if store is None:
return 0
return len(store)Why this is safe
conversation_id = f"{tenant_id}:{user_id}"ensures thatuser123intenant_aanduser123intenant_bhave different keys.- Each tenant has its own
InMemoryConversationStoredict — there is no shared mutable state. - Switching to a Redis-backed store in production only requires replacing
InMemoryConversationStorewith aRedisConversationStore.
Per-user isolation without multi-tenancy
When you only need user isolation (not tenant isolation), use the user ID
directly as the conversation_id:
response = await runner.run(
agent_instance,
prompt,
conversation_id=user_id,
conversation_store=shared_store,
)Each user's messages are stored under their own key in the same store.
Attaching to a Lauren controller
@controller("/chat")
class ChatController:
def __init__(self, runner: AgentRunner) -> None:
self._isolated = TenantIsolatedAgentRunner(runner, MyAgent())
@post("/message")
async def message(self, body: Json[ChatRequest], ctx: ExecutionContext) -> dict:
tenant_id = ctx.request.state.tenant_id
user_id = ctx.request.state.user_id
response = await self._isolated.run(tenant_id, user_id, body.text)
return {"reply": response.content}Reference files
| File | Contents |
src/lauren_ai/_memory/_stores.py | InMemoryConversationStore |
src/lauren_ai/_agents/_runner.py | run(conversation_id=, conversation_store=) |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

