Skip to main content

C# SDK: Spaces & Clusters

Organize memories into spaces and clusters using the Trix .NET SDK.

Overview

Spaces provide logical isolation for memories, perfect for multi-tenant applications or organizing different knowledge domains. Clusters are automatically discovered groupings of semantically related memories within a space.

Spaces

Manual organization with access control. Ideal for tenants, projects, or domains.

Clusters

Auto-discovered topic groups. Emerge from memory content and relationships.

// Access via the client
client.Spaces
client.Clusters

Spaces have human-readable slugs (e.g., project-alpha) that you can use instead of IDs. Slugs are auto-generated from names or can be customized.

Create Space

Create a new space to isolate memories for a tenant, project, or domain:

CreateSpace.cs
var space = await client.Spaces.CreateAsync(new CreateSpaceRequest
{
    Name = "Project Alpha",
    Slug = "alpha",  // Optional - auto-generated if not provided
    Description = "Knowledge base for Project Alpha"
});

Console.WriteLine($"Space ID: {space.Id}");
Console.WriteLine($"Slug: {space.Slug}");  // alpha

// With metadata
var projectSpace = await client.Spaces.CreateAsync(new CreateSpaceRequest
{
    Name = "Project Beta",
    Slug = "beta",
    Description = "Knowledge base for Project Beta",
    Metadata = new Dictionary<string, object>
    {
        ["department"] = "engineering",
        ["tier"] = "enterprise"
    }
});

Per-space settings (auto-clustering, retention, deduplication) are configured through the separate client.SpaceConfig resource, not at creation time.

List Spaces

Retrieve all spaces:

ListSpaces.cs
// Paginated list
var response = await client.Spaces.ListAsync();

foreach (var space in response.Data)
{
    Console.WriteLine($"{space.Name} ({space.Slug}): {space.Description}");
}

// With pagination
var page2 = await client.Spaces.ListAsync(limit: 20, page: 2);

foreach (var space in page2.Data)
{
    Console.WriteLine($"{space.Name} ({space.Slug})");
    Console.WriteLine($"  Created: {space.CreatedAt}");
    Console.WriteLine($"  Updated: {space.UpdatedAt}");
}

Get Space

Retrieve a single space by slug or ID:

GetSpace.cs
// Get by slug (recommended - human-friendly)
var space = await client.Spaces.GetAsync("alpha");

// Or by slug method
var space = await client.Spaces.GetBySlugAsync("alpha");

Update Space

Modify space properties:

UpdateSpace.cs
await client.Spaces.UpdateAsync("alpha", new UpdateSpaceRequest
{
    Name = "Project Alpha v2",
    Slug = "alpha-v2",  // Old slug will redirect to this
    Description = "Updated knowledge base"
});

Delete Space

Permanently delete a space and all its contents:

DeleteSpace.cs
await client.Spaces.DeleteAsync("space_old");

Deleting a space permanently removes all memories and clusters within it. This action cannot be undone.

Using Spaces

Assign memories to spaces when creating them:

UsingSpaces.cs
// Create memory in a specific space
var memory = await client.Memories.CreateAsync(new CreateMemoryRequest
{
    Content = "Customer reported billing issue resolved by refund",
    SpaceId = "space_support"
});

// Query within a space
var results = await client.Memories.ListAsync(new ListMemoriesRequest
{
    SpaceId = "space_support",
    Q = "billing issues"
});

// Search within a specific space
var spaceResults = await client.Memories.ListAsync(new ListMemoriesRequest
{
    SpaceId = "space_billing",
    Q = "refund policy"
});

List Clusters

Clusters are automatically discovered groups of semantically related memories. List clusters to see the topics that have emerged:

ListClusters.cs
// List all clusters
var clusters = await client.Clusters.ListAsync();

foreach (var cluster in clusters.Data)
{
    var count = cluster.MemoryIds?.Count ?? 0;
    Console.WriteLine($"{cluster.Name}: {count} memories");
}

// Filter by space
var spaceClusters = await client.Clusters.ListAsync(new ListClustersRequest
{
    SpaceId = "space_support"
});

// Topics and quality metrics are fetched separately
var topics = await client.Clusters.GetTopicsAsync("cluster_abc");
foreach (var topic in topics.Topics)
{
    Console.WriteLine($"  {topic.Name} (weight: {topic.Weight:F2})");
}

// Async enumerable
await foreach (var cluster in client.Clusters.ListAllAsync())
{
    Console.WriteLine(cluster.Name);
}

Get Cluster

Get details about a specific cluster including its memories:

GetCluster.cs
var cluster = await client.Clusters.GetAsync("cluster_billing");

Console.WriteLine($"Name: {cluster.Name}");
Console.WriteLine($"Description: {cluster.Description}");
Console.WriteLine($"Memory IDs: {cluster.MemoryIds?.Count ?? 0}");

// Quality metrics are fetched separately
var quality = await client.Clusters.GetQualityAsync("cluster_billing");
Console.WriteLine($"Cohesion: {quality.Cohesion:F2}");
Console.WriteLine($"Silhouette: {quality.Silhouette:F2}");

// Get with full memory objects
var clusterWithMemories = await client.Clusters.GetAsync(
    "cluster_billing",
    new GetClusterOptions { IncludeMemories = true }
);

Console.WriteLine("Memories:");
foreach (var memory in clusterWithMemories.Memories ?? new List<Memory>())
{
    Console.WriteLine($"  - {memory.Content}");
}

Create Cluster

Manually create a cluster to organize memories:

CreateCluster.cs
var cluster = await client.Clusters.CreateAsync(
    name: "C# Best Practices",
    description: "Collection of C# patterns and tips"
);

Console.WriteLine($"Created cluster: {cluster.Id}");

Manage Cluster Memories

Add or remove memories from clusters:

ManageClusterMemories.cs
// Add memory to cluster
await client.Clusters.AddMemoryAsync("cluster_abc", "mem_new");

// Remove memory from cluster
await client.Clusters.RemoveMemoryAsync("cluster_abc", "mem_old");

// Add multiple memories one at a time
await client.Clusters.AddMemoryAsync("cluster_abc", "mem_001");
await client.Clusters.AddMemoryAsync("cluster_abc", "mem_002");
await client.Clusters.AddMemoryAsync("cluster_abc", "mem_003");

Expand Cluster

Automatically find and add similar memories to a cluster:

ExpandCluster.cs
var expansion = await client.Clusters.ExpandAsync(
    "cluster_abc",
    limit: 10,
    threshold: 0.7
);

Console.WriteLine($"Cluster: {expansion.ClusterId}");
Console.WriteLine($"Suggested {expansion.NewMemories.Count} new memories");

foreach (var suggestion in expansion.NewMemories)
{
    Console.WriteLine($"  + {suggestion.MemoryId} (confidence: {suggestion.Confidence:F2})");
}

Delete Cluster

Delete a cluster (memories are not deleted, just unassigned):

DeleteCluster.cs
await client.Clusters.DeleteAsync("cluster_old");

Multi-Tenant Example

Setting up a multi-tenant architecture with spaces:

MultiTenant.cs
using Trix;
using Trix.Models;

public class TenantService
{
    private readonly TrixClient _adminClient;

    public TenantService(TrixClient adminClient)
    {
        _adminClient = adminClient;
    }

    public async Task<(Space Space, string SpaceId)> SetupTenant(string tenantId)
    {
        // Create space for tenant
        var space = await _adminClient.Spaces.CreateAsync(new CreateSpaceRequest
        {
            Name = tenantId,
            Description = $"Knowledge base for {tenantId}",
            Metadata = new Dictionary<string, object>
            {
                ["tenant_id"] = tenantId,
                ["created_by"] = "system"
            }
        });

        return (space, space.Id);
    }

    public async Task RemoveTenant(string tenantId)
    {
        // Find space by metadata
        var spaces = await _adminClient.Spaces.ListAsync();
        foreach (var space in spaces.Data)
        {
            if (space.Metadata?.TryGetValue("tenant_id", out var id) == true &&
                id?.ToString() == tenantId)
            {
                await _adminClient.Spaces.DeleteAsync(space.Id);
                break;
            }
        }
    }
}

Types Reference

Types.cs
public class Space
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string Slug { get; set; }
    public string? Description { get; set; }
    public Dictionary<string, object>? Metadata { get; set; }
    public DateTimeOffset CreatedAt { get; set; }
    public DateTimeOffset UpdatedAt { get; set; }
}

public class Cluster
{
    public string Id { get; set; }
    public string? SpaceId { get; set; }
    public string Name { get; set; }
    public string? Description { get; set; }
    public List<string>? MemoryIds { get; set; }
    public float[]? Centroid { get; set; }
    public Dictionary<string, object>? Metadata { get; set; }
    public ClusterScale? Scale { get; set; }
    public List<Memory>? Memories { get; set; }   // populated when IncludeMemories=true
    public DateTimeOffset CreatedAt { get; set; }
    public DateTimeOffset UpdatedAt { get; set; }
}

public class ExpandResult
{
    public string ClusterId { get; set; }
    public List<MemorySuggestion> NewMemories { get; set; }
}

public class MemorySuggestion
{
    public string MemoryId { get; set; }
    public double Confidence { get; set; }
}

Next Steps