01

Memory Is Not Context

Build durable, inspectable facts for Maya before adding any memory framework.

Start with three different things

A support agent that forgets Maya's accessibility preference repeats work; one that mixes it into every chat can leak it to another customer. Context is text supplied to one model call, thread state belongs to one conversation, and durable memory is a record deliberately retained for later work.

Use this boundary: a prompt may contain the last messages; a thread can preserve unfinished work; durable memory holds a fact such as “Maya prefers email summaries.” Neither an earlier chat nor a model's hidden state is durable memory you control.

LayerLifetimeGood forBad for
Context windowOne requestCurrent question, retrieved factsReliable retention
Thread/checkpointOne conversationResume interrupted workCross-thread preference
Durable memoryChosen lifecycleStable user facts, approved playbooksUnreviewed chain-of-thought

Write smallest trustworthy record

Memory needs ownership before search, because an unowned fact cannot be safely retrieved or erased. Start with an explicit SQLite record: Maya's tenant and user identifiers are part of every key, while source and expiry make the record auditable.

import sqlite3

db = sqlite3.connect("support.db")
db.execute("""
CREATE TABLE IF NOT EXISTS memories (
  tenant_id TEXT NOT NULL,
  user_id TEXT NOT NULL,
  memory_id TEXT PRIMARY KEY,
  fact TEXT NOT NULL,
  source TEXT NOT NULL,
  expires_at TEXT
)
""")
db.execute(
  "INSERT INTO memories VALUES (?, ?, ?, ?, ?, ?)",
  ("acme", "maya", "m_1", "Maya prefers email summaries", "user stated", None),
)
db.commit()

This is durable only because support.db survives process restart. It is not semantic search yet; it is the control case Days 02–04 will compare against.

Retrieve within tenant boundary

A correct-looking memory result is harmful if it came from another tenant. Retrieval must filter ownership in the database query, not after a model sees the text.

def facts_for_user(db, tenant_id: str, user_id: str):
    return db.execute(
        "SELECT fact FROM memories WHERE tenant_id = ? AND user_id = ?",
        (tenant_id, user_id),
    ).fetchall()

assert facts_for_user(db, "acme", "maya") == [("Maya prefers email summaries",)]
assert facts_for_user(db, "other-tenant", "maya") == []

Positive evidence is Maya's preference. Denial evidence is the empty second query. Add authorization before this call in production; identifiers alone are not identity proof.

Decide what deserves retention

Storing every message creates stale, sensitive, and contradictory state. Retain only a fact with a future use, a clear owner, and a deletion rule; keep raw transcripts under separate retention policy.

KeepDo not keep
User-stated preference with sourcePasswords, access tokens, payment data
Confirmed account constraintTemporary model speculation
Approved team procedurePrivate data from another tenant

Official SQLite documentation explains its embedded-database trade-offs. Day 02 consumes tenant_id, user_id, and Maya's explicit fact to add semantic retrieval without losing those boundaries.