Overview
The memories resource handles creating, reading, updating, and deleting memory objects. Memories are the core data type in Trix - use them to store any information you want your AI to remember.
// Access via the client
client.MemoriesCreate Memory
Store a new memory with optional tags, metadata, and space assignment:
using Trix.Models;
var memory = await client.Memories.CreateAsync(new CreateMemoryRequest
{
Content = "C# provides static type checking at compile time",
Type = MemoryType.Text,
Tags = new List<string> { "csharp", "programming" },
Metadata = new Dictionary<string, object>
{
["source"] = "documentation",
["author"] = "team"
},
SpaceId = "space_abc123" // Optional: assign to space
});
Console.WriteLine($"Created memory: {memory.Id}");
Console.WriteLine($"Content: {memory.Content}");Create Request Options
| Property | Type | Description |
|---|---|---|
Content | string | The memory content (required) |
Type | MemoryType | Text, Markdown, Code, Json, Html, Url, Audio |
Tags | List<string> | Tags for categorization |
Metadata | Dictionary<string, object> | Custom key-value metadata |
SpaceId | string? | Space to store memory in |
Priority | int? | Priority level (0-100) |
ExpiresAt | DateTime? | Expiration timestamp |
Search Memories
Search for memories using semantic search, full-text search, or hybrid mode:
// Search with semantic query
var results = await client.Memories.ListAsync(new ListMemoriesRequest
{
Q = "how does C# handle types?",
Mode = SearchMode.Semantic,
Limit = 10
});
foreach (var memory in results.Data)
{
Console.WriteLine($"Score: {memory.Score:F2} - {memory.Content}");
}
// Hybrid search (combines semantic and full-text)
var hybrid = await client.Memories.ListAsync(new ListMemoriesRequest
{
Q = "static type checking",
Mode = SearchMode.Hybrid,
Threshold = 0.5,
Limit = 20
});Search Modes
| Mode | Description | Best For |
|---|---|---|
SearchMode.Semantic | Vector similarity search | Conceptual queries, finding related content |
SearchMode.Keyword | Keyword search with BM25 | Exact matches, known keywords |
SearchMode.Hybrid | Combines semantic and keyword with RRF | General purpose (recommended) |
List Memories
List memories with filtering and pagination:
// List all memories with pagination
var response = await client.Memories.ListAsync(new ListMemoriesRequest
{
Limit = 20,
Offset = 0
});
Console.WriteLine($"Total: {response.Total}");
Console.WriteLine($"Has more: {response.HasMore}");
foreach (var m in response.Data)
{
Console.WriteLine($"- {m.Content}");
}
// Filter by tags
var tagged = await client.Memories.ListAsync(new ListMemoriesRequest
{
Tags = new List<string> { "csharp", "programming" },
SortBy = "createdAt",
SortOrder = "desc"
});
// Filter by space
var spaceMemories = await client.Memories.ListAsync(new ListMemoriesRequest
{
SpaceId = "space_abc123",
Type = MemoryType.Text,
Limit = 50
});Async Enumerable
Stream through all memories without manual pagination using await foreach:
// Automatically handles pagination
await foreach (var memory in client.Memories.ListAllAsync())
{
Console.WriteLine(memory.Content);
}
// With filters
await foreach (var memory in client.Memories.ListAllAsync(new ListMemoriesRequest
{
Tags = new List<string> { "important" },
Type = MemoryType.Text
}))
{
ProcessMemory(memory);
}
// With cancellation
var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
await foreach (var memory in client.Memories.ListAllAsync(cancellationToken: cts.Token))
{
if (ShouldStop(memory))
break;
await HandleMemory(memory);
}The ListAllAsync() method returns an IAsyncEnumerable that
automatically fetches pages as needed. This is memory-efficient for large datasets.
Get Single Memory
Retrieve a specific memory by ID:
var memory = await client.Memories.GetAsync("mem_xyz789");
Console.WriteLine($"ID: {memory.Id}");
Console.WriteLine($"Content: {memory.Content}");
Console.WriteLine($"Type: {memory.Type}");
Console.WriteLine($"Tags: {string.Join(", ", memory.Tags ?? Array.Empty<string>())}");
Console.WriteLine($"Created: {memory.CreatedAt}");
// Access metadata
if (memory.Metadata != null)
{
foreach (var (key, value) in memory.Metadata)
{
Console.WriteLine($" {key}: {value}");
}
}Update Memory
Update an existing memory's content, tags, or metadata:
var updated = await client.Memories.UpdateAsync("mem_xyz789", new UpdateMemoryRequest
{
Content = "Updated content here",
Tags = new List<string> { "csharp", "updated" },
Metadata = new Dictionary<string, object>
{
["lastReviewed"] = DateTime.UtcNow.ToString("O"),
["version"] = 2
}
});
Console.WriteLine($"Updated at: {updated.UpdatedAt}");Updating content triggers re-embedding. If you only want to update metadata or tags, consider using a metadata-only update to avoid re-embedding costs.
Delete Memory
Permanently delete a memory:
await client.Memories.DeleteAsync("mem_xyz789");
// Delete with error handling
try
{
await client.Memories.DeleteAsync("mem_xyz789");
Console.WriteLine("Memory deleted successfully");
}
catch (NotFoundException)
{
Console.WriteLine("Memory not found - already deleted?");
}Bulk Operations
Perform operations on multiple memories at once for better performance:
Bulk Create
var result = await client.Memories.BulkCreateAsync(new List<CreateMemoryRequest>
{
new() { Content = "First memory", Tags = new List<string> { "batch" } },
new() { Content = "Second memory", Tags = new List<string> { "batch" } },
new() { Content = "Third memory", Tags = new List<string> { "batch" } }
});
Console.WriteLine($"Created: {result.Success}");
Console.WriteLine($"Failed: {result.Failed}");
if (result.Errors?.Count > 0)
{
foreach (var error in result.Errors)
{
Console.WriteLine($"Error at index {error.Index}: {error.Message}");
}
}Bulk Update
var updateResult = await client.Memories.BulkUpdateAsync(new List<BulkUpdateItem>
{
new() { Id = "mem_abc123", Priority = 10 },
new() { Id = "mem_def456", Tags = new List<string> { "important" } },
new() { Id = "mem_ghi789", Metadata = new Dictionary<string, object> { ["reviewed"] = true } }
});
Console.WriteLine($"Updated: {updateResult.Success}");Bulk Delete
var deleteResult = await client.Memories.BulkDeleteAsync(new List<string>
{
"mem_abc123",
"mem_def456",
"mem_ghi789"
});
Console.WriteLine($"Deleted: {deleteResult.Success}");
Console.WriteLine($"Failed: {deleteResult.Failed}");Bulk operations are significantly faster than individual operations when working with many memories. Use them when creating, updating, or deleting more than 5-10 memories at once.
Reinforce Relationships
Boost a relationship's strength when it proves useful. This helps the most relevant connections surface in future graph traversals:
// Reinforce a helpful relationship
await client.Relationships.ReinforceAsync("rel_abc123", amount: 0.1);Memory Type Reference
The Memory object structure:
public class Memory
{
public string Id { get; set; }
public string SpaceId { get; set; }
public MemoryType Type { get; set; }
public string Content { get; set; }
public double[]? Embedding { get; set; }
public List<string>? Tags { get; set; }
public Dictionary<string, object>? Metadata { get; set; }
public int Priority { get; set; }
public double Salience { get; set; }
public bool IsPrivate { get; set; }
public double? Score { get; set; } // Search relevance score
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public DateTime? AccessedAt { get; set; }
}Paginated Response
public class PaginatedResponse<T>
{
public List<T> Data { get; set; }
public int Total { get; set; }
public int Page { get; set; }
public int Limit { get; set; }
public bool HasMore { get; set; }
}Memory Pinning
Pin important memories to prevent them from being affected by decay or automatic cleanup. Pinned memories are always prioritized in search results.
// Pin a memory to mark it as important
await client.Memories.PinAsync("mem_xyz789");
// Unpin a memory
await client.Memories.UnpinAsync("mem_xyz789");
// Check if a memory is pinned
var memory = await client.Memories.GetAsync("mem_xyz789");
Console.WriteLine($"Pinned: {memory.IsPinned}");
// Create a memory as pinned
var pinned = await client.Memories.CreateAsync(new CreateMemoryRequest
{
Content = "Critical business rule: always validate input",
IsPinned = true,
Tags = new List<string> { "rules", "validation" }
});
// List only pinned memories
var pinnedMemories = await client.Memories.ListAsync(new ListMemoriesRequest
{
Pinned = true
});
foreach (var m in pinnedMemories.Data)
{
Console.WriteLine($"Pinned: {m.Content.Substring(0, Math.Min(50, m.Content.Length))}...");
}Use pinning for critical information that should never be forgotten, such as core business rules, important contacts, or key procedures.
Protection Levels
Set protection levels on memories to control how they can be modified or deleted. This provides an extra layer of safety for important data.
using Trix.Models;
// Set protection level on existing memory
await client.Memories.SetProtectionLevelAsync("mem_xyz789", ProtectionLevel.Hard);
// Protection levels:
// - ProtectionLevel.None: No protection (default)
// - ProtectionLevel.Soft: Requires confirmation for deletion
// - ProtectionLevel.Hard: Cannot be deleted without removing protection first
// Create memory with protection
var protectedMemory = await client.Memories.CreateAsync(new CreateMemoryRequest
{
Content = "Legal compliance requirement: retain for 7 years",
ProtectionLevel = ProtectionLevel.Hard,
Tags = new List<string> { "legal", "compliance" }
});
// Check protection level
var memory = await client.Memories.GetAsync("mem_xyz789");
Console.WriteLine($"Protection: {memory.ProtectionLevel}");
// Remove protection before deletion
await client.Memories.SetProtectionLevelAsync("mem_xyz789", ProtectionLevel.None);
await client.Memories.DeleteAsync("mem_xyz789");Protection Level Reference
| Level | Description | Use Case |
|---|---|---|
ProtectionLevel.None | No protection, can be freely modified or deleted | Regular memories |
ProtectionLevel.Soft | Deletion requires explicit confirmation | Important but occasionally updated data |
ProtectionLevel.Hard | Cannot be deleted without first removing protection | Critical data, compliance requirements |
Soft Delete & Restore
Soft delete moves memories to a recoverable state instead of permanently deleting them. This allows you to restore accidentally deleted memories.
// Soft delete a memory (recoverable)
await client.Memories.SoftDeleteAsync("mem_xyz789");
// Memory is now in "deleted" state but can be restored
var deleted = await client.Memories.GetAsync("mem_xyz789");
Console.WriteLine($"Deleted at: {deleted.DeletedAt}");
// Restore a soft-deleted memory
await client.Memories.RestoreAsync("mem_xyz789");
// Memory is now active again
var restored = await client.Memories.GetAsync("mem_xyz789");
Console.WriteLine("Status: active");
// List soft-deleted memories
var deletedMemories = await client.Memories.ListAsync(new ListMemoriesRequest
{
IncludeDeleted = true
});
foreach (var m in deletedMemories.Data)
{
Console.WriteLine($"Deleted: {m.Content.Substring(0, Math.Min(50, m.Content.Length))}... at {m.DeletedAt}");
}
// Permanently delete
await client.Memories.DeleteAsync("mem_xyz789");Soft-deleted memories are automatically purged after 30 days by default. Configure the retention period in your space settings.
Topic Extraction
Extract and search by topics to organize and discover related memories. Topics are automatically extracted or can be manually assigned.
// Get topics for a specific memory
var topics = await client.Memories.GetTopicsAsync("mem_xyz789");
foreach (var topic in topics)
{
Console.WriteLine($"Topic: {topic.Name} (relevance: {topic.Relevance:F2}, category: {topic.Category})");
}
// Search memories by topic
var results = await client.Memories.SearchByTopicAsync("machine learning", limit: 20);
foreach (var memory in results)
{
Console.WriteLine($"- {memory.Content.Substring(0, Math.Min(50, memory.Content.Length))}...");
}
// Combine with text search
var combined = await client.Memories.ListAsync(new ListMemoriesRequest
{
Q = "dependency injection",
Mode = SearchMode.Hybrid
});
// Manually tag a memory with topics
await client.Memories.UpdateAsync("mem_xyz789", new UpdateMemoryRequest
{
Tags = new List<string> { "software architecture", "best practices" }
});Quality Scores & Enrichment
Assess memory quality and enrich memories with additional metadata, summaries, and extracted information.
Quality Scores
// Get quality score for a memory
var score = await client.Memories.GetQualityScoreAsync("mem_xyz789");
Console.WriteLine($"Quality score: {score:F2}");
// List memories filtered by quality
var highQuality = await client.Memories.ListAsync(new ListMemoriesRequest
{
MinQuality = 0.7,
Limit = 50
});
// List high-quality memories
foreach (var m in highQuality.Data)
{
Console.WriteLine($"High quality: {m.Content.Substring(0, Math.Min(50, m.Content.Length))}...");
}Memory Enrichment
using Trix.Models;
// Enrich a memory with additional data
var result = await client.Memories.EnrichAsync("mem_xyz789", new EnrichMemoryOptions
{
Operations = new List<EnrichmentOperation>
{
EnrichmentOperation.Topics,
EnrichmentOperation.Summary,
EnrichmentOperation.Entities
}
});
Console.WriteLine($"Memory: {result.MemoryId}");
Console.WriteLine($"Operations: {string.Join(", ", result.Operations)}");
// Results are keyed by operation name
foreach (var (op, value) in result.Results)
{
Console.WriteLine($"{op}: {value}");
}
// Trigger an async enrichment via the Enrichments resource
var triggered = await client.Enrichments.TriggerAsync("mem_xyz789");Enrichment Operations
| Operation | Description |
|---|---|
EnrichmentOperation.Topics | Extract topic labels from content |
EnrichmentOperation.Summary | Generate a concise summary |
EnrichmentOperation.Entities | Extract named entities (people, places, organizations) |
EnrichmentOperation.Quality | Calculate a quality score for the memory |
Multi-scale Clusters
Access memory clusters at different granularity levels to understand how memories are organized and find related content.
using Trix.Models;
// List clusters at different scales
var fineClusters = await client.Clusters.ListAsync(new ListClustersRequest
{
Scale = ClusterScale.Fine
});
var mediumClusters = await client.Clusters.ListAsync(new ListClustersRequest
{
Scale = ClusterScale.Medium
});
var coarseClusters = await client.Clusters.ListAsync(new ListClustersRequest
{
Scale = ClusterScale.Coarse
});
Console.WriteLine($"Fine clusters: {fineClusters.Data.Count}");
Console.WriteLine($"Medium clusters: {mediumClusters.Data.Count}");
Console.WriteLine($"Coarse clusters: {coarseClusters.Data.Count}");
// Get cluster details
foreach (var cluster in fineClusters.Data.Take(5))
{
Console.WriteLine($"Cluster: {cluster.Name}");
Console.WriteLine($" Memories: {cluster.MemoryIds?.Count ?? 0}");
}
// Fetch a cluster with its memory objects hydrated
var withMemories = await client.Clusters.GetAsync(
"cluster_abc123",
new GetClusterOptions { IncludeMemories = true }
);
foreach (var mem in withMemories.Memories ?? new List<Memory>())
{
Console.WriteLine($" - {mem.Content}");
}Cluster Scales
| Scale | Description | Typical Use |
|---|---|---|
ClusterScale.Fine | Many small, tightly related clusters | Finding very similar memories |
ClusterScale.Medium | Balanced clustering | General organization (default) |
ClusterScale.Coarse | Few large, broadly related clusters | High-level categorization |
Advanced List & Create Options
The list and create methods support additional parameters for fine-grained control over memory management.
Advanced List Options
// List with all advanced filters
var memories = await client.Memories.ListAsync(new ListMemoriesRequest
{
Q = "search query", // Text search
Mode = SearchMode.Hybrid, // Search mode
Tags = new List<string> { "important" }, // Filter by tags
SpaceId = "space_abc123", // Filter by space
Pinned = true, // Only pinned memories
Protected = true, // Only protected memories
MinQuality = 0.7, // Minimum quality score
IncludeDeleted = false, // Include soft-deleted
SessionId = "sess_abc123", // Filter by session
Limit = 50,
Offset = 0
});
// Iterate with advanced filters
await foreach (var memory in client.Memories.ListAllAsync(new ListMemoriesRequest
{
Pinned = true,
MinQuality = 0.8
}))
{
Console.WriteLine($"High-quality pinned: {memory.Content.Substring(0, Math.Min(50, memory.Content.Length))}...");
}Advanced Create Options
// Create with all options
var memory = await client.Memories.CreateAsync(new CreateMemoryRequest
{
Content = "Important business rule documentation",
Type = MemoryType.Markdown,
Tags = new List<string> { "rules", "documentation" },
Metadata = new Dictionary<string, object>
{
["author"] = "admin",
["department"] = "engineering"
},
SpaceId = "space_abc123",
Priority = 9,
IsPinned = true, // Pin on creation
ProtectionLevel = ProtectionLevel.Soft, // Set protection
ExpiresAt = DateTime.Parse("2025-12-31T23:59:59Z") // Expiration date
});
Console.WriteLine($"Created: {memory.Id}");
Console.WriteLine($"Pinned: {memory.IsPinned}");
Console.WriteLine($"Protection: {memory.ProtectionLevel}");Next Steps
- Graph & Relationships - Connect memories with relationships
- Spaces & Clusters - Organize memories
- Advanced Topics - Error handling and best practices