MemorySync
Integrations

Agno Memory

Give Agno agents long-term memory with one constructor argument. MemorySyncDb plugs into Agno’s own MemoryManager: agno’s native pipeline extracts memories after every run, they persist to MemorySync, and they’re injected back into context automatically — with real semantic recall and an async-native twin.

Agno splits session storage from MemorySyncDb, which backs MemoryManager with semantic recall and guarded writes.

How it works

  1. Install agno-memorysync from PyPI.
  2. Keep your sessions wherever they already live (SQLite, Postgres…).
  3. Point the agent’s MemoryManager at a MemorySyncDb — memories now live in MemorySync.
  4. Done — agno extracts memories after each run and injects them on the next. No per-turn code.

Before you start

  1. A MemorySync API key. Create one in the dashboard under Settings → API Keys, inside a project.
  2. Python 3.10+ with agno 2.8 or newer.

Install

One package:

Terminal
pip install agno-memorysync

Quickstart

Step 1 — split sessions from memories

Agno’s db= holds sessions; the MemoryManager’s db= holds memories. Keep sessions local, put memories in MemorySync:

agent.py
from agno.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.memory import MemoryManager
from agno_memorysync import MemorySyncDb
agent = Agent(
db=SqliteDb(db_file="agent.db"), # sessions: local
memory_manager=MemoryManager(db=MemorySyncDb()), # memories: MemorySync
update_memory_on_run=True, # extract + store after every run
user_id="customer-42", # whose memories these are
)

Step 2 — run it

Tell the agent something in one run; it recalls it in the next — even after a restart:

agent.py
agent.run("I prefer teal dashboards and window seats")
agent.run("Which color should the new chart use?") # remembers: teal

A memory-only db — on purpose

Agno’s BaseDb interface also covers sessions, evals, knowledge, metrics and traces. MemorySyncDb implements every memory method for real and makes every other surface raise MemorySyncMemoryOnlyError with the fix in the message — a backend that silently pretended to store sessions would lose them. Pair it with any session db, as in the quickstart.

Each memory is one value in MemorySync’s state store for agno, keyed by its memory_id and holding the UserMemory exactly as the manager wrote it: text, topics, input, feedback, agent and team ids, timestamps. A memory id always has exactly one current value. The memory’s text is also sent to fact extraction; the extracted facts (tagged with the memory’s agent_id / team_id) are recallable from every MemorySync surface, and they are what the MemorySync dashboard shows. Updating a memory replaces the facts extracted from its previous version, and deleting a memory deletes its facts too, so nothing resurfaces through recall.

Real semantic recall

Agno’s own search_user_memories offers last_n, first_n, and agentic — the last is an extra LLM round-trip that reads all memories and picks ids. search_content here ranks the user’s memories by similarity on the MemorySync side: no LLM call, best match first.

search.py
db = MemorySyncDb()
memories = db.get_user_memories(
user_id="customer-42",
search_content="what does the user like to eat?", # ranked server-side
limit=5,
)

Async agents

For Agent.arun paths, use the async twin — the MemoryManager awaits AsyncBaseDb natively. It is the only async-native memory backend in the agno ecosystem; the sync db never blocks the event loop either, because every read is bounded by the budget.

async_agent.py
from agno_memorysync import AsyncMemorySyncDb
manager = MemoryManager(db=AsyncMemorySyncDb())

Deletes that cannot nuke an account

CallWhat happens
delete_user_memory(id, user_id=...)Deletes that memory and the facts extracted from it; already-gone id is an idempotent no-op; a FAILED delete raises
delete_user_memories([ids], user_id=...)Bulk variant, same guarantees
clear_memories()Always raises — a nullary everything-wipe is how accounts get destroyed
forget_user_memories(user_id)The explicit, scoped, loud per-user wipe (memories and their facts); returns the number removed

Writes fail open by default with loud logs and an honest None return, so post-run extraction can never turn a successful agent run into a failure.

Configuration

ParameterDefaultMeaning
api_keyMEMORYSYNC_API_KEY env varAPI key
default_user_iddefaultNamespace when agno passes user_id=None
recall_timeout1.2Hard read budget in seconds
fail_open_writesTrueExtraction failures log instead of raise
sourceagnoNot used for storage: memories always live under the agno source, so every install shares them

Quotas and plan limits

Hitting a monthly plan limit never breaks a run. On free and paid plans, over-limit writes are accepted without storing and reads return empty — the agent keeps working. Evaluation keys instead surface a truthful 429, so you find out during testing, not in production.

Troubleshooting

  • Memories stored but never appear in replies — you passed a verbatim system_message= string, which replaces agno’s built system prompt (where memories are injected). Use instructions= for your prompt text instead.
  • `MemorySyncMemoryOnlyError` — you pointed a session/knowledge/eval surface at this db. Keep those on your local db (see the quickstart split); only memory_manager= gets MemorySyncDb.
  • Recall returns nothing right after storing — extraction is asynchronous; give it a moment. Also confirm both runs use the same user_id.
  • A run went without memories once — that’s the read budget working: a slow lookup is skipped rather than delaying the run.
  • `clear_memories()` raised — deliberate: a no-argument everything-wipe is refused. Use forget_user_memories(user_id) for an explicit per-user wipe.

Supported versions

SurfaceRequiresVerified on
agno-memorysync 1.1.0agno 2.8+ (Python 3.10+)63 CI checks against the latest agno: the REAL MemoryManager add/replace/delete flows and a REAL Agent run (stub model, local session db) asserting MemorySync memories reach the model context — plus the memory-only scope contract, semantic search_content, one-value-per-memory idempotency, facts replaced on update and deleted with their memory, the guarded nullary clear, the AsyncBaseDb twin, the 1.2s budget, and both monthly-quota server modes

How it compares

Mem0 (`Mem0Tools` + cookbook)Zep (`ZepTools` + cookbook)SupermemoryMemorySync
Integration depth✗ LLM tools — the model must *decide* to recall✗ LLM tools + a hardcoded time.sleep(10) for indexing— nothing at all✓ native MemoryManager backend — automatic extraction + injection
Async agents✗ sync client blocks the event loop✗ sync—✓ bounded-budget sync db + a true AsyncBaseDb twin
Missing user id✗ returns error strings as tool output——✓ deterministic default namespace, never cross-user
Retries / re-runs✗ cookbook: *"comment out this line after running once"*——✓ one value per memory id — an unchanged memory is never stored or extracted twice
Memory freshness✗ cookbook injects a static snapshot fetched at construction✗ same static-dependencies pattern—✓ fresh recall every run
Agent scoping✗ search/get_all ignore agent_id——✓ agent_id/team_id stored and filterable
Semantic search———✓ server-side similarity search via search_content (agno itself has only last_n / first_n / an extra LLM call)
Whole-store wipe———✓ clear_memories() refuses; per-user wipe is explicit

Where to go next

Was this page helpful?