Skip to main content
Session memory gives each conversation its own typed key-value scope over the same pluggable StateStore used for durability checkpoints — no hand-rolled per-project memory table, and no separate persistence layer to configure.

Attaching memory to routes

withMemory is a middleware that attaches a MemoryStore to ctx.state, namespaced per request:
By default, the namespace is the x-session-id request header, falling back to 'default' if the header is absent. Pass a custom function to derive the namespace differently — from a JWT claim, a cookie, or a route param:

Reading and writing memory in a handler

getMemory(ctx) returns undefined if withMemory wasn’t attached upstream — always check before use, or attach it at the root _middleware.ts so every route has it.

MemoryStore API

<T>(key: string) => Promise<T | undefined>
Read a typed value. Returns undefined if the key was never set.
(key: string, value: unknown) => Promise<void>
Write a value, overwriting anything already stored under key.
<T>(key: string, item: T) => Promise<number>
Append item to an array value, creating the array if it doesn’t exist yet. Returns the new array length. Useful for conversation history without a separate read-modify-write round trip in handler code.
(key: string) => Promise<void>
Remove a key.
() => Promise<string[]>
List all keys currently set within this instance’s namespace.
Every key is stored under a namespaced prefix (anvil:memory:<namespace>:<key>) in the underlying StateStore, so different sessions never collide even when sharing one store instance.

Choosing a backing store

MemoryStore works over any StateStore implementation:
SqliteStateStore also backs durable execution checkpoints — a single store instance can serve both session memory and agent-run checkpointing, since they write to different key prefixes.

See also

  • RAG & retrieval — semantic search over documents, distinct from per-session conversational memory
  • Semantic cache — cache LLM responses across sessions by prompt similarity
  • Durable execution — checkpoint and resume agent runs using the same StateStore interface
Session memory gives each conversation its own typed key-value scope over the same pluggable StateStore used for durability checkpoints — no hand-rolled per-project memory table, and no separate persistence layer to configure.

Attaching memory to routes

withMemory is a middleware that attaches a MemoryStore to ctx.state, namespaced per request:
By default, the namespace is the x-session-id request header, falling back to 'default' if the header is absent. Pass a custom function to derive the namespace differently — from a JWT claim, a cookie, or a route param:

Reading and writing memory in a handler

getMemory(ctx) returns undefined if withMemory wasn’t attached upstream — always check before use, or attach it at the root _middleware.ts so every route has it.

MemoryStore API

<T>(key: string) => Promise<T | undefined>
Read a typed value. Returns undefined if the key was never set.
(key: string, value: unknown) => Promise<void>
Write a value, overwriting anything already stored under key.
<T>(key: string, item: T) => Promise<number>
Append item to an array value, creating the array if it doesn’t exist yet. Returns the new array length. Useful for conversation history without a separate read-modify-write round trip in handler code.
(key: string) => Promise<void>
Remove a key.
() => Promise<string[]>
List all keys currently set within this instance’s namespace.
Every key is stored under a namespaced prefix (anvil:memory:<namespace>:<key>) in the underlying StateStore, so different sessions never collide even when sharing one store instance.

Choosing a backing store

MemoryStore works over any StateStore implementation:
SqliteStateStore also backs durable execution checkpoints — a single store instance can serve both session memory and agent-run checkpointing, since they write to different key prefixes.

See also

  • RAG & retrieval — semantic search over documents, distinct from per-session conversational memory
  • Semantic cache — cache LLM responses across sessions by prompt similarity
  • Durable execution — checkpoint and resume agent runs using the same StateStore interface