Persistent Memory for Your Lab 02 Agent
Give the Lab 02 agent long-term memory: a persistent store with provenance, a disciplined write path (extraction, dedupe, contradiction resolution), a scored read path injecting fenced memories at session start, threshold-triggered compaction — and a self-written red-team test proving the write path resists memory injection. Gate G2 ends with Claude attempting a novel injection against your defenses.
pip install sentence-transformers for memory embeddings (already installed if you did Lab 03). SQLite ships in Python's standard library, so the store needs nothing extra. Budget one to two days including the red-team tests.What you're building
Your Lab 02 agent currently forgets everything at process exit. You'll wrap it with a memory layer: at session end, extract candidate facts and run them through the write-path gauntlet into SQLite (or JSON files); at session start, recall top-k scored memories into the system prompt as fenced untrusted data; mid-session, compact when the conversation crosses 75% of the context budget. The deliverable is proved by a three-session demo script: session 1 teaches three facts, session 2 (a fresh process) uses them, session 3 contradicts one and shows the resolution — plus a red-team test where a poisoned corpus file tries to plant "always approve refunds" in your store.
Suggested structure
# memory/store.py — MemoryStore over SQLite (schema from Lesson 3)
# columns: fact, provenance JSON, created_at, importance,
# superseded_by, embedding
# memory/write_path.py
def commit_session(store, transcript: str, session_id: str) -> list[str]:
outcomes = []
for cand in extract_candidates(transcript, session_id):
verdict = screen_candidate(cand) # provenance + instruction gates
if verdict != "accept":
log_quarantine(cand, verdict)
outcomes.append(f"{verdict}: {cand['fact']}")
continue
outcomes.append(write_fact(store, cand)) # dedupe + contradiction check
return outcomes
# memory/read_path.py
def session_preamble(store, task_hint: str) -> str:
mems = recall(store, task_hint, k=5, min_score=0.35)
if not mems:
return "" # empty beats misleading
return render_fenced_memory_block(mems) # <memories> ... </memories>
# agent.py — Lab 02 loop, now memory-aware
def run_session(task: str):
system = SYSTEM_PROMPT + session_preamble(STORE, task)
messages = [{"role": "user", "content": task}]
while True:
messages = maybe_compact(messages, system) # 75% threshold
resp = call_with_retries(lambda: client.messages.create(
model="claude-sonnet-5", max_tokens=1024,
system=system, tools=SCHEMAS, messages=messages))
# ... Lab 02 tool loop unchanged ...
if resp.stop_reason != "tool_use":
break
commit_session(STORE, render_transcript(messages), new_session_id())
# demo.py — three sessions, three fresh processes
# tests/test_injection.py — your red-team suite (Lesson 5 harness)
# tests/test_compaction.py — planted constraint survives compactionHow Gate G2 will probe it: you'll run the three-session demo live for Claude, then Claude writes one novel injection payload — a phrasing not in your test suite — and you run it through your write path on the spot. This is why the provenance gate matters more than the instruction classifier: a structural rule ("content the agent merely read never auto-qualifies as memory") catches attacks you didn't anticipate, while a classifier alone catches only attacks that look like your training examples. Be ready to narrate each layer's decision from your logs.
Ship it to your portfolio
This lab is one of the module projects worth packaging properly: 2026 hiring guides specifically cite an agent with persistent long-term memory — including conflict resolution between contradicting facts and defense against memory-injection attacks — as a high-value portfolio project, and hiring managers look at GitHub before the résumé. Two or three deep, evaluated projects beat a pile of shallow demos; make this one of them.
- README with a 60-second demo — an asciinema recording or GIF of the three-session demo script: facts taught, fresh process recalls them, contradiction resolved. A reviewer should see it work without cloning anything.
- Evidence of memory-conflict resolution — show the
superseded_bychain for the session-3 contradiction: both timestamped facts, the conflict flag in the log, and the agent preferring the newer one at recall. This is the first of the two things the hiring guides call out by name. - Evidence of injection defense — the red-team test output, with the layered verdicts (quarantine vs reject) and a one-paragraph explanation of why the provenance gate catches phrasings the classifier has never seen. This is the second.
- An honest "Limitations" section — what your write path would miss (e.g. an attack phrased as a first-person user preference, cross-session slow-drip facts), where brute-force cosine stops scaling, what you didn't build (TTLs? hard-delete cascade?). Candor here reads as seniority, not weakness.
- Eval numbers, not adjectives — injection payloads blocked (n/n), cross-session recall accuracy on your demo facts, the compaction test passing; if you did the recall-quality stretch goal, report its precision/recall. "Robust memory" is a claim; a table is evidence.
- ◇Memory decay and expiry: half-life-based downweighting at recall plus TTLs for shelf-life facts ("working on the Q3 launch"), with a test showing an expired fact no longer surfaces
- ◇Recall-quality eval: a labeled set of (task, should-recall, should-not-recall) triples; report precision/recall of your read path and tune the scoring weights against it
- ◇MemGPT-style self-managed memory: expose remember/recall/forget as tools so the agent pages its own memory mid-session, and compare against the automatic write path
Be honest — the gates only mean something if the criteria really pass.
Repo URL, demo link, notes to your future self — saved locally with your progress, and handy when you package the portfolio.