ctx.memory

Scoped key-value and vector storage. Four scopes with different lifetimes and sharing rules — from ephemeral execution state to persistent user memory and shared suite context.

Why it exists

Correct lifecycle and portability. Execution = scratch; session = this conversation; persistent = forever (user-scoped); suite = shared across agents. Never replace with local variables or module state—you lose scope and audit.

How it makes life better

Use the four scopes and you get a clear contract: "scratch" vs "this session" vs "forever." Bypass with globals or ad-hoc storage and you get leaks, wrong lifetime, and no way to reason about what survives restarts.

The Four Scopes

typescript
// Four memory scopes, each with different lifetime and sharing rules
ctx.memory.execution // Ephemeral — auto-cleaned after execution ends
ctx.memory.session // User session — hours to days
ctx.memory.persistent // Long-term — user-scoped, survives restarts
ctx.memory.suite // Shared — all agents in the same suite can read/write
ScopeLifetimeShared withHas Vector StoreUse for
ctx.memory.executionUntil execution endsThis execution onlyNoStep state, intermediate results
ctx.memory.sessionHours to daysSame user sessionNoConversation context, user preferences
ctx.memory.persistentUntil explicitly deletedSame user, any agentYesKnowledge base, long-term user state
ctx.memory.suiteUntil suite completesAll agents in the suiteYesCross-agent data sharing in workflows

Key-Value Storage

All four scopes support key-value operations. Values are JSON-serialized automatically.

typescript
// Key-value storage
await ctx.memory.execution.set('step', 'extracting');
const step = await ctx.memory.execution.get('step'); // 'extracting'
// Store complex objects (automatically serialized)
await ctx.memory.persistent.set('user_preferences', {
language: 'en',
timezone: 'America/New_York',
notifications: true,
});
const prefs = await ctx.memory.persistent.get('user_preferences');
// { language: 'en', timezone: 'America/New_York', notifications: true }

KeyValueStore API

MethodReturnsDescription
get(key)Promise<T | null>Read a value. Returns null if not found.
set(key, value)Promise<void>Write a value. Overwrites existing.
delete(key)Promise<void>Remove a key.
has(key)Promise<boolean>Check if a key exists.
list(prefix?)Promise<string[]>List keys, optionally filtered by prefix.

Vector Store

The persistent and suite scopes also include a vector store for semantic search. Use ctx.llm.embed() to generate vectors, then store and search them.

typescript
// Vector storage for semantic search (persistent and suite scopes)
const embedding = await ctx.llm.embed('Invoice processing workflow');
// Store with metadata
await ctx.memory.persistent.store(embedding.vector, {
key: 'kb/invoice-workflow',
metadata: {
category: 'finance',
source: 'internal-kb',
updatedAt: Date.now(),
},
});
// Semantic search
const results = await ctx.memory.persistent.search(
(await ctx.llm.embed(userQuery)).vector,
{ limit: 5, minScore: 0.75 }
);
for (const result of results) {
console.log(result.key, 'score:', result.score);
console.log(result.metadata);
}

VectorStore API

MethodReturnsDescription
store(vector, options)Promise<string>Store a vector with key and metadata. Returns the storage ID.
search(vector, options)Promise<VectorSearchResult[]>Find similar vectors. Options: limit, minScore.
delete(key)Promise<void>Remove a stored vector by key.

Sharing Data Across Agents

ctx.memory.suite is the recommended way to pass large data between agents in a workflow — avoids serializing large payloads through function arguments.

typescript
// Suite memory — shared across all agents in the same workflow
// Agent A (web-researcher) stores research results
await ctx.memory.suite.set('research_results', researchData);
// Agent B (report-generator) in the same suite reads them
const research = await ctx.memory.suite.get('research_results');
// Useful for: passing large data between agents without duplicating in function args,
// building shared context as a multi-agent workflow progresses

Tracking Execution Progress

typescript
// Track multi-step progress in execution memory
await ctx.memory.execution.set('progress', { step: 1, total: 5, status: 'processing' });
// Later in the same execution
const progress = await ctx.memory.execution.get('progress');
await ctx.memory.execution.set('progress', { ...progress, step: 2 });
// When execution ends, this is automatically cleaned up — no manual delete needed

In the wild

Reference agents that demonstrate ctx.memory in production.

See Also