Code with Claude 2026 · Workshop W3 · 45 min
Sample code. Not maintained and not accepting contributions.
Arc: Problem (amnesiac agent) → CMA Memory (live store) → Dreaming (consolidate past transcripts). "Goldfish to colleague in 45 minutes."
Your agent forgot what you told it thirty seconds ago. We start with a Managed Agent that's visibly amnesiac across sessions, then layer in memory primitives one at a time: a memory store for cross-session persistence, and the Dreaming Service so it improves from its own transcripts. You'll leave knowing exactly which lever to reach for when your own agent forgets.
- Clone, add your API key.
git clone <this-repo>
cd cwc-workshops/agents-that-remember
cp .env.example .env # open .env and add your ANTHROPIC_API_KEY- Wait for your organization to be added to the research preview.
IMPORTANT: You must be opted into the research preview for the below step.
- Run the bootstrap script.
./scripts/bootstrap.sh
source .bootstrap-vars # sets PATH, AGENT, ENV, HIST1/2/3The script downloads the preview ant CLI to ./ant, then creates (or
reuses) an agent, an environment, and three seeded historical
sessions in your workspace. It writes the IDs to .bootstrap-vars — load
them.
- Open https://platform.claude.com/ (Console) alongside your terminal — you'll use both throughout.
Idempotent: re-running the script skips the CLI download if
./antexists and reuses agent/env by name; only new history sessions are added. If the script fails, the underlying commands are inscripts/bootstrap.sh— run them one at a time.
What this shows: without a memory store, each session is a silo. Something told in one session is gone in the next.
SES_A=$(ant beta:sessions create --agent "$AGENT" --environment-id "$ENV" \
--title "Write test (no memory)" --format json | jq -r .id)
# Terminal 2 — live-tail the agent's responses (SSE stream of events)
ant beta:sessions:events stream --session-id "$SES_A" --max-items -1 --format pretty
# Terminal 1 — tell it what you attended
ant beta:sessions:events send --session-id "$SES_A" \
--event '{"type":"user.message","content":[{"type":"text","text":"I attended the CMA talk yesterday at noon — I learned that multi-agent orchestration, outcomes, memory are launching, and dreaming is launching to research preview. I took notes and uploaded them to https://example.com/notes/cma."}]}'- Navigate to https://platform.claude.com/workspaces/\<workspace>/sessions
- Create a session using the agent and env the script created:
- Title: Write test (no memory)
- Agent: cwc-agent
- Env: cwc-env
- Tell it information about your CwC experience. For example: "I attended the CMA talk yesterday at noon — I learned that multi-agent orchestration, outcomes, memory are launching, and dreaming is launching to research preview. I took notes and uploaded them to https://example.com/notes/cma."
SES_B=$(ant beta:sessions create --agent "$AGENT" --environment-id "$ENV" \
--title "Recall test (no memory)" --format json | jq -r .id)
ant beta:sessions:events stream --session-id "$SES_B" --max-items -1 --format pretty
ant beta:sessions:events send --session-id "$SES_B" \
--event '{"type":"user.message","content":[{"type":"text","text":"What features did they announce at the CMA talk? Give me the go link for my notes."}]}'- Navigate to https://platform.claude.com/workspaces/\<workspace>/sessions
- Create a session using the agent and env the script created:
- Title: Recall test (no memory)
- Agent: cwc-agent
- Env: cwc-env
- Ask it a question about the previous sessions e.g.: "What features did they announce at the CMA talk? Give me the go link for my notes."
Talking point: sessions are isolated by design — nothing persists. This is the "goldfish" baseline.
What this shows: a memory store is a persistent filesystem-like store the agent can read from and write to across sessions. Attaching the same store to two sessions gives them shared memory.
MEM=$(ant beta:memory-stores create --name "cwc-memory" \
--description "My CwC attendance and resources" --format json | jq -r .id)
echo "MEM=$MEM"- Navigate to https://platform.claude.com/workspaces/\<workspace>/memory-stores
- Press New Memory Store and fill in:
- Name: cwc-memory
- Description: My CwC attendance and resources
- Search by
$MEM(or the name "cwc-memory") to view
What this does: the --resource '{"type":"memory_store",...}' flag mounts
the store into each session's container. Same $AGENT and $ENV as before —
only the session is new. The resource object also takes optional prompt and
access fields: prompt is injected into the system prompt to steer how
the agent uses the store (when to read, what to write, how to organize it).
This is the lever you'll iterate on.
MEM_RESOURCE='{"type":"memory_store","memory_store_id":"'"$MEM"'","prompt":"Track which CwC sessions I have attended, resource links I mention, and anything I flag to follow up on.","access":"read_write"}'
SES_C=$(ant beta:sessions create --agent "$AGENT" --environment-id "$ENV" \
--title "Attended — CMA talk (with memory)" \
--resource "$MEM_RESOURCE" --format json | jq -r .id)
ant beta:sessions:events send --session-id "$SES_C" \
--event '{"type":"user.message","content":[{"type":"text","text":"I attended the CMA talk yesterday at noon — I learned that multi-agent orchestration, outcomes, memory are launching, and dreaming is launching to research preview. I took notes and uploaded them to https://example.com/notes/cma."}]}'
# wait for the reply (stream it, or open in Console)...
SES_D=$(ant beta:sessions create --agent "$AGENT" --environment-id "$ENV" \
--title "Recall test (with memory)" \
--resource "$MEM_RESOURCE" --format json | jq -r .id)
ant beta:sessions:events send --session-id "$SES_D" \
--event '{"type":"user.message","content":[{"type":"text","text":"What features did they announce at the CMA talk? Give me the go link for my notes."}]}'- Navigate to https://platform.claude.com/workspaces/\<workspace>/sessions
- Create sessions as before, but additionally attach a memory resource:
- Memory store: cwc-memory
- Access: Read & write
- Instructions: Track which CwC sessions I have attended, resource links I mention, and anything I flag to follow up on.
For Session 1, populate:
- Title: Write test (memory)
- Agent: cwc-agent
- Env: cwc-env
- Resource: Attach memory store as written above
Then tell it information about your CwC experience. For example: "I attended the CMA talk yesterday at noon — I learned that multi-agent orchestration, outcomes, memory are launching, and dreaming is launching to research preview. I took notes and uploaded them to https://example.com/notes/cma."
For Session 2, populate:
- Title: Recall test (no memory)
- Agent: cwc-agent
- Env: cwc-env
- Resource: Attach memory store as written above
Then ask it a question about the previous session e.g.: "What features did they announce at the CMA talk? Give me the go link for my notes."
What this does: lists the files/entries the agent wrote, and their full edit history — so you can see what the agent chose to remember and how it organized it.
ant beta:memory-stores:memories list --memory-store-id "$MEM"
ant beta:memory-stores:memory-versions list --memory-store-id "$MEM"Grab a memory_id / memory_version_id from the list output and fetch a single entry (retrieve defaults to --view full, so content is populated):
ant beta:memory-stores:memories retrieve \
--memory-store-id "$MEM" --memory-id <mem_...>
ant beta:memory-stores:memory-versions retrieve \
--memory-store-id "$MEM" --memory-version-id <memver_...>To see everything the CLI can do with memory stores:
ant beta:memory-stores --help # store CRUD: create/retrieve/update/list/delete/archive
ant beta:memory-stores:memories --help # individual memory entries
ant beta:memory-stores:memory-versions --help # edit historyOpen Memory Stores → cwc-memory to browse the file tree and edit timeline.
Check-in: Anything surprising about what Claude decided to write? Try changing the
promptinMEM_RESOURCEand rerunning §2b — does the file structure change?
What this shows: Dreaming is a batch job that reads an existing memory store and past session transcripts, runs a model over them, and writes distilled memories into a new memory store. It turns raw conversation history into structured recall — the agent improves from its own transcripts.
What this does: inputs are what the dream reads from — here, the
existing memory store plus the historical and recent sessions. instructions
is the optional steering prompt — it shapes how the dream organizes what it
extracts. The dream runs asynchronously and produces a new memory store as
output.
DREAM=$(ant beta:dreams create \
--model claude-opus-4-7 \
--input "{\"type\":\"memory_store\",\"memory_store_id\":\"$MEM\"}" \
--input "{\"type\":\"sessions\",\"session_ids\":[\"$HIST1\",\"$HIST2\",\"$HIST3\",\"$SES_C\",\"$SES_D\"]}" \
--instructions "I am attending CwC, and I want to remember what I've learned." \
--format json | jq -r .id)
echo "DREAM=$DREAM"- Navigate to https://platform.claude.com/workspaces/\<workspace>/dreams
- Press Dream to create a dream. To get the session IDs as a comma-separated list to paste in:
echo "$HIST1,$HIST2,$HIST3,$SES_C,$SES_D"or for only historical, if you've been using console to create other sessions:
echo "$HIST1,$HIST2,$HIST3"- Toggle Use custom instructions and enter a steering prompt, for example: "I am attending CwC, and I want to remember what I've learned."
- Navigate to https://platform.claude.com/workspaces/\<workspace>/dreams to see live progress.
What this does: the dream's outputs array contains the new memory store
it wrote. Pull its ID and list what was written — then open it in Console to
compare file organization against your live $MEM.
MEM_OUT=$(ant beta:dreams retrieve --dream-id "$DREAM" --format json \
| jq -r '.outputs[] | select(.type=="memory_store") | .memory_store_id')
echo "MEM_OUT=$MEM_OUT"
ant beta:memory-stores:memories list --memory-store-id "$MEM_OUT"- Follow the link in the dream detail to see the changes the dream made (snapshotted comparison).
- In Memory Stores, compare different outputted memory stores against one another (live comparison).
Check-in: How did Claude reorganize the files compared to the live store? Anything surprising? Try different
--instructionsand rerun. Try creating more sessions with the memory store attached and run dreaming over them - how does dreaming modify the memory? How does this change with instruction changes?
What this does: memory stores attach at session-create time — there's no
in-place swap on a running session. So "replace" means: create the next
session pointing at $MEM_OUT instead of $MEM.
SES_E=$(ant beta:sessions create --agent "$AGENT" --environment-id "$ENV" \
--title "Post-dreaming recall" \
--resource "{\"type\":\"memory_store\",\"memory_store_id\":\"$MEM_OUT\"}" \
--format json | jq -r .id)
ant beta:sessions:events send --session-id "$SES_E" \
--event '{"type":"user.message","content":[{"type":"text","text":"Give me a recap: which sessions have I attended, what resources do I have links for, and what follow-ups did I flag?"}]}'
ant beta:sessions:events stream --session-id "$SES_E" --max-items -1 --format prettyCreate a session as in 2b and input the new memory store.
Talking point: the agent now recalls facts from sessions it never participated in — Dreaming consolidated the historical transcripts into the store it's reading from. Goldfish → colleague.
ant beta:memory-stores archive --memory-store-id "$MEM"- Go to Memory Stores.
- Click on relevant memory store's three dots.
- Archive.
cheap, live ◀────────────────────────────────▶ batch, distilled
SESSION MEMORY STORE DREAMING
isolated context, persistent FS the reads transcripts,
nothing persists agent reads/writes writes a new store —
across sessions consolidated recall
Reach for a memory store when the agent needs to carry state across sessions right now. Reach for Dreaming when you want an agent to reorganize its memory store to make it more effective, or you have additional transcripts you want the agent to remember from.
Point this at your own domain tonight: create a memory store, attach it to your CMA agent, run Dreaming over your last week of sessions. Docs: