Back to Theory
Theory9 min read · July 10, 2026

Multi-Agent Memory Architecture: How to Share Context Across AI Agents

Multiple AI agents sharing a single memory store need namespace isolation, typed edges for cross-agent context, and concurrent-safe read patterns. Feather DB handles all three with its entity system, graph traversal API, and in-process concurrency model.

F
Feather DB
Engineering

Multi-agent systems where multiple AI agents share context require three things from their memory layer: namespace isolation (agent A's private memories cannot bleed into agent B's context), typed edges for cross-agent knowledge sharing (agent A can link its findings to agent B's context explicitly), and concurrent-safe read access. Feather DB handles all three through its entity system, graph traversal API, and in-process concurrency model — multiple agents share a single .feather file with strong isolation guarantees and sub-millisecond concurrent reads.

Why Multi-Agent Memory Is Different

Single-agent memory is a solved problem: one agent, one memory store, query by entity ID. Multi-agent memory introduces three challenges that single-agent architectures don't face:

  1. Isolation: Agent A's memories about User X must not appear in Agent B's context for the same user. A support agent's private diagnostic notes should not surface in the sales agent's context.
  2. Controlled sharing: Some information should cross agent boundaries. A research agent's findings should be accessible to the report-writing agent. A data-gathering agent should be able to share context with an analysis agent.
  3. Concurrency: Multiple agents querying the same store simultaneously must not corrupt each other's reads or produce inconsistent results.

Feather DB addresses all three with a namespace + entity model, typed edges for explicit sharing, and a reader-writer locking model that allows concurrent reads with exclusive writes.

Namespace Model: Isolation by Design

Every memory in Feather DB has metadata fields. The multi-agent isolation pattern uses two fields: user_id (who this memory is about) and agent_id (which agent owns this memory). Shared memories omit the agent_id field and are accessible to all agents.

import feather_db as fdb
from datetime import datetime

# Shared memory store for all agents
db = fdb.FeatherDB("multi_agent_memory.feather")

def store_agent_memory(
    text: str,
    user_id: str,
    agent_id: str,
    importance: float = 0.6,
    shared: bool = False
) -> str:
    """
    Store a memory with namespace isolation.
    If shared=True, omit agent_id so all agents can access it.
    """
    metadata = {
        "user_id": user_id,
        "stored_at": datetime.now().isoformat(),
        "shared": shared
    }
    if not shared:
        metadata["agent_id"] = agent_id

    return db.add(
        text=text,
        metadata=metadata,
        importance=importance
    )

def recall_agent_context(
    query: str,
    user_id: str,
    agent_id: str,
    include_shared: bool = True,
    top_k: int = 8
) -> list:
    """
    Retrieve memories for a specific agent.
    By default, includes both private agent memories and shared memories.
    """
    results = []

    # Agent-private memories
    private_memories = db.search(
        query=query,
        top_k=top_k // 2,
        filters={"user_id": user_id, "agent_id": agent_id}
    )
    results.extend(private_memories)

    if include_shared:
        # Shared memories (accessible to all agents)
        shared_memories = db.search(
            query=query,
            top_k=top_k // 2,
            filters={"user_id": user_id, "shared": True}
        )
        results.extend(shared_memories)

    # Re-rank combined results by score
    results.sort(key=lambda x: x['score'], reverse=True)
    return results[:top_k]

Cross-Agent Context Sharing with Typed Edges

When Agent A discovers something that Agent B should know, the recommended pattern is not to copy the memory — it is to link it. Feather DB's typed edges allow Agent A to create a link from its memory to Agent B's context namespace, without duplicating data:

# Agent A (research agent) stores a finding
research_agent_id = "research_agent"
analysis_agent_id = "analysis_agent"

research_finding_id = store_agent_memory(
    text="User's customer churn rate increased 23% in Q2 2026, primarily from the enterprise tier",
    user_id="client_acme",
    agent_id=research_agent_id,
    importance=0.9,
    shared=False  # Private to research agent initially
)

# Research agent decides to share this with the analysis agent
shared_context_id = store_agent_memory(
    text="[Shared from research] ACME churn: +23% Q2 2026, enterprise tier dominant driver",
    user_id="client_acme",
    agent_id=analysis_agent_id,
    importance=0.9,
    shared=False  # Private to analysis agent
)

# Link the shared copy to the original for provenance
db.link_nodes(
    source_id=shared_context_id,
    target_id=research_finding_id,
    edge_type="derived_from",
    weight=1.0
)

# When analysis agent retrieves context, it gets the shared copy
# and can traverse to the original finding via context_chain()
analysis_context = db.context_chain(
    query="ACME churn data",
    hops=2,
    filters={"user_id": "client_acme", "agent_id": analysis_agent_id}
)
# Returns: the shared copy + the original finding (via derived_from edge)

Complete Multi-Agent System: 4-Agent Pipeline

Here is a complete 4-agent system where agents specialize in research, analysis, writing, and review — sharing context through Feather DB:

import feather_db as fdb
from openai import OpenAI
from dataclasses import dataclass
from typing import Optional

db = fdb.FeatherDB("pipeline_memory.feather")
client = OpenAI()

@dataclass
class Agent:
    agent_id: str
    role: str
    system_prompt: str

    def recall(self, query: str, user_id: str, top_k: int = 8) -> list:
        """Recall memories accessible to this agent."""
        private = db.search(
            query=query,
            top_k=top_k // 2,
            filters={"user_id": user_id, "agent_id": self.agent_id}
        )
        shared = db.search(
            query=query,
            top_k=top_k // 2,
            filters={"user_id": user_id, "shared": True}
        )
        combined = sorted(private + shared, key=lambda x: x['score'], reverse=True)
        return combined[:top_k]

    def remember(self, text: str, user_id: str, importance: float = 0.7,
                 shared: bool = False) -> str:
        """Store a memory from this agent."""
        metadata = {
            "user_id": user_id,
            "agent_id": self.agent_id,
            "stored_at": __import__('datetime').datetime.now().isoformat(),
            "shared": shared
        }
        return db.add(text=text, metadata=metadata, importance=importance)

    def run(self, task: str, user_id: str) -> str:
        """Execute the agent's task with memory context."""
        memories = self.recall(task, user_id)
        context = "\n".join([f"- {m['text']}" for m in memories])

        response = client.chat.completions.create(
            model="gpt-4o",
            messages=[
                {"role": "system", "content": f"{self.system_prompt}\n\nContext:\n{context}"},
                {"role": "user", "content": task}
            ]
        )
        return response.choices[0].message.content


# Define the 4-agent pipeline
research_agent = Agent(
    agent_id="research",
    role="Researcher",
    system_prompt="You are a research agent. Gather and synthesize factual information."
)

analysis_agent = Agent(
    agent_id="analysis",
    role="Analyst",
    system_prompt="You are an analysis agent. Identify patterns and insights from research."
)

writing_agent = Agent(
    agent_id="writing",
    role="Writer",
    system_prompt="You are a writing agent. Produce clear, structured content from analysis."
)

review_agent = Agent(
    agent_id="review",
    role="Reviewer",
    system_prompt="You are a review agent. Check accuracy, clarity, and completeness."
)


def run_pipeline(task: str, user_id: str) -> dict:
    """Run the 4-agent pipeline with shared memory."""

    # Step 1: Research
    print("Research agent running...")
    research_output = research_agent.run(task, user_id)
    research_id = research_agent.remember(
        f"Research findings: {research_output[:500]}",
        user_id=user_id,
        importance=0.85,
        shared=True  # Make available to downstream agents
    )

    # Step 2: Analysis (has access to research via shared memory)
    print("Analysis agent running...")
    analysis_output = analysis_agent.run(
        f"Analyze this research and extract key insights: {research_output}",
        user_id=user_id
    )
    analysis_id = analysis_agent.remember(
        f"Analysis insights: {analysis_output[:500]}",
        user_id=user_id,
        importance=0.85,
        shared=True  # Make available to writing agent
    )

    # Link analysis to research for provenance
    db.link_nodes(analysis_id, research_id, "derived_from", 1.0)

    # Step 3: Writing (has access to both research and analysis)
    print("Writing agent running...")
    writing_output = writing_agent.run(
        f"Write a comprehensive report based on this analysis: {analysis_output}",
        user_id=user_id
    )

    # Step 4: Review
    print("Review agent running...")
    review_output = review_agent.run(
        f"Review this draft for accuracy and completeness: {writing_output}",
        user_id=user_id
    )

    return {
        "research": research_output,
        "analysis": analysis_output,
        "draft": writing_output,
        "review": review_output
    }

Concurrency Model: Concurrent Reads, Safe Writes

Multiple agents running simultaneously will query Feather DB concurrently. Feather DB uses a reader-writer locking model:

  • Concurrent reads: Any number of agents can read simultaneously without blocking each other. A 0.19ms read does not block while 10 other reads are in progress.
  • Exclusive writes: Writes acquire an exclusive lock. If Agent A and Agent B both write simultaneously, one waits (typically under 1ms). For most agent pipelines, this is not a bottleneck — reads dominate writes by 10:1 or more.
  • Single-file model: For extremely high write concurrency (thousands of agents writing simultaneously), use Feather DB Cloud (Q3 2026) which distributes write load across nodes.
import threading
import feather_db as fdb

db = fdb.FeatherDB("concurrent_memory.feather")

def simulate_concurrent_reads(n_agents: int, query: str, user_id: str):
    """Simulate concurrent reads from multiple agents."""
    results = {}
    errors = []

    def agent_read(agent_id: int):
        try:
            memories = db.search(
                query=query,
                top_k=5,
                filters={"user_id": user_id}
            )
            results[agent_id] = len(memories)
        except Exception as e:
            errors.append(str(e))

    # Launch n_agents concurrent reads
    threads = [threading.Thread(target=agent_read, args=(i,)) for i in range(n_agents)]
    for t in threads:
        t.start()
    for t in threads:
        t.join()

    print(f"{n_agents} concurrent reads: {len(results)} succeeded, {len(errors)} errors")
    # Output: 50 concurrent reads: 50 succeeded, 0 errors

simulate_concurrent_reads(n_agents=50, query="user background", user_id="user_001")

Deployment Patterns for Multi-Agent Systems

Pattern 1: Shared file, multiple processes

All agents access the same .feather file. Works well for up to ~100 concurrent agents. Deploy agents as separate Python processes, point them all to the same file path.

Pattern 2: Shard by user

Each user has their own .feather file. All agents for user X use memory_X.feather. This eliminates cross-user contention entirely and makes user data deletion trivial (delete the file).

Pattern 3: Shard by agent type

Research agents use research.feather; writing agents use writing.feather. Shared context is explicitly copied (with a derived_from link) between files. Higher complexity, maximum isolation.

FAQ

How do I prevent one agent's memories from contaminating another agent's context?

Always include "agent_id": agent_id in the filter for every db.search() call. Shared memories use "shared": True in their metadata and are queried with a separate "shared": True filter. The two filter conditions never overlap with agent-private queries.

Can two agents write to the same memory at the same time?

Feather DB's write lock ensures only one write proceeds at a time. The waiting write queues and completes as soon as the lock is released — typically under 1ms wait time. There is no data corruption from concurrent writes.

How do agents discover what other agents have found?

Two mechanisms: (1) shared memories ("shared": True) are accessible to all agents; (2) explicit edges (db.link_nodes()) allow one agent's memory to surface in another's context_chain() traversal via a derived_from or refines edge.

What is the maximum number of agents that can share a single Feather DB file?

Read concurrency is unlimited — any number of agents can read simultaneously. Write concurrency serializes, but with typical agent write rates (a few writes per minute per agent), a single file handles hundreds of concurrent agents without bottleneck.

Can I use Feather DB for a supervisor/worker multi-agent pattern?

Yes. The supervisor agent writes task assignments and overall context to shared memory. Worker agents read their assigned context, execute tasks, and write results back with their agent_id. The supervisor reads all worker outputs via shared memory queries. This is a natural fit for Feather DB's namespace model.