Skip to content
Sign up

Shared memory blocks guide

Guide to sharing memory blocks between multiple agents for collaborative workflows.

Shared memory blocks enable multiple agents to access and update the same memory, creating powerful multi-agent systems with seamless coordination.

Shared memory blocks allow you to attach the same memory block to multiple agents. When one agent updates the block, all other agents with access immediately see the changes. This enables:

  • Real-time coordination without explicit agent-to-agent messaging
  • Consistent information across teams and departments
  • Hierarchical access control based on roles and responsibilities
  • Privacy boundaries for sensitive information
  • Knowledge sharing across specialized agents

A memory block becomes “shared” when you attach it to multiple agents using the same block_id. All agents with access see the same content in real-time.

from letta_client import Letta
import os
client = Letta(api_key=os.getenv("LETTA_API_KEY"))
# Step 1: Create a memory block
shared_block = client.blocks.create(
label="team_knowledge",
description="Shared knowledge base for the team",
value="Team policies and procedures...",
limit=5000
)
# Step 2: Attach to multiple agents
agent1 = client.agents.create(
name="Agent_1",
block_ids=[shared_block.id], # Attach shared block
# ... other config
)
agent2 = client.agents.create(
name="Agent_2",
block_ids=[shared_block.id], # Same block ID = shared memory
# ... other config
)
# Now agent1 and agent2 share the same memory block!
TypeDescriptionUse Case
Read-OnlyAgents can read but not modifyCompany policies, reference data
Read/WriteAgents can read and updateTask queues, shared notes
PrivateSingle agent onlyPersonal work logs, private notes

Letta supports multiple access patterns for organizing shared memory:

  1. Hierarchical: Tier 1 < Tier 2 < Tier 3 (access increases up the hierarchy)
  2. Team-Based: All team members share the same blocks
  3. Overlapping: Each agent has a unique combination of blocks
  4. Organizational: Department → Cross-Department → Executive levels

Pattern 1: Hierarchical Access (Support Tiers)

Section titled “Pattern 1: Hierarchical Access (Support Tiers)”
Tier 1 Agents → company_policies [R]
Tier 2 Agents → company_policies [R], escalation_procedures [R]
Tier 3 Agents → company_policies [R], escalation_procedures [R], team_metrics [R/W]

Use Cases:

  • Customer support with tier levels
  • Knowledge bases with sensitivity levels
  • Organizations with clearance levels

Example: Read-Only Organizational Knowledge Tutorial

Pattern 2: Team Coordination (Shared Queues)

Section titled “Pattern 2: Team Coordination (Shared Queues)”
All Team Members → task_queue [R/W], completed_work [R/W]
Supervisor Only → team_metrics [R/W]
Each Worker → private_work_log [R/W]

Use Cases:

  • Task coordination across workers
  • Project management teams
  • Shared deliverables tracking

Example: Task Coordination Tutorial

Pattern 3: Specialized Agents (Overlapping Access)

Section titled “Pattern 3: Specialized Agents (Overlapping Access)”
Coordinator → ALL blocks (user_profile, preferences, interaction_history, calendar, financial)
Email Agent → user_profile, preferences, interaction_history, calendar
Research Agent → user_profile, preferences, interaction_history
Calendar Agent → user_profile, preferences, calendar
Finance Agent → user_profile, preferences, financial

Use Cases:

  • Personal AI assistant networks
  • Specialized service agents
  • Multi-domain customer support

Example: Multi-Agent User Assistant Tutorial

Pattern 4: Enterprise Hierarchy (Departments)

Section titled “Pattern 4: Enterprise Hierarchy (Departments)”
Company-Wide [R] → ALL agents (mission, policies)
Department Blocks [R/W] → Department members only
Cross-Dept Block [R/W] → All directors + CEO
Executive Dashboard [R/W] → CEO only

Use Cases:

  • Enterprise organizations
  • Multi-department companies
  • Regulated industries with compliance requirements

Example: Enterprise Multi-Team Tutorial

1. Use Read-Only Blocks for Critical Information

Section titled “1. Use Read-Only Blocks for Critical Information”

Protect policies, procedures, and reference data from accidental modification:

company_policies = client.blocks.create(
label="company_policies",
value="Our company policies...",
# Read-only ensures consistency
)

2. Implement the Principle of Least Privilege

Section titled “2. Implement the Principle of Least Privilege”

Only give agents access to blocks they need:

# ❌ Bad: Sales agent with access to HR data
sales_agent = client.agents.create(
block_ids=[sales_knowledge.id, hr_employee_data.id] # Too much access
)
# ✓ Good: Sales agent with only sales data
sales_agent = client.agents.create(
block_ids=[sales_knowledge.id] # Appropriate access
)

Make block purposes obvious:

# ✓ Good names
"company_policies" # Clear scope and content
"sales_team_knowledge" # Clear ownership
"cross_dept_projects" # Clear purpose
"ceo_executive_dashboard" # Clear access level
# ❌ Bad names
"data" # Too generic
"block1" # Not descriptive
"temp" # Purpose unclear

Balance between enough space and memory constraints:

# Reference data: smaller
company_policies = client.blocks.create(
limit=5000 # Policies don't change often
)
# Active coordination: larger
task_queue = client.blocks.create(
limit=10000 # Tasks accumulate over time
)
# Detailed logs: largest
interaction_history = client.blocks.create(
limit=12000 # Many interactions to track
)

5. Document Block Access in Agent Personas

Section titled “5. Document Block Access in Agent Personas”

Make agents aware of their access:

agent = client.agents.create(
memory_blocks=[{
"label": "persona",
"value": """I am a Sales Representative.
My access:
- company_policies (read-only): Company-wide policies
- sales_knowledge (read/write): Shared with sales team
- my_leads (private): My personal lead tracking
I do NOT have access to:
- engineering_specs (Engineering team only)
- hr_employee_data (HR team only)
"""
}]
)

Help with debugging and management:

block = client.blocks.create(
label="sales_knowledge",
description="Sales team knowledge base: pricing, playbooks, targets. Read/write access for Sales Director, Rep 1, Rep 2.",
# Good description includes: content, access, and purpose
)

Problem: Support agents at different levels need different information.

Solution: Hierarchical blocks with increasing access

support_tier1/ → Basic policies
support_tier2/ → Advanced troubleshooting + escalation procedures
support_tier3/ → Full system access + team metrics

Benefits:

  • Consistent policy information across all tiers
  • Sensitive escalation procedures protected
  • Supervisors track team performance privately

Problem: Multiple workers need to coordinate on tasks.

Solution: Shared task queue + completion log

task_queue (R/W) → All team members claim and update tasks
completed_work (R/W) → All team members share findings
team_metrics (R/W) → Supervisor only tracks performance

Benefits:

  • Real-time task claiming without conflicts
  • Knowledge sharing through completed work
  • Supervisor oversight without micromanagement

Problem: User needs specialized agents that understand full context.

Solution: Overlapping block access with privacy boundaries

Universal: user_profile, user_preferences → All agents
Coordination: interaction_history → Coordinator, Email, Research
Domain-specific: calendar_data → Calendar, Email agents only
Restricted: financial_data → Finance agent only

Benefits:

  • Seamless handoffs between specialists
  • Consistent user experience
  • Privacy protection for sensitive data

Problem: Large company with departments needs coordination.

Solution: Multi-tier hierarchy with isolation

Company-wide (R) → All employees see mission/policies
Department (R/W) → Each dept has private knowledge
Cross-dept (R/W) → Directors coordinate projects
Executive (R/W) → CEO tracks company metrics

Benefits:

  • Department autonomy and isolation
  • Async cross-department coordination
  • Executive oversight without bottlenecks
  • Compliance with data privacy regulations
block = client.blocks.create(
label="block_name", # Required: identifier
description="What this is", # Recommended: for management
value="Initial content", # Required: starting content
limit=5000 # Optional: character limit
)
agent = client.agents.create(
name="Agent_Name",
block_ids=[block1.id, block2.id], # Attach existing blocks
memory_blocks=[ # Create new private blocks
{"label": "persona", "value": "..."}
],
# ... other config
)
# Attach a block to an existing agent
client.agents.blocks.attach(
agent_id=agent.id,
block_id=block.id
)
# Detach a block from an agent
client.agents.blocks.detach(
agent_id=agent.id,
block_id=block.id
)

Find blocks across your project with optional filtering:

# List all blocks in project
all_blocks = client.blocks.list()
# Filter by label
team_blocks = client.blocks.list(label="team_knowledge")
# Search by label text
search_results = client.blocks.list(label_search="sales")

Get complete block information by ID:

{block.label}") print(f"Value: {block.value}") ``` ```typescript TypeScript
const block = await client.blocks.retrieve(block.id); console.log(`Block: $
{block.label}`); console.log(`Value: ${block.value}`); ```
</TabItem>
</Tabs>
### Modifying Blocks Directly
Update block content without going through an agent. Useful for external scripts syncing data to agents:
<Tabs>
<TabItem label="Python">
```python Python
# Update block content - completely replaces the value
client.blocks.update(
block.id,
value="Updated team knowledge: New procedures..."
)
# Update multiple properties
client.blocks.update(
block.id,
value="New content",
limit=8000,
description="Updated description"
)
# Make block read-only
client.blocks.update(block.id, read_only=True)

Remove blocks when no longer needed. This detaches the block from all agents:

python Python client.blocks.delete(block_id=block.id) typescript TypeScript await client.blocks.delete(block.id);

See all memory blocks attached to a specific agent:

# List all blocks for an agent
agent_blocks = client.agents.blocks.list(agent_id=agent.id)
# With pagination
agent_blocks = client.agents.blocks.list(
agent_id=agent.id,
limit=10,
order="asc"
)
for block in agent_blocks:
print(f"{block.label}: {block.value[:50]}...")

Get a specific block from an agent using its label instead of ID:

# Get agent's human block
human_block = client.agents.blocks.retrieve(
agent_id=agent.id,
block_label="human"
)
print(human_block.value)
# Get shared task queue from specific agent
task_queue = client.agents.blocks.retrieve(
agent_id=worker_agent.id,
block_label="task_queue"
)

Update a specific agent’s block without needing the block ID:

# Update agent's knowledge about the human
client.agents.blocks.update(
agent_id=agent.id,
block_label="human",
value="Updated user information: Alice, prefers email over chat"
)
# Update shared block via specific agent
client.agents.blocks.update(
agent_id=worker.id,
block_label="task_queue",
value="Updated task queue with new items..."
)

See which agents have a block attached:

# List all agents that use this block
agents_with_block = client.blocks.agents.list(block_id=block.id)
print(f"Used by {len(agents_with_block)} agents:")
for agent in agents_with_block:
print(f" - {agent.name}")
# With pagination
agents_page = client.blocks.agents.list(
block_id=block.id,
limit=10,
order="asc"
)

Agents update blocks using memory tools during conversations:

# Agent updates shared block content
client.agents.messages.create(
agent_id=agent.id,
messages=[{
"role": "user",
"content": "Update the task queue to mark task-001 as complete"
}]
)
# Agent uses core_memory_replace or core_memory_append tools
# Changes are immediately visible to all agents with access

Symptoms: Agent reads old content after another agent updated it.

Solutions:

  1. Verify both agents have the same block_id attached
  2. Check that updates are being committed (agent finished its turn)
  3. Ensure character limit hasn’t been exceeded (updates may fail silently)
# Debug: Check which agents share the block
block_info = client.blocks.retrieve(block_id=block.id)
print(f"Agents with access: {block_info.agent_ids}")

Symptoms: Updates not applying, content truncated.

Solutions:

  1. Increase block limit: client.blocks.update(block_id=block.id, limit=10000)
  2. Archive old content: Move completed items to a separate block
  3. Summarize content: Have an agent periodically summarize and condense
# Check current usage
block = client.blocks.retrieve(block_id=block.id)
print(f"Characters: {len(block.value)} / {block.limit}")

Symptoms: Agent accessing data it shouldn’t see.

Solutions:

  1. Review block attachments: client.agents.retrieve(agent_id).block_ids
  2. Detach inappropriate blocks: client.agents.blocks.detach()
  3. Update agent persona to clarify access boundaries
  4. Consider splitting one block into multiple with different access

Problem: Race Conditions on Concurrent Updates

Section titled “Problem: Race Conditions on Concurrent Updates”

Symptoms: Two agents try to claim the same task, conflicts occur.

Solutions:

  1. Design blocks to minimize conflicts (separate sections for each agent)
  2. Use timestamps and agent IDs in updates
  3. Implement retry logic for failed updates
  4. Consider optimistic concurrency control
# Good: Each agent updates their own section
"""
TASK-001:
Status: In Progress
Claimed by: Worker_1
Timestamp: 2024-10-08 14:30
TASK-002:
Status: In Progress
Claimed by: Worker_2
Timestamp: 2024-10-08 14:31
"""
  • Smaller blocks (<5Klt;5K chars): Faster loading, more focused context
  • Larger blocks (>10Kgt;10K chars): More context but slower processing
  • Optimal: Keep blocks focused on single purpose, split large blocks
  • Recommended: 3-7 blocks per agent
  • Each block adds: Context in agent’s working memory
  • Too many blocks: May dilute agent focus
  • Too few blocks: May limit coordination capabilities
  • High-frequency updates (many agents, frequent changes): Consider separate blocks to reduce contention
  • Low-frequency updates (policies, references): Larger consolidated blocks are fine

Shared memory blocks enable compliance with data privacy regulations:

# GDPR/HIPAA Example: Isolate sensitive data
hr_employee_data = client.blocks.create(
label="hr_employee_data",
description="CONFIDENTIAL - HR Department only. Contains PII."
)
# Only attach to authorized agents
hr_director = client.agents.create(
block_ids=[hr_employee_data.id] # Only HR has access
)
# Sales/Engineering agents do NOT get access
sales_agent = client.agents.create(
block_ids=[sales_knowledge.id] # No HR data access
)

Track block access for compliance:

# Check block usage
block_info = client.blocks.retrieve(block_id=sensitive_block.id)
print(f"Accessed by: {block_info.agent_ids}")
# Log all agents with access
for agent_id in block_info.agent_ids:
agent = client.agents.retrieve(agent_id=agent_id)
print(f" {agent.name} - {agent.created_at}")

Remove access when no longer needed:

# Employee leaves company - revoke agent access
client.agents.blocks.detach(
agent_id=former_employee_agent.id,
block_id=company_confidential.id
)
# Or delete the agent entirely
client.agents.delete(agent_id=former_employee_agent.id)

Learn shared memory patterns through hands-on tutorials:

Shared memory blocks enable seamless multi-agent coordination without explicit messaging ✓ Access patterns range from simple (all agents) to complex (hierarchical organizations) ✓ Privacy boundaries protect sensitive data while enabling collaboration ✓ Real-time sync ensures all agents see updates immediately ✓ Scales from 2 agents to enterprise systems with 10+ agents ✓ Complements agent-to-agent messaging for complete multi-agent systems

Shared memory blocks are a powerful primitive for building sophisticated multi-agent systems. Start with simple patterns (Tutorial 1) and progress to complex architectures (Tutorial 4) as your needs grow.