feat(managed_agents): add Managed Agents Memory Cookbook#573
Conversation
A guided tutorial showing how to give a Managed Agent a memory store so it learns and recalls a customer's shopping preferences across separate sessions. Covers store creation, the resources attachment with per-attachment instructions, inspecting and seeding memories from your own application, and combining a per-customer read-write store with a brand-wide read-only store. https://claude.ai/code/session_01VkfVPdiJTWVh6Vj5owqRXH
Notebook ChangesThis PR modifies the following notebooks: 📓
|
There was a problem hiding this comment.
PR Review
Recommendation: REQUEST_CHANGES
Summary
This adds a well-written memory store cookbook demonstrating a shopping agent that learns and recalls customer preferences across sessions. The writing is clear and pedagogically solid. However, several issues with the event-loop pattern, cleanup, and series conventions need fixing before merge.
Actionable Feedback (5 items)
-
CMA_remember_user_preferences.ipynb(inrun_turn, theelif event.type == "session.status_idle": breakblock) — The idle break omits thestop_reasonguard. The correct pattern (used inutilities.pyand every other CMA notebook) isif event.stop_reason and event.stop_reason.type == "end_turn": break. Without this, arequires_actionidle event (e.g. a tool confirmation) would silently exit the loop mid-turn. -
CMA_remember_user_preferences.ipynb(cleanup cell withclient.beta.sessions.archive(...)) —wait_for_idle_status(client, session.id)must be called before eachsessions.archive(). The server-side status can briefly remainrunningafter the stream closes, causing a non-deterministic 400. All other notebooks in the series do this. -
CMA_remember_user_preferences.ipynb(cleanup cell:client.beta.environments.delete(environment.id)) — Should beclient.beta.environments.archive(environment.id)to match the series convention. The operate notebook explicitly explains whyarchiveis preferred overdeletefor most workflows. -
CMA_remember_user_preferences.ipynb(Step 2 cell:model="claude-sonnet-4-6") — All other CMA notebooks defineMODEL = os.environ.get("COOKBOOK_MODEL", "claude-sonnet-4-6")in the setup cell and referenceMODELinline. This allows CI and users to swap models without hunting through cells. Addimport osand theMODELconstant, then replace the inline string. -
CMA_remember_user_preferences.ipynb(Prerequisites markdown cell:pip install -U anthropic) — The install instruction is in a markdown fenced block rather than a runnable%pip install -q -U anthropiccode cell. Either add a runnable cell or remove the instruction and rely on the directory'spyproject.toml(matchingCMA_iterate_fix_failing_tests.ipynb).
Detailed Review
Code Quality
The run_turn helper re-implements the event loop from scratch rather than wrapping utilities.stream_until_end_turn. The memory-filter logic is a nice demo touch, but doing a full re-implementation means it won't benefit from future fixes to utilities.py, and it carries the stop_reason bug noted above. Consider either wrapping the utilities helper with the memory filter on top, or at minimum ensure the stop condition matches.
The reply = run_turn(...) assignment in the session two cell is never used afterward. Either drop it or add a brief note explaining what a caller would do with it.
The agent_toolset_20260401 dated type string is correct for the current API, but a one-sentence note explaining that toolset types are versioned differently from model aliases would preempt reader confusion.
Security
No issues. No API keys are hardcoded. The notebook uses Anthropic() (picks up ANTHROPIC_API_KEY from the environment), which is consistent with the rest of the CMA series even if it diverges slightly from the repo-wide load_dotenv() pattern.
Suggestions
- Drop or explain the unused
reply =assignment in the session two cell. - Add a brief inline comment on
agent_toolset_20260401noting that toolset types carry explicit version dates (unlike model aliases).
Positive Notes
- Introduction leads with the user problem, not the machinery — exactly the right structure.
- The
[memory]trace inrun_turnoutput is a great teaching aid; seeing the agent read and write memory paths makes the concept concrete. - Model string
"claude-sonnet-4-6"is the correct non-dated alias. - Registry entry has all required fields and the README table row matches the series style precisely.
- The "Going further" section (catalog store pattern, audit/correct pointer) is well-scoped and production-relevant without sprawling.
- Outputs are kept in the notebook per repo convention and the shown outputs are realistic and demonstrate the feature well.
- The beta callout block is well-placed and accurate.
- Prefer uv add over pip in the prerequisites - Clarify that the agent_toolset_20260401 type string identifies the toolset, not a model, and does not need bumping - Drop unused reply variable from the second run_turn call Intentionally skip the dotenv suggestion: the other managed_agents notebooks set up the client without load_dotenv, so adding it here would be the inconsistent choice. https://claude.ai/code/session_01VkfVPdiJTWVh6Vj5owqRXH
Notebook ChangesThis PR modifies the following notebooks: 📓
|
There was a problem hiding this comment.
PR Review
Recommendation: REQUEST_CHANGES
Summary
This notebook adds a clear, well-motivated tutorial for the Managed Agents memory store feature. The prose is excellent, the scenario is concrete, and the [memory] trace lines in the event loop are a great pedagogical touch. A few functional and pedagogical issues need to be addressed before merge.
Actionable Feedback (6 items)
-
CMA_remember_user_preferences.ipynb(inrun_turn,elif event.type == "session.status_idle": break) — The unconditional break onsession.status_idleis a pedagogical hazard: readers will copy this pattern into code that uses custom tools, where the same event fires onrequires_actionmid-turn, and the loop will exit prematurely. The established idiom across the CMA series is to checkstop_reason.type == "end_turn"before exiting. Even thoughagent_toolsetcan't emitrequires_actionhere, the pattern taught matters. -
CMA_remember_user_preferences.ipynb(cleanup cell witharchive()calls) — There is a known race between thesession.status_idleSSE event and the server-side status field settling; callingarchive()immediately after streaming can 400 with "cannot be archived while status is running." The sibling notebooks use await_for_idle_statushelper for exactly this reason. Add that helper call or a shorttime.sleep(1.0)with a comment before eacharchive(). -
CMA_remember_user_preferences.ipynb(seed cell, "Seed a store from your existing data") — The seed cell writes intostore, which is the same store that the cleanup cell deletes. On a second run (or after cleanup),store.idis stale and the call 404s. Either move the seed cell before session creation (which is the correct production workflow anyway — seed before first session, not after), or add a comment warning that it must run before cleanup. -
CMA_remember_user_preferences.ipynb(agent creation cell) — Hard-codesmodel="claude-sonnet-4-6"instead of theMODEL = os.environ.get("COOKBOOK_MODEL", "claude-sonnet-4-6")constant used by every other CMA notebook in this folder. Addimport osand define/use the constant so users can override the model without editing the notebook body. -
CMA_remember_user_preferences.ipynb(seed cell output) — Thememories.create()call produces no output (cell shows empty outputs), making it look like it failed after all the verbose feedback in earlier cells. Addprint(f"Seeded {memory.path}")using the returned memory object. -
CMA_remember_user_preferences.ipynb(run_turnsignature is-> strbut both call sites discard the return value) — Either change to-> Noneto accurately reflect the demo's printing-as-side-effect design, or capture the result at the call sites to show programmatic usage. The current-> strsignature implies value consumers that are never shown.
Detailed Review
Code Quality
The helper function structure is clean and the memory_resource dict being defined once and reused across both sessions is a good pattern. The narrative flow (learn → inspect → recall) is logical and progressive. The markdown-only "Combine stores" section is fine as illustrative pseudocode — just add a note that it should not be run as-is since the catalog object has no cleanup path.
Security
No concerns. The notebook correctly relies on the ANTHROPIC_API_KEY environment variable via the implicit Anthropic() constructor.
Suggestions
- The
## What you will buildintro section would be stronger as outcome-focused bullets ("what the reader can do after") rather than artefact-focused bullets ("what gets created"), which matches the TLO format used elsewhere in the cookbook. - The new README table row is significantly longer than adjacent entries; trimming the description would match the existing style better.
Positive Notes
- The introduction hook ("they have to repeat themselves, and the experience feels transactional rather than personal") is excellent — it opens with a concrete pain point before introducing the API machinery.
- The
[memory]prefix lines inrun_turnmake otherwise-invisible file I/O visible inline, which is the exact insight the notebook is teaching. - The "How memory works" conceptual section before any code gives readers a mental model first — exactly right for a tutorial.
- The beta feature callout block sets reader expectations appropriately.
- Model ID
claude-sonnet-4-6is the correct non-dated alias per CLAUDE.md. - The registry.yaml entry is correctly formatted with appropriate categories.
- The Summary maps cleanly back to the numbered steps.
- Guard the session.status_idle break on stop_reason.type == "end_turn" so the pattern is safe to copy into custom-tool agents - Import wait_for_idle_status from utilities and call it before each sessions.archive() to absorb the SSE-vs-status race - Use environments.archive instead of environments.delete - Define MODEL via the COOKBOOK_MODEL env var like the other CMA notebooks and pass it to agents.create - Seed cell: capture the return, print the seeded path, and note that it must run before the cleanup cell that deletes the store https://claude.ai/code/session_01VkfVPdiJTWVh6Vj5owqRXH
Notebook ChangesThis PR modifies the following notebooks: 📓
|
There was a problem hiding this comment.
PR Review
Recommendation: REQUEST_CHANGES
Summary
Adds a well-structured memory stores cookbook showing a shopping agent that learns and recalls customer preferences across sessions. The narrative flow and API usage are sound, but the run_turn streaming helper has robustness gaps that need fixing before merge.
Actionable Feedback (7 items)
Blocking
-
CMA_remember_user_preferences.ipynb(in cell withdef run_turn) — Nosession.status_terminatedguard: if a session terminates unexpectedly the event loop will spin indefinitely. Every other CMA notebook's streaming loop includeselif event.type == "session.status_terminated": break. Add the same guard here. -
CMA_remember_user_preferences.ipynb(in cell withdef run_turn) — The helper returns without callingwait_for_idle_status. The cleanup cell compensates by calling it manually, but any reader who adaptsrun_turnand immediately callsarchive()will hit a 400 "cannot archive while running" race. Either callwait_for_idle_status(client, session_id)before returning, or add an inline comment explaining why the cleanup cell handles it externally. -
CMA_remember_user_preferences.ipynb(in cell withdef run_turn) — Norequires_action/ non-end_turnstop guard: the loop only breaks onstop_reason.type == "end_turn". Any other idle reason leaves the stream open indefinitely. A safe fallback iselif event.type == "session.status_idle": breakthat exits on any idle, plus a comment noting the helper is only safe when the agent has no custom tools.
Important
-
CMA_remember_user_preferences.ipynb(in cell withseeded = client.beta.memory_stores.memories.create(...)) — The seeding cell runs after both sessions have already completed, so the seeded purchase history has no visible effect on any notebook output. Either move the seeding step before session one (making the demo richer) or add prose explicitly noting that in a real application seeding would happen before the first session — and explain why the example is placed here. -
CMA_remember_user_preferences.ipynb(in cell withseeded = client.beta.memory_stores.memories.create(...)) — The saved cell output is empty ([]) despite containingprint(f"Seeded {seeded.path}"). Per the repo convention of keeping outputs for demonstration, this looks like a failed or un-run cell. Re-execute and commit the output (Seeded /purchase-history.md), or remove the print. -
CMA_remember_user_preferences.ipynb(in cell withagent = client.beta.agents.create(...)) —agent_toolset_20260401is missingdefault_config/permission_policy. All other CMA series notebooks that use this toolset include"default_config": {"enabled": True, "permission_policy": {"type": "always_allow"}}. Add it for consistency and to make the required config explicit for readers. -
CMA_remember_user_preferences.ipynb(in cell withenvironment = client.beta.environments.create(...)) —environments.createomitsconfig(networking type). All other CMA series notebooks pass an explicitconfig={"type": "cloud", "networking": {"type": "..."}}. Add the config to match series conventions and clarify the networking policy.
Detailed Review
Code Quality
The notebook structure is clean and the step-by-step prose before each cell is well-calibrated — each explanation answers "why this call, why now" rather than just narrating the code. The stream-open-before-send ordering is correct (the with block opens the SSE connection before events.send), which is a common footgun the notebook avoids correctly.
The run_turn helper diverges from the series utility stream_until_end_turn without explanation. Since this notebook has no custom tools, delegating to stream_until_end_turn (with thin wrapper for the [memory] logging) would be cleaner and would inherit the series' error handling for free. If the inline loop is intentional for pedagogy, a comment should say so.
Security
No concerns — no secrets, keys, or sensitive data. ANTHROPIC_API_KEY is loaded from the environment correctly via the SDK default.
Suggestions
memory_resourcedict is reused across both sessions with only a# same store, new sessioncomment. A brief note that the dict is a value object andstore.idis captured at construction time would address the implied shared-state question.- The README.md table entry is noticeably longer than all other rows. Consider a shorter description in the table and a prose detail paragraph below.
- The
registry.yamlentry usesAgent PatternsandTools— worth checking whether other CMA entries use aManaged Agentscategory tag for better discoverability.
Positive Notes
- Introduction follows the problem-first structure perfectly: user pain → solution → learning objectives.
- The "How memory works" callout and beta-feature disclaimer are exactly right for an API-in-preview feature.
MODELconstant uses the non-dated aliasclaude-sonnet-4-6withCOOKBOOK_MODELenv override — correct per CLAUDE.md.- "Going further" section (seeding, combining stores, auditing) provides genuinely useful production patterns.
wait_for_idle_statususage in the cleanup cell is correct and consistent with the series.- The summary cell maps back to all stated learning objectives — closes the pedagogical loop correctly.
- run_turn: handle session.status_terminated and call wait_for_idle_status before returning, mirroring utilities.stream_until_end_turn; drop the now-redundant wait_for_idle_status calls from the cleanup cell - environments.create: pass an explicit cloud/limited config - agent_toolset_20260401: include the default_config block with permission_policy always_allow, matching every other CMA notebook - Seed section: explain that production seeding happens before any sessions, and add the cell's stdout so it doesn't look un-run Not changed: the end_turn-guarded idle break stays as-is. Reverting it to an unconditional break would undo the previous round's fix and diverge from utilities.stream_until_end_turn. https://claude.ai/code/session_01VkfVPdiJTWVh6Vj5owqRXH
|
Addressed 6 of the 7 review items in 6c32b29. Intentionally not changing the Generated by Claude Code |
Notebook ChangesThis PR modifies the following notebooks: 📓
|
There was a problem hiding this comment.
PR Review
Recommendation: REQUEST_CHANGES
Summary
This notebook introduces memory stores for Claude Managed Agents through a well-paced, narrative-driven shopping assistant tutorial. The prose, code quality, and pedagogy are strong. Two issues diverge from established series conventions and should be fixed before merging.
Actionable Feedback (4 items)
-
CMA_remember_user_preferences.ipynb(in cells withsession_one = client.beta.sessions.create(...)andsession_two = client.beta.sessions.create(...)) — Pass a pinned agent version dict instead of the bare stringagent.id. Every other CMA notebook usesagent={"type": "agent", "id": agent.id, "version": agent.version}to prevent sessions from silently picking up prompt changes if the agent is updated concurrently. This is a correctness concern for readers copying the pattern into production. -
CMA_remember_user_preferences.ipynb(in cell withdef run_turn(session_id: str, user_text: str) -> str:) — The event loop onlybreaks whenstop_reason.type == "end_turn". If the session idles withstop_reason.type == "requires_action"(possible withagent_toolsetin edge cases), the loop never exits and the stream blocks until a server-side timeout. Either handle therequires_actioncase explicitly or add a comment explaining the limitation, so readers who copy this helper into their own code aren't surprised. -
CMA_remember_user_preferences.ipynb(in cell withdef run_turn(session_id: str, user_text: str) -> str:) — The return value ("".join(reply_parts)) is never used at either call site. Either assign it in one of the example calls (e.g.,reply = run_turn(...)) to show readers it is capturable, or change the return type toNoneto remove the confusion. -
CMA_remember_user_preferences.ipynb(cleanup cell withclient.beta.memory_stores.delete(store.id)) — All other CMA notebooks usearchive()for cleanup. Ifdelete()is correct for memory stores (noarchivemethod exists), add a one-line comment explaining why memory stores usedeletewhile sessions/agents/environments usearchive, to avoid reader confusion.
Detailed Review
Code Quality
The Python is clean and idiomatic. run_turn uses modern list[str] annotation, opens the stream before sending (matching the canonical pattern in CMA_iterate_fix_failing_tests.ipynb), and clearly surfaces memory tool calls. The event.input.get("file_path") or event.input.get("command", "") idiom is slightly surprising — an empty file_path string would fall through to command — but this is unlikely in practice with the memory toolset.
The seeding cell has a useful comment noting it should run before cleanup, but the ordering could be made even clearer by adding a reminder in the cleanup cell's markdown header.
Security
No issues. client = Anthropic() picks up ANTHROPIC_API_KEY from the environment correctly. No credentials are hardcoded.
Model IDs
MODEL = os.environ.get("COOKBOOK_MODEL", "claude-sonnet-4-6") uses the correct non-dated alias. The agent_toolset_20260401 string is correctly identified in the prose as an API toolset identifier, not a model alias.
Suggestions
- The "Going further: patterns for production" section is well-placed but the Summary at the end doesn't mention the multi-store pattern — a brief reference there would help readers who skim to the bottom.
- The README table entry accurately describes the notebook. A brief note that this is the only CMA notebook covering the Memory API surface would help readers scanning the table.
Positive Notes
- The introduction hooks immediately on real user pain (agents that forget) and the "What you will build" bullets are concrete and honest.
- The
[memory]lines surfaced inrun_turnoutput make memory I/O visible without cluttering the helper — excellent pedagogy. - The "In a real application you would run this seeding step before any sessions are created; it appears here, after the demo, only so the main learn-then-recall flow above stays focused" comment in the seeding cell is exactly the right thing to say and models good notebook authorship.
- Registry entry follows the established format;
gaganb-antis already inauthors.yaml.
…ookbook
Pass agent={"type": "agent", "id": agent.id, "version": agent.version}
instead of the bare agent.id, matching every other notebook in the
managed_agents series.
https://claude.ai/code/session_01VkfVPdiJTWVh6Vj5owqRXH
Notebook ChangesThis PR modifies the following notebooks: 📓
|
There was a problem hiding this comment.
PR Review
Recommendation: REQUEST_CHANGES
Summary
This notebook adds a well-structured shopping agent demo that demonstrates the Claude Managed Agents Memory Store feature. The run-to-completion flow is solid, resources are correctly cleaned up, and the model ID usage is correct. One inconsistency in a code snippet needs fixing before merge.
Actionable Feedback (1 item)
-
CMA_remember_user_preferences.ipynb(in the "Combine per-customer and shared stores" markdown cell) — The code snippet usesagent=agent.id(a plain string), but every runnable cell in this notebook uses the dict formagent={"type": "agent", "id": agent.id, "version": agent.version}. A reader copy-pasting this "production" pattern would silently get the latest agent version rather than a pinned one — the exact footgun thatCMA_prompt_versioning_and_rollback.ipynbwarns against. Change to the dict form to stay consistent.
Detailed Review
Code Quality
The cell flow is clean: every variable (store, environment, agent, memory_resource, session_one, session_two) is defined before it is used. A clean top-to-bottom run produces no undefined-variable errors. The run_turn helper is readable and correctly mirrors the event-loop pattern established in earlier CMA notebooks.
The seeding cell in "Going further" appears after both session demos, so neither demonstrated session ever sees the seeded file. The surrounding comment (# Run before the cleanup cell below) acknowledges only the cleanup ordering, not that the seeding has no visible effect on the sessions shown. A brief prose note that a third session would be needed to observe the seeded data would close the pedagogical gap. This is a suggestion, not a blocker.
Security
No secrets or API keys appear anywhere in the notebook source or saved outputs. No credentials are logged. Clean.
Suggestions
- The
run_turnstream loop exits silently if neithersession.status_idlenorsession.status_terminatedfires before the stream closes (e.g., on a network drop). The returned string may be partial with no indication of the failure. This matches the pattern in the sharedutilities.py, so it is consistent with the series — but a one-line comment noting the partial-response risk would help readers adapting this for production. event.input.get("file_path") or event.input.get("command", "")falls back to""for non-memory tools, which the guard then correctly suppresses. A short inline comment would make the intentional suppression of non-memory tool calls explicit.
Positive Notes
claude-sonnet-4-6(non-dated alias) is used via theCOOKBOOK_MODELenv var with fallback — correct per CLAUDE.md.- Both runnable
sessions.createcalls correctly passagent={"type": "agent", "id": agent.id, "version": agent.version}. - Cleanup cell archives all five resources (
session_one,session_two,store,agent,environment) — no leaks. - The beta callout in the introduction is exactly right: it flags the feature as public beta and notes that the SDK handles the required header automatically.
- README table entry and
registry.yamladdition are well-formed and consistent with existing entries. - Notebook outputs are retained, consistent with the repo convention for demo notebooks.
The illustrative markdown snippet under "Combine per-customer and shared stores" still passed agent=agent.id while the runnable cells were already using the pinned dict form. Align the snippet so readers copying the production pattern get the same version-pinned shape. https://claude.ai/code/session_01VkfVPdiJTWVh6Vj5owqRXH
Notebook ChangesThis PR modifies the following notebooks: 📓
|
Model Check Results ✅Files reviewed: Findings
SummaryNo model issues found. The notebook uses
🤖 Generated with Claude Code |
There was a problem hiding this comment.
PR Review
Recommendation: REQUEST_CHANGES
Summary
Adds a well-structured memory stores tutorial for Claude Managed Agents, showing a shopping assistant that learns customer preferences in one session and recalls them in the next. The notebook is clear and educationally sound, but two code correctness issues need to be fixed before merging.
Actionable Feedback (6 items)
-
CMA_remember_user_preferences.ipynb(cleanup cell) — Addwait_for_idle_statuscalls before botharchivecalls, matching the series pattern. The current code could cause a400error if copied closer in time to the lastrun_turn. Example fix:wait_for_idle_status(client, session_one.id) wait_for_idle_status(client, session_two.id) client.beta.sessions.archive(session_one.id) client.beta.sessions.archive(session_two.id) ...
-
CMA_remember_user_preferences.ipynb(in cell withdef run_turn) — Thesession.status_idlehandler only breaks onend_turn; any other stop reason (e.g.requires_action) silently continues the loop indefinitely. Add a comment (or anelse: break) explaining the intent, asCMA_gate_human_in_the_loop.ipynbdoes for the same pattern. -
CMA_remember_user_preferences.ipynb(in cell withtarget = event.input.get) — Guard againstevent.inputbeingNone:inp = event.input or {}; target = inp.get("file_path") or inp.get("command", ""). -
CMA_remember_user_preferences.ipynb(seeding cell) — Convert the inline comment# Run before the cleanup cell belowto a markdown> **Note:**callout before the cell so it's more visible in notebook rendering. -
CMA_remember_user_preferences.ipynb— Add a%%capture\n%pip install -q "anthropic>=0.91.0"cell before the imports, matching the pattern in other CMA notebooks that require a minimum SDK version for beta API surfaces. -
CMA_remember_user_preferences.ipynb(Summary cell) — Add pointers to sibling CMA notebooks (e.g.CMA_iterate_fix_failing_tests.ipynbas the series entry point,CMA_operate_in_production.ipynbfor production patterns) — every other CMA tutorial does this.
Detailed Review
Code Quality
The run_turn helper correctly uses the "open stream first, then send" ordering that the series establishes as the canonical pattern, and the memory-specific [memory] surface logging is a nice touch that makes the notebook's core mechanic visible without being noisy. The memory_resource dict is appropriately defined once and reused for session_two, teaching the reuse pattern rather than hiding it.
The two blocking issues are:
- Missing
wait_for_idle_statusin cleanup — Every other CMA notebook places explicit idle waits beforearchivecalls. This notebook skips them. In a live demo it's unlikely to fail because session_one went idle many cells earlier, but as a copy-paste pattern it is dangerous. - Partial
session.status_idlehandling — Theif stop_reason.type == "end_turn": breakbranch is correct, but if any other idle reason arrives the stream loop hangs silently. A comment or else branch is needed.
Security
No secrets hardcoded. client = Anthropic() reads ANTHROPIC_API_KEY from the environment correctly. No injection risks.
Suggestions
- dotenv: The other standalone CMA tutorials (
CMA_prompt_versioning_and_rollback.ipynb) include aload_dotenv()call for readers with a.envfile. The five earlier CMA series notebooks don't use it either, so this is consistent within the series — but inconsistent with CLAUDE.md guidance. Worth a deliberate choice. - Cross-notebook links in Summary: Every other CMA tutorial links to siblings. Adding a "See also" list would help readers navigate the series.
- The
agent_toolset_20260401note ("not a model alias, so you don't need to update it when newer models ship") is an excellent call-out that other notebooks don't have.
Positive Notes
- Model ID is
claude-sonnet-4-6(non-dated alias) withCOOKBOOK_MODELenv override — exactly correct per CLAUDE.md. - Beta feature callout block at the top is clear and appropriately scoped.
- Cleanup cell covers all five created resources (session_one, session_two, store, agent, environment) — nothing is orphaned.
- Registry and README entries are both present, correctly formatted, and consistent with other CMA entries.
- Cell outputs are preserved per project convention.
- Add wait_for_idle_status calls before session archive in cleanup - Break out of run_turn on any status_idle, not just end_turn - Guard event.input against None in tool_use handler - Move seeding-order warning to a markdown Note callout - Add %pip install cell for minimum SDK version - Link to sibling CMA notebooks from the summary
Notebook ChangesThis PR modifies the following notebooks: 📓
|
There was a problem hiding this comment.
PR Review
Recommendation: COMMENT
Summary
Adds a well-structured memory store tutorial showing a shopping agent that learns customer preferences in one session and recalls them in the next. The core flow, API usage, cleanup, and registry entries are all correct.
Actionable Feedback (4 items)
-
CMA_remember_user_preferences.ipynb(in cell withdef run_turn(session_id: str, user_text: str)) — Thesession.status_idlehandler has dead code: both theif event.stop_reason and event.stop_reason.type == "end_turn": breakbranch and the barebreakdo the same thing. The comment implies two distinct behaviors but only one exists. Simplify to a single unconditionalbreakwith a comment explaining why:# Break on any idle reason to prevent unexpected stop_reason from hanging the loop. -
CMA_remember_user_preferences.ipynb(in cell with# Optional: "Seed a store from your existing data") — The warning about running the seeding cell before cleanup is easy to miss in markdown. Add a# Optional: run before the cleanup cellcomment directly in the code cell source so it's visible even when markdown is collapsed. -
CMA_remember_user_preferences.ipynb(in markdown cell withcatalog = client.beta.memory_stores.create(...)snippet) — The "Combine per-customer and shared stores" snippet creates acatalogstore but doesn't show cleanup. Readers who run this verbatim will leak a resource. Add a commented cleanup line:# client.beta.memory_stores.delete(catalog.id) -
CMA_remember_user_preferences.ipynb(in cell withdef run_turn) — The return value (-> str) is never used by either call site. Either drop the accumulation and annotate-> None, or note in the docstring that the return value is available for callers who want the reply programmatically.
Detailed Review
Code Quality
The notebook follows the CMA series conventions closely. The [memory] prefix in run_turn that surfaces file reads/writes is an excellent pedagogical choice — it makes the agent's internal behavior visible without requiring readers to understand the full event structure. The wait_for_idle_status calls are placed correctly both inside run_turn and at the top of the cleanup cell.
The dead branch in the session.status_idle handler is the main code quality issue. Compared to utilities.py and CMA_iterate_fix_failing_tests.ipynb which only break on end_turn, this notebook breaks on any idle reason — which is a valid deliberate choice, but the dual-branch structure obscures that intent. A single break with a clear comment would be cleaner.
Security
No issues. No hardcoded keys. API key is picked up via Anthropic() from the environment, consistent with the rest of the CMA series (which doesn't use dotenv — this is an accepted convention for this sub-series given the prerequisites cell says to set ANTHROPIC_API_KEY as an environment variable).
Suggestions
- The cleanup cell correctly tears down all five resources (both sessions, the memory store, the agent, and the environment) in the right order — good.
agent.versionpinning on allsessions.createcalls (including the markdown snippet) is consistent with the series and prevents silent prompt drift.- Model ID
claude-sonnet-4-6is the correct non-dated alias perCLAUDE.md. registry.yamlandREADME.mdentries are accurate and concise.
Positive Notes
The problem framing in the introduction is strong — it opens with the concrete customer pain ("the agent has forgotten everything") before introducing the solution. The step numbering (Steps 1–5) creates a clear narrative arc, and the "Going further" section appropriately separates the core demo from production patterns without cluttering the main flow.
- Simplify status_idle handler to a single unconditional break - Document run_turn return value in the docstring - Restore inline 'Optional: run before cleanup' hint in the seeding cell - Add catalog store cleanup reminder to the combine-stores snippet - Tighten registry description and intro phrasing
Notebook ChangesThis PR modifies the following notebooks: 📓
|
There was a problem hiding this comment.
PR Review
Recommendation: REQUEST_CHANGES
Summary
This PR adds a well-structured memory store cookbook for Claude Managed Agents, demonstrating how a shopping agent learns user preferences in one session and recalls them in the next. The two-session demo is effective and the prose is clear, but two blocking issues should be resolved before merging.
Actionable Feedback (6 items)
Blocking:
-
CMA_remember_user_preferences.ipynb(in cell withdef run_turn() — The stream loop breaks on anysession.status_idleevent regardless ofstop_reason. The comment claims this prevents hangs, but it actually silently swallowsrequires_actionidle events and leaves the session in an unresolved state. Since readers will copy this pattern, add a guard:if event.stop_reason and event.stop_reason.type != "end_turn": raise RuntimeError(...), or explicitly note in the comment that this helper must not be used with custom-tool agents. -
CMA_remember_user_preferences.ipynb(setup cell withclient = Anthropic()) — Missingdotenv.load_dotenv()before constructing the client. The most recent peer notebook (CMA_prompt_versioning_and_rollback) addedpython-dotenvandload_dotenv(). Please follow that pattern here.
Important:
-
CMA_remember_user_preferences.ipynb(intro cell) — The "What you will build" section describes artifacts, not skills. Replace with**By the end of this guide, you'll be able to:**learning objectives per the cookbook template. -
CMA_remember_user_preferences.ipynb(seeding cell in "Going further") — The seeding cell runs after both sessions complete and is immediately followed by cleanup, so the write produces no observable outcome. Either add a briefrun_turncall after seeding to show the agent using the pre-seeded data, or restructure so seeding happens before the first session.
Suggestions:
-
CMA_remember_user_preferences.ipynb("Going further" / Combine stores snippet) — Thecatalogstore created in the illustrative snippet is never deleted by the cleanup cell. The commented-out cleanup line is easy to miss; add a prose callout below the block: "If you run this snippet, delete the catalog store separately withclient.beta.memory_stores.delete(catalog.id)— it is not included in the cleanup cell below." -
CMA_remember_user_preferences.ipynb(Step 4memory_stores.memories.listcall) — Add one sentence explaining what the default (noview="full") returns, so readers know when they can omit the parameter in production.
Detailed Review
Code Quality
The run_turn helper is well type-annotated and its inline comments explain why each event branch exists. All three sessions.create calls correctly pin agent.version, including the one inside the "Combine stores" markdown snippet — good attention to detail. The %%capture magic on the pip install cell follows project convention. The cleanup cell is complete and correctly calls wait_for_idle_status before archiving.
Security
No secrets or hardcoded credentials. Anthropic() reads from the environment as expected. The only concern is the missing load_dotenv() call (see blocking item above).
Suggestions
- The
run_turnhelper prints each streamingagent.messageblock as it arrives, which can produce fragmented output during a live run. Other series notebooks accumulate the full reply or useend="". Not blocking, but worth aligning. - Consider adding a parenthetical to the Summary section noting that the webhook fires
session.status_idledwhile the SSE stream emitssession.status_idle, to prevent confusion for readers who work with both patterns. - The
view="full"parameter description would benefit from one sentence explaining what the default view omits (metadata-only vs. full content).
Positive Notes
- The problem hook is strong — opening with the "starts from scratch" pain point grounds the reader immediately.
- The two-session structure is the right pedagogical choice: the memory effect is demonstrated rather than described.
managed_agents/README.mdrow is well-formatted and accurate.registry.yamlentry is correct;gaganb-antexists inauthors.yaml.- The beta-feature callout in the intro cell is well-placed and accurate.
- Rebase onto current main (resolves DIRTY merge state from PRs anthropics#573, anthropics#595) - Re-execute notebook end-to-end against live XPOZ MCP + Claude Sonnet 4.6 (804 posts sampled across Twitter/Reddit/Instagram, structured analysis committed as cell outputs per CONTRIBUTING.md guidance) - ruff check + ruff format clean (sorted imports, formatted code) - authors.yaml sorted alphabetically (validate_authors_sorted.py passes) - registry.yaml description: 'analyse' -> 'analyze' (US English)
- Rebase onto current main (resolves DIRTY merge state from PRs anthropics#573, anthropics#595) - Re-execute notebook end-to-end against live XPOZ MCP + Claude Sonnet 4.6 (804 posts sampled across Twitter/Reddit/Instagram, structured analysis committed as cell outputs per CONTRIBUTING.md guidance) - ruff check + ruff format clean (sorted imports, formatted code) - authors.yaml sorted alphabetically (validate_authors_sorted.py passes) - registry.yaml description: 'analyse' -> 'analyze' (US English)
Build agents that remember your users
Adds a guided tutorial to
managed_agents/showing how to give a Managed Agent a memory store so it learns and recalls a customer's shopping preferences across separate sessions.Checkout the full notebook preview here.