DEV Community

Mohammed Rafay
Mohammed Rafay

Posted on Originally published at memorysync.hashnode.dev

Strands Agents memory: how to add long-term memory to a Strands agent (MemoryManager, stores and per-user recall)

Disclosure: I'm Mohammed, founder of MemorySync. I drafted this with AI assistance and checked it against the Strands Agents docs and MemorySync's Strands guide. Code status: on Oct 25, 2026 I installed strands-agents 1.62.0 and strands-memorysync 1.1.0 on Python 3.13 and ran every import and constructor below (agent, MemoryManager, TestMemoryStore, MemorySyncStore with InvocationTrigger, get_tools()). I also ran one agent(...) turn end to end with a scripted stand-in model and MemorySync's HTTP responses mocked locally, to see what the store sends and what reaches the model. No live LLM or live MemorySync API call was made.

By default a Strands agent starts each conversation from zero. Strands Agents memory is one of three kinds of state the Strands docs separate (memory overview):

  • Session management persists the full conversation so you can resume it.
  • Conversation management keeps a session inside the context window.
  • Memory carries durable knowledge across sessions without replaying old conversations.

If your agent "forgets the user" between sessions, you need the third one.

How Strands memory works

You attach a MemoryManager with one or more stores. Across those stores, the manager does three jobs:

  1. Recall: the agent searches memory on demand through a tool.
  2. Injection: relevant memories are added to the prompt automatically before the model runs.
  3. Extraction: conversation messages are turned into memories and written to stores.

Recall and injection are on by default when you attach a store. Writing is opt-in.

Step 1: Prototype with the local test store

from strands import Agent
from strands.memory import MemoryManager
from strands.vended_memory_stores.test_memory_store import TestMemoryStore

# Persists to ~/.strands/memory/notes.json by default.
store = TestMemoryStore(name="notes")
agent = Agent(memory_manager=MemoryManager(stores=[store]))
Enter fullscreen mode Exit fullscreen mode

This ran as written. It's fine on your laptop, but a JSON file in a home directory isn't per-user and won't follow a container redeploy. For production, Strands documents an Amazon Bedrock Knowledge Base store, a file store on any storage backend, and a custom-store interface.

Step 2: Swap in a per-user hosted store

MemorySync ships strands-memorysync, a store for the same MemoryManager (guide). It needs Python 3.10+, a Strands release with the MemoryManager (2026+), and a MemorySync API key in MEMORYSYNC_API_KEY.

pip install strands-agents strands-memorysync
Enter fullscreen mode Exit fullscreen mode
from strands import Agent
from strands.memory import MemoryManager, InvocationTrigger
from strands_memorysync import MemorySyncStore

store = MemorySyncStore(
    user_id="customer-42",        # required: whose memories these are
    session_id="support",         # optional: tags this conversation's facts
    extraction={"trigger": InvocationTrigger()},  # send every turn, see below
)

agent = Agent(memory_manager=MemoryManager(stores=[store]))
agent("Which seat should I book?")
Enter fullscreen mode Exit fullscreen mode

What happens: before every model call, the manager asks the store for relevant memories and injects them. After each exchange, only the user's messages are sent for fact extraction. Assistant replies, tool messages and system messages are not sent. In my local run (stand-in model, mocked API), the recalled memory showed up in the model's input, and the only write was the user's message with role: "user". The assistant's reply was not sent.

Step 3: Fix the "first few turns are forgotten" surprise

Strands' default extraction trigger fires every five invocations, so a user's first exchanges aren't written yet and early recalls come back empty. That's by design. The synchronous agent(...) call also flushes after each call, but invoke_async does not. If you want memories from the first exchange, pass InvocationTrigger() as above. In my local run, the first turn's user message was written right after that first call. The MemorySync guide recommends this because its writes are idempotent (a retry isn't extracted twice).

Step 4: Pick a stable user_id

Use your own user ID, an email or a UUID, and use the same value every session. A different value means an empty recall. The user_id is also the isolation boundary between your users. Create one store per user (or per request) rather than sharing one store across users.

Optional: explicit memory tools

tools = store.get_tools()   # -> memorysync_search, memorysync_save
Enter fullscreen mode Exit fullscreen mode

I confirmed these two names on the box, and the defaults in the table below against the installed MemorySyncStore signature. There's deliberately no delete tool, so deletion stays an API or admin action, and the user identity is never a tool parameter the model can change.

Useful knobs

Parameter Default What it does
top_k 5 Memories considered per model call
min_prompt_chars 8 Skip recall for trivial prompts
writable True Allow extraction writes

Common questions

Do I still need a session manager? Yes, if you want to resume the exact conversation. Memory and session persistence solve different problems, and Strands documents them separately.

Why are recalls empty right after I store something? Extraction runs asynchronously, so give it a moment. Also check that both runs use the same user_id, and that you're not on the five-turn default trigger.

ModuleNotFoundError: strands? Install the framework itself: pip install strands-agents.

Want to watch a fact survive a page reload before you wire it in? Try MemorySync in the browser. No signup is needed.

Sources

Top comments (0)