Three Kinds of Memory
Smithers memory has three layers, each solving a different problem:| Layer | What it stores | How you access it | When to use it |
|---|---|---|---|
| Working Memory | Key-value facts with optional TTL | getFact / setFact | Config, counters, last-known-good values |
| Message History | Ordered messages per thread | saveMessage / listMessages | Conversation logs, audit trails |
| Semantic Recall | Embedded text searchable by similarity | remember / recall | ”Find past outputs similar to this query” |
Namespaces
Every piece of memory lives in a namespace. A namespace scopes memory so that different workflows, agents, or users do not collide.workflow— scoped to a specific workflow definitionagent— scoped to a specific agent identityuser— scoped to an end userglobal— shared across everything
namespaceToString() helper produces the canonical string form ("workflow:code-review"). All database queries filter by this string, so memory in one namespace never leaks into another.
Working Memory
Working memory stores structured facts as JSON. Each fact has a namespace, a string key, and a JSON value. Optionally, a TTL in milliseconds causes the fact to expire automatically.Message History
Message history records ordered messages in threads. A thread belongs to a namespace and can hold messages from any role (user, assistant, system, tool).Semantic Recall
Semantic recall uses the existing RAG infrastructure (vector store + embedding model) to store and retrieve memory by meaning rather than by key.remember chunks the content, embeds it with the AI SDK’s embedMany(), and upserts the vectors into the same _smithers_vectors table that RAG uses. recall embeds the query with embed(), searches the vector store filtered by namespace, and returns ranked results.
Task Integration
Thememory prop on <Task> connects memory to the execution flow. Before the agent runs, recalled context is prepended to the prompt. After the agent finishes, output is stored.
memory.recall— before the agent call, query semantic memory and prepend the top results as contextmemory.remember— after the agent call, store the output in both working memory (under the given key) and semantic memory
Loop Memory
Ralph (Loop) can use memory to carry context across iterations. WhenrecallPreviousRuns is enabled, each iteration recalls what happened in previous iterations via semantic search.
Processors
Memory processors run maintenance operations on stored data:- TtlGarbageCollector — deletes expired facts based on their
ttlMsfield - TokenLimiter — compresses message history when it exceeds a token budget
- Summarizer — uses an LLM to summarize old messages, replacing many messages with a single summary
Effect Service
TheMemoryService Effect tag bundles working memory, semantic recall, and message history into a single service layer. This is the recommended way to use memory in Effect-based code.
Storage
Memory uses three SQLite tables, all created automatically:| Table | Purpose |
|---|---|
_smithers_memory_facts | Working memory key-value pairs |
_smithers_memory_threads | Message thread metadata |
_smithers_memory_messages | Individual messages within threads |
_smithers_vectors table from the RAG module. No separate vector table is needed.
Observability
Memory operations emit structured events and update Effect metrics:MemoryFactSet/MemoryRecalled/MemoryMessageSavedeventssmithers.memory.fact_reads/smithers.memory.fact_writescounterssmithers.memory.recall_queriescountersmithers.memory.recall_duration_mshistogram