Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Shared memory across frameworks

A practical guide to using one Mnemosyne store as shared memory for agents built on different frameworks - when to give each agent its own branch, how a real conflict surfaces and resolves, and what the concurrency model means for how to actually structure this. Everything below is checked against two real worked examples, not written from theory: examples/cross_framework_merge.py (two agents, one real conflict) and examples/multi_agent_incident_retro.py (four agents, a sequential merge).

Separate branches, or one shared branch?

Give each agent its own branch when its work is provisional until reviewed, or genuinely independent of the others' until merge time. Both worked examples do this: CrewAI's own branch in cross_framework_merge.py, and all four agents' own branches in multi_agent_incident_retro.py. A branch costs nothing but a pointer (ADR-0012), so there is no real reason to default to a shared branch just to save the call to new_branch.

Write straight to a shared branch (usually main) when the agents' writes are already known not to collide - distinct node ids, no overlapping scope, and no review step needed before the write counts. LangGraph's branch in cross_framework_merge.py still uses its own branch even though its write never collides with CrewAI's, because the point of that example is to demonstrate branching generally; in a real deployment where you already know two agents never touch the same ids, writing directly to a shared branch is a reasonable simplification - the merge algorithm (ADR-0013) still protects you if that assumption ever turns out to be wrong, since a real collision would simply surface as a conflict on the next merge rather than silently overwriting.

How a conflict actually surfaces and resolves

A conflict is only possible when two branches both changed the same node id since they diverged. This matters directly for the first question above: if every agent sharing a store writes under a genuinely distinct id scheme (see each adapter's own "Sharing a store with other adapters" README section, and the reserved-namespace finding in #362), two agents on different frameworks structurally cannot conflict with each other at all - which is exactly why multi_agent_incident_retro.py's four-way merge has no conflict to resolve, only four independent findings landing cleanly in sequence.

When a real conflict does happen - two branches that both touch the same node, the way cross_framework_merge.py's two CrewAI branches do - merge() returns a result whose status is "conflicts", not an exception and not a silent pick of one side:

result = store.merge("their-branch", time_ms=...)
if result.status == "conflicts":
    for c in result.conflicts:
        print(c.ours.content, c.theirs.content)
    # decide, then call again with the resolution:
    store.merge(
        "their-branch",
        resolutions={c.id: "theirs" for c in result.conflicts},
        time_ms=...,
    )

Nothing is written until every conflict has a resolution - "ours", "theirs", "base", "delete", or a MemoryNode to set directly (ADR-0014). Which side should win is a decision for whatever is driving the merge (a human, a review step, a rule), not something this guide can answer generically - cross_framework_merge.py picks "theirs" because the scenario's own later event (an escalation) should win over an earlier one (a refund), which is a decision specific to that story, not a default.

What the concurrency model means for a real deployment

The one constraint that actually shapes how you'd structure this for real: redb allows exactly one open handle per store per process. Every agent in both worked examples opens its own backend, writes, and lets the handle drop (the function returns) before the next agent opens its own - never two handles open on the same store path at the same instant in the same process. In practice, this means:

  • Separate processes, same machine, same store path: fine, as long as they are not literally open at the identical instant. A short-lived process (open, write, exit) sharing a store with other short-lived processes is the pattern both worked examples model.
  • One long-running process holding the store open for its whole lifetime: also fine, as long as no second process (or second in-process handle) ever opens that same path while the first is still open.
  • Two agents that need to write at genuinely the same instant, from the same process: not supported by anything in the current substrate. This needs a daemon mediating access, already noted as a backlog item - don't structure a real deployment around an assumption that isn't true yet.

See also

  • The concurrency model - the full one-handle constraint this guide's last section summarises.
  • Each adapter's own README has a "Sharing a store with other adapters" section naming its real reserved id shape.
  • #362 - the research that found which adapter pairs structurally cannot collide, and which pair (the OpenAI Agents SDK and AutoGen) can guarantee one if given the same identifier string.