Your Agent Remembers Nothing. AgentCore Memory Fixes Two Tiers and Leaves Trust to You.
AgentCore Memory is two first-party classes and two undocumented idioms; pick by provenance, configure extraction strategies, and never treat the extractor as a validator.

Short-term checkpoints, long-term extraction, and the fork AWS never names: memory as infrastructure versus memory as tools.
Your agent re-discovers the same competitor tier change every Monday with full confidence, while the long-term store you wired has been a silent no-op. Two tiers can be managed; trust on write still cannot.
In this article: You will learn how Amazon Bedrock AgentCore Memory splits into
AgentCoreMemorySaverandAgentCoreMemoryStore, why an extraction strategy is the silent difference between recall and a well-instrumented no-op, how AWS documents two incompatible wiring idioms, and whenDynamoDBSaveris the better short-term answer. By the end you will wire durable memory for DeepAgents and the Claude Agent SDK, choose a write path by provenance, and know which trust problems the service will never solve.
Every Monday, the market-intelligence agent discovers that a competitor changed its enterprise tier. It reports this with enthusiasm. It discovered the same thing last Monday. The analyst has stopped reading the first paragraph.
That is the visible failure. The invisible one is worse. Your LangGraph checkpointer is InMemorySaver. That memory is the microVM's memory. The microVM terminates after fifteen minutes of inactivity. The join you wrote is correct. The thread ID is threaded. The state still evaporates, because you persisted it into a container whose whole design premise is that it is disposable.
Both problems are memory problems, and they are not the same memory. Getting that distinction right is most of this article.
Three tiers, and only two of them transfer
The harness component list has memory as one item, which is a simplification the moment you build it. There are three tiers, and AgentCore has an answer for exactly two.
Working memory is what the model sees this turn: selection, compaction, eviction, and the token budget. This is the context manager. It is the highest-frequency decision in your loop, and it does not transfer. AgentCore ships nothing here. No managed service has an opinion about what your model should be looking at right now.
Short-term memory is continuity within a task: the messages, the graph state, and the fact that you already called the pricing tool and got a 503. This is what dies with the microVM.
Long-term memory is continuity across tasks: this analyst prefers tables over prose, this competitor's page moved in March, and we already flagged that tier change three weeks ago.

AgentCore Memory ships both of the last two as two different classes, which is the part everybody misses.
Two classes, two jobs
from langgraph_checkpoint_aws import AgentCoreMemorySaver, AgentCoreMemoryStore
checkpointer = AgentCoreMemorySaver(MEMORY_ID, region_name=REGION)
store = AgentCoreMemoryStore(MEMORY_ID, region_name=REGION)
A common assumption is that AgentCoreMemoryStore is an adapter you write against BaseStore. It is not. Both classes are first-party in langgraph-checkpoint-aws, maintained by AWS inside the langchain-aws monorepo. Check before you build the bridge.
AgentCoreMemorySaver is the checkpointer. It saves and loads checkpoint objects: user and AI messages, graph execution state, and metadata, stored through AgentCore Memory's blob types. This is short-term durability, and it is the direct answer to state that evaporates with the microVM.
AgentCoreMemoryStore is the long-term store. You put conversational messages into it, and then something genuinely different happens: the AgentCore Memory service extracts insights, summaries, and user preferences in the background, and later sessions semantic-search those extracted memories rather than the raw messages.

That asymmetry is the whole product. The checkpointer stores what happened. The store stores what it meant, and it figures out the meaning asynchronously, on AWS's compute, while your agent is doing something else. You are not running an extraction pipeline. You are not running a vector database. You put messages in and get facts back.
The config that makes it work
config = {"configurable": {
"thread_id": "session-1", # maps to AgentCore session_id
"actor_id": "research-agent", # maps to AgentCore actor_id. REQUIRED.
}}
You already have thread_id if you joined the AgentCore Runtime session ID into framework state. The same string can key sandbox isolation and checkpoint persistence too. One string, three jobs, and the chain finally runs end to end: one microVM lease, one conversation, one sandbox, and one durable checkpoint.
actor_id is new, and it is required. It is the identity axis: which agent, or which user, this memory belongs to. In the store's pre_model_hook pattern, the namespace is the tuple (actor_id, thread_id), which tells you exactly how AWS thinks about the hierarchy.
Sit with actor_id for a second, because it is doing more than it appears to. It is the isolation boundary for multi-agent systems, so worker agents can have their own memories rather than trampling a coordinator's. It is also the seam where per-user memory happens. A memory system whose primary key includes an identity is a memory system that was designed for multi-tenancy from the start.
Wiring it: memory as infrastructure
The devguide idiom plugs memory into the loop:
from langgraph.prebuilt import create_react_agent
graph = create_react_agent(
model=llm,
tools=tools,
checkpointer=checkpointer, # AgentCoreMemorySaver ①
store=store, # AgentCoreMemoryStore ②
pre_model_hook=pre_model_hook, # saves messages before the model call ③
# post_model_hook=post_model_hook
)
① The checkpointer is short-term durability: AgentCoreMemorySaver keeps thread state past the microVM.
② The store is long-term memory: AgentCoreMemoryStore feeds the service's extraction pipeline.
③ The pre_model_hook is the write gate: it decides which messages enter long-term memory before each model call.
Note: The full extracted listing at code/agent-core/part-08-memory-across-sessions/listings/01-create-react-agent-memory.py shows the wiring without markers.
The hook is where you decide what is worth remembering:
def pre_model_hook(state, config: RunnableConfig, *, store: BaseStore): # ①
"""Save the latest human message to long-term memory before the LLM runs."""
actor_id = config["configurable"]["actor_id"]
thread_id = config["configurable"]["thread_id"]
namespace = (actor_id, thread_id) # ②
for msg in reversed(state.get("messages", [])): # ③
if isinstance(msg, HumanMessage):
store.put(namespace, str(uuid.uuid4()), {"message": msg}) # ④
break
① The harness injects state, config, and store into the hook on every model turn.
② Namespace is the (actor_id, thread_id) tuple AWS uses as the memory hierarchy key.
③ Messages are scanned newest-first so only the latest human turn is considered.
④ store.put writes that one message under a fresh key; extraction runs later in the service.
Note: The full extracted listing at code/agent-core/part-08-memory-across-sessions/listings/02-pre-model-hook.py shows the hook without markers.
Nothing about that is exotic, and that is the point. The checkpointer needs no code at all. The store needs a hook that says which messages matter. Everything after that is the service's problem: extraction, consolidation, indexing, and retrieval.
For DeepAgents, both slots exist on create_deep_agent as constructor arguments (checkpointer, store). The harness concerns are visible as parameters, so wiring a managed service into one is a keyword argument rather than an integration.
The gotcha that makes it all silently do nothing
Here it is, and it is the single most expensive fact in this article.
Your AgentCore Memory resource must have at least one extraction strategy configured, such as semanticMemoryStrategy. Without one, create_event stores raw events and extracts nothing. No error. No warning. Long-term recall returns empty, forever, and your agent behaves exactly as if you had never wired memory at all.
The asymmetry is what gets people: the checkpointer works fine without strategies. So you wire both, test conversation continuity, watch it work, ship it, and discover months later that the long-term half has been a very well-instrumented no-op.
The strategies are semantic, summary, user-preference, and episodic. Choose deliberately. The default of "none" is a valid configuration that means "store, do not think."
Gotcha: no strategies means no extraction means no recall, silently. Check your Memory resource's strategy list before you debug anything else.
The fork nobody names
AWS documents two different idioms for AgentCore Memory, in two different places, and never says they are alternatives.
The devguide idiom is above: checkpointer, store, and hooks. Memory is infrastructure. It happens to the agent.
The other idiom is in AWS's own competitive research agent blog, and it looks nothing like it:
from bedrock_agentcore.memory import MemoryClient
from langchain_core.tools import tool
memory_client = MemoryClient(region_name="us-west-2") # ①
@tool # ②
def save_research_insights(insights: str, session_id: str = "default") -> str:
"""Save competitive research insights to AgentCore long-term memory."""
memory_client.create_event( # ③
memory_id=memory_id, actor_id=actor_id, session_id=session_id,
messages=[(f"Save these research insights:\n\n{insights}", "USER"), # ④
("Insights saved to long-term memory.", "ASSISTANT")],
)
return "Insights saved and are extracted into long-term memory."
① MemoryClient is the direct AgentCore Memory API, not a LangGraph checkpointer or store adapter. ② @tool exposes the write as a model-callable action, so remembering is a visible decision in the trace. ③ create_event persists a turn into the Memory resource for background extraction. ④ The USER/ASSISTANT pair is the event shape the service expects when it extracts insights.
Note: The full extracted listing at code/agent-core/part-08-memory-across-sessions/listings/03-save-research-insights-tool.py shows the tool without markers.
Memory as a tool. The agent decides to remember, and remembering is an action it takes, visible in the trace, with an argument you can read.
The blog goes further: it sets checkpointer=None and store=InMemoryStore(), with a comment that InMemoryStore is "internal storage for Deep Agents (separate from AgentCore Memory)" and that you should use AgentCoreMemorySaver for session resumability. So AWS's flagship DeepAgents example deliberately does not use the store, and flags the checkpointer as a simplification it skipped.
That is not a contradiction. It is a design fork, and it is a real one:
Memory-as-infrastructure is automatic and complete. Every message you hook gets saved. Nothing depends on the model choosing correctly. The cost is that you cannot see the decision, because there was no decision, and everything the agent read is now something the agent will remember.
Memory-as-tools is selective and legible. The agent calls save_research_insights with an explicit argument, and that call is a span in your trace with content you can inspect, gate, and validate. The cost is that the model can forget to remember, which is a real failure mode with a real fix: put it in the system prompt. It also leaves a real residue: the fix is a suggestion to a component that can be talked out of suggestions.

The tell for which to pick is not elegance. It is provenance. If everything entering memory originates inside your trust boundary, take the infrastructure idiom; it is less code and it does not forget. If any of it came off a web page, take the tools idiom, because a tool call is a function you control, and a function you control is where a validator goes.
For a market-intelligence agent with a browser, the answer is the tools idiom for long-term insight writes. You can also run both: use the checkpointer for thread durability (no judgment required, nothing untrusted, pure mechanism) and explicit tools for long-term insight writes (judgment required, untrusted input, validator attached). That is what I would ship.
The Claude Agent SDK wiring
Adapter, as usual, and instructively so.
Every first-party memory integration is LangGraph-shaped, because AgentCoreMemorySaver is a BaseCheckpointSaver and the Claude Agent SDK has no such concept. So for the SDK, memory wraps the loop rather than plugging into it: retrieve relevant memories before query(), inject them into the prompt or system context, run the loop, and create_event after.
memories = memory_client.retrieve_memories(memory_id=..., actor_id=analyst_id, query=topic) # ①
prompt = f"Prior findings:\n{format(memories)}\n\nTask: {task}" # ②
async for message in query(prompt=prompt, options=options): # ③
...
memory_client.create_event(memory_id=..., actor_id=analyst_id, session_id=..., messages=[...]) # ④
① Retrieve prior long-term memories for this actor and topic before the loop starts. ② Inject those findings into the prompt so the model sees them this turn. ③ The SDK query loop runs with no built-in checkpointer or store slot. ④ create_event after the loop is the explicit write path you own.
Note: The full extracted listing at code/agent-core/part-08-memory-across-sessions/listings/04-sdk-memory-wrap-loop.py shows the wrap-loop pattern without markers.
Verify MemoryClient's method names against your installed bedrock-agentcore; the retrieval surface is less stable than the write surface.
That shape costs you the automatic part: nothing is saved unless you save it, and the SDK's own resume is in-process and dies with the microVM, so you are the durability layer. What it buys is that every read and every write is a line in your code. There is no hook, so there is no invisible write path. For an agent chewing on hostile input, the SDK's clumsier integration is accidentally the safer default.
The recurring trade shows up again: the ergonomic harness makes the dangerous thing easy, and the awkward one makes it explicit.
The checkpoint storm
A production fact that no marketing page will tell you.
LangGraph checkpoints after every node. That is by design, for fault tolerance. Now put AgentCoreMemorySaver behind it and count the network calls.
A team building a real-time conversational agent measured a six-node workflow: user message, LLM, tool call, LLM, tool call, and response. That workflow generated 62 API calls: 49 createEvent plus 13 listEvents, adding roughly 8.7 seconds of latency per user request. They filed an issue asking for a checkpoint_mode="end_of_workflow" parameter, which would take it to two calls and about 300 milliseconds.

Check whether that shipped in your version. If it has not, you have three options: accept the latency, buffer writes yourself, or use a checkpointer whose per-node cost is lower.
When AgentCore Memory is not the answer
The same package, langgraph-checkpoint-aws, ships DynamoDBSaver, with S3 offload for checkpoints over 350 KB, ttl_seconds, and compression. It also ships ValkeyStore and ValkeyCache.
DynamoDBSaver is the boring answer, and for pure thread durability it is often the better one: single-digit-millisecond writes, a TTL you control, a cost model your team already understands, and no extraction strategies to misconfigure.
The case for AgentCoreMemorySaver is not that it is a faster key-value store. It is that it is the same resource as the store, so your short-term and long-term memory live in one place with one identity model and one audit surface, and the extraction pipeline you did not build runs against the events you were already writing.
If you need long-term semantic recall, that consolidation is worth a lot. If you need conversations to survive a microVM and nothing else, use DynamoDB and skip the long-term half of this article.
In production: pick the checkpointer for the memory tier you actually need, not for brand consistency. Mixing is legitimate and sometimes correct: DynamoDBSaver for threads and AgentCoreMemoryStore for insights.
What stays yours
The service extracts, consolidates, indexes, and searches. It will not do the following, and these are where memory systems actually fail:
Retrieval scoring and saliency. The store returns semantic matches. It has no idea that a finding from March about a discontinued product is noise now. Recency weighting, relevance thresholds, and the decision to retrieve nothing rather than something marginal are your policy.
Deduplication on write. Nothing stops you writing the same insight eleven times in slightly different words, at which point semantic search returns eleven copies and your context window pays for all of them.
Forgetting. There is no managed answer to "this memory is now wrong." Correction and expiry are a design problem, and an agent confidently citing a fact that stopped being true in April is exactly as damaging as one that never knew it.
And the validator. A read_write memory plus untrusted input is a prompt-injection write path into trusted memory. Your browser subagent reads a page. The page contains a sentence addressed to AI agents. The claim rides into an insight, the insight goes through create_event, the extraction strategy runs, and AWS faithfully persists it as a fact your agent now believes. Three weeks later a different session retrieves it and puts it in front of a pricing committee.

Every component worked correctly. The extraction strategy is not a validator. semanticMemoryStrategy extracts what is there; it has no opinion about whether what is there is true. A managed memory service that faithfully persists a lie is a managed memory service working as designed.
So: default shared reference material to read-only. Put the validator in the write path, in code, where the agent cannot route around it. And carry provenance into the store, so that a retrieved memory can answer "who told you that, and when."
Pattern check: Memory implements the persistence and extraction machinery, which is genuinely a lot. It does not implement trust. Every memory system is a trust system, and this one delegates trust entirely to you.
Do this today
- Create or inspect your AgentCore Memory resource and confirm at least one extraction strategy (
semantic,summary,user-preference, orepisodic) is configured before you debug "empty recall." - Replace
InMemorySaverwithAgentCoreMemorySaverorDynamoDBSaverso thread state survives the microVM; passthread_idand the requiredactor_idinconfigurable. - For DeepAgents or
create_react_agent, wirecheckpointerandstore, then add apre_model_hookthat puts only the messages you intend to remember. - If the agent browses untrusted pages, expose long-term writes as tools (
MemoryClient.create_event) so a validator can sit on a function you own. - For Claude Agent SDK agents, wrap the loop: retrieve before
query(), inject into the prompt, write withcreate_eventafter, and verify method names against your installedbedrock-agentcore.
Memory without trust is just a durable rumor mill
You can now stop re-discovering last week's news. Conversations survive after a microVM expires. Insights accumulate across sessions in a store that extracts meaning without you running a pipeline, keyed by an identity designed for multiple tenants from the beginning.
That identity is still a placeholder if actor_id is a hard-coded string and every analyst authenticates to market data as the same service principal. Entitlements become "we trust the agent," and the audit trail becomes "the agent did it." Identity that injects credentials into tool code, never into model context, is the next layer of mechanical enforcement.
Until then, treat AgentCore Memory as what it is: excellent persistence and extraction machinery with no opinion about truth. Wire the tier you need. Name the fork. Put the validator where the agent cannot walk around it. Monday's competitor tier change should be remembered once, on purpose, and only if it was real.