Skip to content
Back to skills

312 Multi User 2dd88364

ASecurity

Building applications where multiple users interact with Letta agents.

  • 9 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 31, 2026
ai-agentstypescriptpythonapidatabase

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned May 31, 2026

npx -y skills add tools-only/X-Skills --skill 312-multi-user_2dd88364 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 312 Multi User 2dd88364?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 312 Multi User 2dd88364
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-312-multi-user-2dd88364/badge)](https://www.skillsdirectory.com/skills/tools-only-312-multi-user-2dd88364)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# Multi-User Patterns

Building applications where multiple users interact with Letta agents.

## Architecture Decision

| Pattern | Personalization | Isolation | Cost | Use Case |
|---------|----------------|-----------|------|----------|
| 1 Agent per User | High | Full | Higher | Personal assistants, companions |
| Shared Agent + Conversations | Low | Partial | Lower | Support bots, FAQ agents |
| Shared Agent + Identities | Medium | Partial | Lower | Multi-tenant with context |

## Pattern 1: One Agent Per User

Each user gets their own agent with personalized memory.

### When to Use
- Personal assistants that learn user preferences
- Companion apps with relationship building
- Applications requiring full conversation isolation

### Implementation

```python
from letta_client import Letta

client = Letta(api_key="...")

def create_agent_for_user(user_id: str, user_name: str):
    """Create a dedicated agent for a new user."""
    agent = client.agents.create(
        model="anthropic/claude-sonnet-4-5-20250929",
        embedding="openai/text-embedding-3-small",
        memory_blocks=[
            {
                "label": "persona",
                "value": "I am a personal assistant."
            },
            {
                "label": "human",
                "value": f"User ID: {user_id}\nName: {user_name}\nPreferences: (to be learned)"
            }
        ],
        tags=[f"user:{user_id}"]  # Tag for easy lookup
    )
    
    # Store agent_id in your database
    save_user_agent_mapping(user_id, agent.id)
    return agent

def get_user_agent(user_id: str):
    """Retrieve existing agent for a user."""
    agent_id = get_agent_id_from_database(user_id)
    if agent_id:
        return client.agents.retrieve(agent_id)
    return None

def chat_with_user_agent(user_id: str, message: str):
    """Send message to user's agent."""
    agent_id = get_agent_id_from_database(user_id)
    
    response = client.agents.messages.create(
        agent_id=agent_id,
        messages=[{"role": "user", "content": message}]
    )
    
    return extract_assistant_message(response)
```

```typescript
// TypeScript
import { Letta } from "@letta-ai/letta-client";

const client = new Letta({ apiKey: process.env.LETTA_API_KEY });

async function createAgentForUser(userId: string, userName: string) {
  const agent = await client.agents.create({
    model: "anthropic/claude-sonnet-4-5-20250929",
    embedding: "openai/text-embedding-3-small",
    memory_blocks: [
      { label: "persona", value: "I am a personal assistant." },
      { label: "human", value: `User: ${userName}` }
    ],
    tags: [`user:${userId}`]
  });
  
  await saveUserAgentMapping(userId, agent.id);
  return agent;
}

async function chatWithUserAgent(userId: string, message: string) {
  const agentId = await getAgentIdFromDatabase(userId);
  
  const response = await client.agents.messages.create(agentId, {
    messages: [{ role: "user", content: message }]
  });
  
  return extractAssistantMessage(response);
}
```

## Pattern 2: Shared Agent with Conversations API

Single agent handles multiple users through separate conversation threads.

### When to Use
- Stateless support bots
- FAQ or knowledge base agents
- Cost-sensitive applications

### Implementation

```python
from letta_client import Letta

client = Letta(api_key="...")

# Create a single shared agent
support_agent = client.agents.create(
    model="anthropic/claude-sonnet-4-5-20250929",
    embedding="openai/text-embedding-3-small",
    memory_blocks=[
        {
            "label": "persona", 
            "value": "I am a customer support agent for Acme Corp."
        },
        {
            "label": "knowledge",
            "value": "Product info, policies, etc."
        }
    ]
)

def start_user_conversation(user_id: str):
    """Start a new conversation for a user."""
    conversation = client.conversations.create(
        agent_id=support_agent.id,
        name=f"Support chat for {user_id}"
    )
    
    save_user_conversation_mapping(user_id, conversation.id)
    return conversation

def chat_in_conversation(user_id: str, message: str):
    """Send message in user's conversation."""
    conversation_id = get_conversation_id_for_user(user_id)
    
    response = client.agents.messages.create(
        agent_id=support_agent.id,
        messages=[{"role": "user", "content": message}],
        conversation_id=conversation_id
    )
    
    return extract_assistant_message(response)
```

### Conversation Concurrency

Different conversations run in parallel:

```python
import asyncio
from letta_client import AsyncLetta

async_client = AsyncLetta(api_key="...")

async def handle_concurrent_users():
    # These run fully parallel - no blocking
    responses = await asyncio.gather(
        async_client.agents.messages.create(
            agent_id=agent_id,
            messages=[{"role": "user", "content": "User 1 message"}],
            conversation_id="conv-user-1"
        ),
        async_client.agents.messages.create(
            agent_id=agent_id,
            messages=[{"role": "user", "content": "User 2 message"}],
            conversation_id="conv-user-2"
        ),
        async_client.agents.messages.create(
            agent_id=agent_id,
            messages=[{"role": "user", "content": "User 3 message"}],
            conversation_id="conv-user-3"
        )
    )
    return responses
```

## Pattern 3: Identities

Inject user context into a shared agent without separate agents.

### When to Use
- Multi-tenant SaaS with user-specific context
- Applications needing user identification without full personalization

### Implementation

```python
from letta_client import Letta

client = Letta(api_key="...")

# Create identities for users
def create_user_identity(user_id: str, user_data: dict):
    identity = client.identities.create(
        identifier_key=user_id,
        name=user_data["name"],
        properties={
            "email": user_data["email"],
            "plan": user_data["subscription_plan"],
            "company": user_data["company"]
        }
    )
    return identity

# Attach identity to agent
def setup_agent_with_identity(agent_id: str, identity_id: str):
    client.agents.identities.attach(
        agent_id=agent_id,
        identity_id=identity_id
    )

# Agent can now access user context via agent_state.identities
```

## Multi-User Best Practices

### 1. Agent Lookup Optimization

```python
# Use tags for efficient user->agent lookup
def find_user_agent(user_id: str):
    agents = client.agents.list(tags=[f"user:{user_id}"], limit=1)
    return next(iter(agents), None)
```

### 2. Cleanup Inactive Agents

```python
from datetime import datetime, timedelta

def cleanup_inactive_agents(days_inactive: int = 90):
    cutoff = datetime.now() - timedelta(days=days_inactive)
    
    agents = client.agents.list(limit=1000)
    for agent in agents:
        if agent.last_message_at < cutoff:
            # Archive or delete
            client.agents.delete(agent.id)
```

### 3. Rate Limiting Per User

```python
from collections import defaultdict
from time import time

class RateLimiter:
    def __init__(self, max_requests: int = 10, window_seconds: int = 60):
        self.max_requests = max_requests
        self.window = window_seconds
        self.requests = defaultdict(list)
    
    def is_allowed(self, user_id: str) -> bool:
        now = time()
        # Clean old requests
        self.requests[user_id] = [
            t for t in self.requests[user_id] 
            if now - t < self.window
        ]
        
        if len(self.requests[user_id]) >= self.max_requests:
            return False
        
        self.requests[user_id].append(now)
        return True

rate_limiter = RateLimiter()

def chat(user_id: str, message: str):
    if not rate_limiter.is_allowed(user_id):
        raise Exception("Rate limit exceeded")
    
    # Proceed with agent call
    ...
```

### 4. User Context Isolation

```python
def get_response_for_user(user_id: str, message: str):
    """Ensure responses only contain user's data."""
    agent_id = get_agent_id_for_user(user_id)
    
    # Verify agent belongs to user
    agent = client.agents.retrieve(agent_id)
    if f"user:{user_id}" not in agent.tags:
        raise PermissionError("Agent does not belong to user")
    
    return client.agents.messages.create(
        agent_id=agent_id,
        messages=[{"role": "user", "content": message}]
    )
```

## Scaling Considerations

| Users | Recommended Pattern | Notes |
|-------|---------------------|-------|
| < 100 | 1 Agent per User | Simple, full personalization |
| 100-10K | Mixed | Personal agents for active users, shared for occasional |
| > 10K | Shared + Conversations | Cost-effective, use identities for context |

For high-scale deployments, consider:
- Agent pooling for shared patterns
- Background cleanup of inactive agents
- Caching of frequently-accessed agent metadata

Files in this skill

  • README.md805 B
  • skill.md8.8 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.