Your First Memory

A hands-on tutorial walking through the complete memory lifecycle. You will create a memory, search for it, update it, and delete it -- all with detailed code examples and example responses.

Overview

Every memory in Rekall follows the same lifecycle: Create, Read (search or retrieve), Update, and Delete. This tutorial walks through each operation step by step, using realistic examples.

We will create an episodic memory capturing a user interaction, search for it with natural language, update it with new information, and finally clean it up. By the end, you will understand how memories flow through the system.

Prerequisites

This tutorial assumes you have already installed the SDK and configured your API key. If not, complete the Quickstart first.

Create a Memory

Choosing a Memory Type

Rekall supports 7 memory types. For this tutorial, we will use episodic memory, which captures events with context -- perfect for recording interactions, decisions, and observations. Here is a quick reference for when to use each type:

TypeBest For
episodicEvents, interactions, decisions, observations
semanticFacts, entities, relationships, domain knowledge
proceduralWorkflows, recipes, step-by-step processes
long_termConsolidated knowledge, accumulated insights
short_termCurrent session context, working state
executionAgent task state, checkpoints, progress tracking
preferencesLearned user preferences and settings

Create Request

Let's create an episodic memory that records a user conversation where they described their project requirements.

import { RekallClient } from '@rekall/agent-sdk';
const rekall = new RekallClient({
apiKey: process.env.REKALL_API_KEY,
});
const memory = await rekall.memories.create({
type: 'episodic',
content: `User described their project: building a multi-agent system for
customer support. They need agents to remember conversation history,
track open tickets, and learn from resolved issues. The system serves
approximately 10,000 customers and handles 500 tickets per day.`,
metadata: {
source: 'project-planning-session',
userId: 'user_abc123',
agentId: 'agent_planner_01',
tags: ['project-requirements', 'customer-support', 'multi-agent'],
importance: 'high',
},
context: 'personal',
});
console.log('Memory created:', memory.id);
console.log('Type:', memory.type);
console.log('Strength:', memory.strength);

Example response:

201 Created
{
"id": "mem_9c4f2a1e8b3d7f6a5e0c9d8b",
"type": "episodic",
"content": "User described their project: building a multi-agent system for customer support...",
"context": "personal",
"metadata": {
"source": "project-planning-session",
"userId": "user_abc123",
"agentId": "agent_planner_01",
"tags": ["project-requirements", "customer-support", "multi-agent"],
"importance": "high"
},
"strength": 1.0,
"embedding": null,
"createdAt": "2025-01-15T14:22:00.000Z",
"updatedAt": "2025-01-15T14:22:00.000Z",
"lastAccessedAt": "2025-01-15T14:22:00.000Z",
"accessCount": 0
}

Embeddings are generated automatically

You do not need to provide embeddings. Rekall automatically generates vector embeddings from the content using a high-quality embedding model. The embedding field appears as null in the response for brevity, but the vectors are stored and indexed for semantic search.

Search for Memories

Rekall supports two primary search modes: semantic search (natural language queries matched against vector embeddings) and filtered search (using metadata fields, tags, and memory types).

Search with a natural language query. Rekall converts your query into an embedding and finds the most similar memories using cosine similarity.

const results = await rekall.memories.search({
query: 'what are the customer support project requirements?',
limit: 5,
threshold: 0.7,
});
for (const result of results) {
console.log(`Score: ${result.score.toFixed(3)}`);
console.log(`Type: ${result.memory.type}`);
console.log(`Content: ${result.memory.content.substring(0, 100)}...`);
console.log('---');
}

Example response:

Search Results
{
"results": [
{
"score": 0.952,
"memory": {
"id": "mem_9c4f2a1e8b3d7f6a5e0c9d8b",
"type": "episodic",
"content": "User described their project: building a multi-agent system for customer support...",
"context": "personal",
"strength": 1.0,
"metadata": {
"source": "project-planning-session",
"tags": ["project-requirements", "customer-support", "multi-agent"]
},
"createdAt": "2025-01-15T14:22:00.000Z"
}
}
],
"total": 1,
"query": "what are the customer support project requirements?"
}

Combine semantic search with metadata filters for precise results. You can filter by memory type, tags, date ranges, context, and custom metadata fields.

const results = await rekall.memories.search({
query: 'project requirements',
type: 'episodic',
filters: {
tags: { contains: 'customer-support' },
'metadata.importance': 'high',
createdAfter: '2025-01-01T00:00:00Z',
},
limit: 10,
});
console.log(`Found ${results.length} matching memories`);

Update a Memory

Memories evolve as new information becomes available. Rekall supports both partial updates (patch specific fields) and full replacements.

Partial Update

Use a partial update to modify specific fields without affecting others. This is the most common way to update memories -- for example, appending new context or changing tags.

const updated = await rekall.memories.update(
'mem_9c4f2a1e8b3d7f6a5e0c9d8b',
{
content: `User described their project: building a multi-agent system for
customer support. They need agents to remember conversation history,
track open tickets, and learn from resolved issues. The system serves
approximately 10,000 customers and handles 500 tickets per day.
UPDATE: User confirmed they want to use Rekall for long-term memory
and preferences. Budget approved for Pro plan. Timeline is Q2 launch.`,
metadata: {
source: 'project-planning-session',
userId: 'user_abc123',
agentId: 'agent_planner_01',
tags: ['project-requirements', 'customer-support', 'multi-agent', 'approved'],
importance: 'high',
status: 'approved',
},
}
);
console.log('Updated at:', updated.updatedAt);

Example response:

200 OK
{
"id": "mem_9c4f2a1e8b3d7f6a5e0c9d8b",
"type": "episodic",
"content": "User described their project: building a multi-agent system for customer support... UPDATE: User confirmed they want to use Rekall for long-term memory and preferences. Budget approved for Pro plan. Timeline is Q2 launch.",
"context": "personal",
"metadata": {
"source": "project-planning-session",
"userId": "user_abc123",
"agentId": "agent_planner_01",
"tags": ["project-requirements", "customer-support", "multi-agent", "approved"],
"importance": "high",
"status": "approved"
},
"strength": 1.0,
"createdAt": "2025-01-15T14:22:00.000Z",
"updatedAt": "2025-01-15T15:45:00.000Z",
"lastAccessedAt": "2025-01-15T15:45:00.000Z",
"accessCount": 2
}

Re-embedding on content change

When you update a memory's content, Rekall automatically regenerates the vector embedding to reflect the new text. This ensures semantic search results remain accurate after updates. Metadata-only updates do not trigger re-embedding.

Full Replacement

Use a PUT request to completely replace a memory. All fields not included in the request will be reset to their defaults. This is useful when you want to rewrite a memory entirely.

const replaced = await rekall.memories.replace(
'mem_9c4f2a1e8b3d7f6a5e0c9d8b',
{
type: 'episodic',
content: 'Project requirements finalized: multi-agent customer support system using Rekall. Pro plan approved, Q2 launch target.',
metadata: {
source: 'project-planning-session',
userId: 'user_abc123',
tags: ['project-requirements', 'finalized'],
status: 'finalized',
},
context: 'personal',
}
);

PUT replaces the entire memory

A PUT (replace) operation replaces the entire memory object. Any fields you omit will be reset. For most use cases, prefer PATCH (partial update) to avoid accidentally losing metadata.

Delete a Memory

Delete a memory permanently by its ID. This is irreversible -- the memory, its embedding, and all associated metadata will be removed.

await rekall.memories.delete('mem_9c4f2a1e8b3d7f6a5e0c9d8b');
console.log('Memory deleted successfully.');
// Attempting to retrieve it will throw a 404 error
try {
await rekall.memories.get('mem_9c4f2a1e8b3d7f6a5e0c9d8b');
} catch (error) {
console.log(error.status); // => 404
console.log(error.message); // => Memory not found
}

Deletion is permanent

There is no undo for memory deletion. If you need to preserve memories for audit purposes, consider using soft-delete by updating the metadata with a deleted: true flag instead. Alternatively, create a snapshot before deleting.

Lifecycle Summary

Here is a recap of the full memory CRUD lifecycle and the corresponding HTTP methods:

OperationMethodEndpointDescription
CreatePOST/v1/memoriesStore a new memory with content and metadata
ReadGET/v1/memories/:idRetrieve a memory by ID (also strengthens it)
SearchPOST/v1/memories/searchSemantic or filtered search across memories
UpdatePATCH/v1/memories/:idPartially update specific fields
ReplacePUT/v1/memories/:idFully replace a memory
DeleteDELETE/v1/memories/:idPermanently remove a memory

Next Steps

You now understand the complete memory lifecycle. Here is where to go deeper:

Rekall
rekall