Neuroloom

Cookbooks

Multi-Agent Workflows

Two engineers working on different features in the same codebase make decisions that affect each other. One discovers a performance constraint. The other hits the same wall three days later and spends four hours diagnosing it from scratch. A shared workspace means the second engineer finds the diagnosis in 30 seconds.

Problem

When multiple developers or agent sessions work on the same codebase, knowledge stays siloed. Context discovered in one session — a bug root cause, a performance ceiling, a security constraint — never reaches the next session. Agents that share a workspace can share that knowledge, but only if they store it in a way that other agents can retrieve.

Persona

The Neuroloom engineering team runs two concurrent Claude Code sessions: one working on the backend API, one on the MCP server. Both need to know about schema changes, performance discoveries, and architectural constraints. Without shared memory, they duplicate work and occasionally contradict each other.

Prerequisites

  • API key from app.neuroloom.dev/settings/api-keys
  • A single shared workspace ID used by all agents (configured via environment variable or .mcp.json)
  • Environment variables set on each agent's host:
    export MEMORIES_API_TOKEN="nl_your_api_key_here"
    export MEMORIES_WORKSPACE_ID="ws_shared_workspace_id"

Step 1: Establish shared context conventions

Before agents start storing memories, agree on conventions. Memories stored with consistent types, tags, and concept labels are easier for other agents to discover.

Store a meta-memory that documents the conventions for your team's workspace:

Use memory_store:
- title: "Workspace memory conventions"
- memory_type: "convention"
- content: "All agents storing to this workspace follow these conventions: (1) Tag memories with the agent identity using tags like 'agent:api', 'agent:mcp', 'agent:frontend'. (2) Use memory_type 'decision' for architectural choices, 'pattern' for reusable solutions, 'incident' for root causes, 'architecture' for structural changes. (3) Always include source_files when a memory relates to specific code. (4) Set importance_score 1.0 for workspace-wide invariants that all agents must know."
- concepts: ["workspace", "conventions", "multi-agent"]
- importance: 1.0
- tags: ["meta", "conventions"]
curl -X POST https://api.neuroloom.dev/api/v1/memories/store \
  -H "Authorization: Token $MEMORIES_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "'"$MEMORIES_WORKSPACE_ID"'",
    "title": "Workspace memory conventions",
    "memory_type": "convention",
    "narrative": "All agents storing to this workspace follow these conventions: (1) Tag memories with agent identity: agent:api, agent:mcp, agent:frontend. (2) Use memory_type decision for architectural choices, pattern for reusable solutions, incident for root causes. (3) Always include source_files when a memory relates to specific code. (4) Set importance_score 1.0 for workspace-wide invariants.",
    "concepts": ["workspace", "conventions", "multi-agent"],
    "importance_score": 1.0,
    "tags": ["meta", "conventions"]
  }'

Step 2: Store from Agent A (API session)

The API engineer discovers a performance constraint while working on the graph endpoint:

Use memory_store:
- title: "pgvector ef_search performance ceiling"
- memory_type: "architecture"
- content: "The default ef_search=40 is insufficient for the graph exploration endpoint. With 10,000+ memories, recall at ef_search=40 drops to ~78%. We use SET LOCAL hnsw.ef_search = 100 for the /memories/explore endpoint and ef_search = 200 for /memories/search when min_importance >= 0.8. Higher ef_search adds ~15ms per query at 10k memories — acceptable for high-recall paths, too slow for real-time autocomplete."
- concepts: ["pgvector", "HNSW", "ef_search", "performance", "recall"]
- files: ["api/neuroloom_api/routers/memories.py", "api/neuroloom_api/services/memory_service.py"]
- importance: 0.93
- tags: ["agent:api", "performance", "pgvector"]
curl -X POST https://api.neuroloom.dev/api/v1/memories/store \
  -H "Authorization: Token $MEMORIES_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "'"$MEMORIES_WORKSPACE_ID"'",
    "title": "pgvector ef_search performance ceiling",
    "memory_type": "architecture",
    "narrative": "The default ef_search=40 is insufficient for the graph exploration endpoint. With 10,000+ memories, recall at ef_search=40 drops to ~78%. We use SET LOCAL hnsw.ef_search = 100 for /memories/explore and ef_search = 200 for /memories/search when min_importance >= 0.8. Higher ef_search adds ~15ms per query at 10k memories.",
    "concepts": ["pgvector", "HNSW", "ef_search", "performance", "recall"],
    "source_files": [
      "api/neuroloom_api/routers/memories.py",
      "api/neuroloom_api/services/memory_service.py"
    ],
    "importance_score": 0.93,
    "tags": ["agent:api", "performance", "pgvector"]
  }'

Response:

{
  "id": "mem-6a3f8e1c",
  "title": "pgvector ef_search performance ceiling",
  "memory_type": "architecture",
  "importance_score": 0.93,
  "created_at": "2026-04-01T11:00:00Z"
}

Step 3: Retrieve from Agent B (MCP session)

The MCP engineer, working on memory_search tool implementation, needs to know about performance constraints before choosing default parameters:

Use memory_search with query "search performance constraints pgvector" and tags ["agent:api"]
curl -X POST https://api.neuroloom.dev/api/v1/memories/search \
  -H "Authorization: Token $MEMORIES_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "'"$MEMORIES_WORKSPACE_ID"'",
    "query": "search performance constraints pgvector",
    "tags": ["agent:api"],
    "limit": 5
  }'

Response:

{
  "results": [
    {
      "id": "mem-6a3f8e1c",
      "title": "pgvector ef_search performance ceiling",
      "memory_type": "architecture",
      "score": 0.92,
      "summary": "ef_search=40 drops recall to ~78% at 10k+ memories; use 100 for explore, 200 for high-recall search"
    }
  ]
}

Agent B now knows the performance constraint discovered by Agent A — without any direct communication between the sessions.


Step 4: Use session context for handoff

When Agent A finishes a work period, it ends the session with a summary. That summary becomes the basis for context injection when Agent B picks up related work.

Agent A ends session:

Use session_end with session_id "ses-api-7b4c2a1f" and summary "Implemented graph exploration endpoint. Discovered ef_search performance ceiling at 10k memories — documented in workspace. Workspace isolation on pgvector queries verified working. Next: MCP session needs to use ef_search=100 for memory_search tool default."
curl -X POST https://api.neuroloom.dev/api/v1/sessions/ses-api-7b4c2a1f/end \
  -H "Authorization: Token $MEMORIES_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "summary": "Implemented graph exploration endpoint. Discovered ef_search performance ceiling at 10k memories — documented in workspace. Next: MCP session needs to use ef_search=100 for memory_search tool default."
  }'

Agent B starts its session:

Use session_start
curl -X POST https://api.neuroloom.dev/api/v1/sessions/start \
  -H "Authorization: Token $MEMORIES_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "'"$MEMORIES_WORKSPACE_ID"'",
    "project_path": "/Users/team/Projects/neuroloom/mcp"
  }'

Response:

{
  "session_id": "ses-mcp-2d9a5f3b",
  "injected_memories": [
    {
      "id": "mem-6a3f8e1c",
      "title": "pgvector ef_search performance ceiling",
      "memory_type": "architecture",
      "importance_score": 0.93
    },
    {
      "id": "mem-conv-1a2b",
      "title": "Workspace memory conventions",
      "memory_type": "convention",
      "importance_score": 1.0
    }
  ]
}

The performance constraint discovered by Agent A is automatically injected into Agent B's context at session start.


Step 5: Handle conflicts between agents

When two agents store memories that contradict each other — different conclusions about the same behaviour — mark the conflict explicitly.

Agent B discovers that ef_search=80 is sufficient for the MCP tool use case (shorter queries, different latency tolerance):

# Store the conflicting finding
curl -X POST https://api.neuroloom.dev/api/v1/memories/store \
  -H "Authorization: Token $MEMORIES_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "'"$MEMORIES_WORKSPACE_ID"'",
    "title": "MCP memory_search ef_search tuning",
    "memory_type": "architecture",
    "narrative": "For MCP tool invocations (memory_search), ef_search=80 balances recall and latency adequately. MCP tool callers tolerate ~8ms more latency vs the REST endpoint but require consistent sub-200ms responses. ef_search=100 from the API recommendation is conservative for this use case.",
    "concepts": ["pgvector", "HNSW", "ef_search", "MCP", "latency"],
    "source_files": ["mcp/neuroloom_mcp/tools/memory_tools.py"],
    "importance_score": 0.87,
    "tags": ["agent:mcp", "performance", "pgvector"]
  }'

Then mark it as a refinement of (not a contradiction to) the original:

curl -X POST https://api.neuroloom.dev/api/v1/memories/relationships \
  -H "Authorization: Token $MEMORIES_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "'"$MEMORIES_WORKSPACE_ID"'",
    "source_memory_id": "mem-mcp-ef80",
    "target_memory_id": "mem-6a3f8e1c",
    "relationship_type": "references",
    "confidence": 0.95
  }'
Note

Use contradicts when two memories represent genuinely opposing conclusions about the same thing. Use references when one memory adds nuance or a specific context to a broader finding. The distinction matters for graph navigation — contradictions surface as warnings, references as related context.


Production Patterns

Agent identity tagging

Always tag memories with the storing agent's identity (agent:api, agent:mcp, agent:frontend). This lets agents filter for memories from their own domain and gives traceability when a memory turns out to be wrong.

# Agent A can search only its own memories
curl -X POST https://api.neuroloom.dev/api/v1/memories/search \
  -H "Authorization: Token $MEMORIES_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "'"$MEMORIES_WORKSPACE_ID"'",
    "query": "performance decisions",
    "tags": ["agent:api"]
  }'

CONTRADICTS resolution process

When a contradicts relationship is discovered (either manually or by automatic relationship detection), resolve it deliberately:

  1. Retrieve both memories with memory_get_detail
  2. Determine which is correct for the current state of the codebase
  3. Store a new resolution memory documenting the investigation
  4. Create a supersedes relationship from the resolution to the incorrect memory

Don't leave contradicts relationships unresolved — they create noise for every agent that retrieves that part of the graph.

Workspace-per-team tradeoffs

A single shared workspace gives the best cross-agent search relevance, but it means all agents see all memories. Consider separate workspaces when:

  • Teams are working on completely independent codebases
  • You need to prevent an agent from accessing sensitive architectural decisions
  • Search quality degrades because memories from unrelated domains dilute results

Use a shared workspace as the default. Split when you have a concrete reason to separate context.


Before You Ship

  • Confirm all agents use the same MEMORIES_WORKSPACE_ID
  • Verify each agent tags its memories with its identity (agent:*)
  • Run memory_search from each agent's perspective and confirm cross-agent memories appear
  • Check that session handoffs inject cross-agent context — verify the injected_memories field in session_start responses
  • Review any automatically discovered contradicts relationships and resolve them explicitly
  • Confirm the workspace conventions memory has importance_score: 1.0 so it appears in every session

Ready to get started?

Start building with Neuroloom for free.

Start Building Free