Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/S1LV4/th0th/llms.txt

Use this file to discover all available pages before exploring further.

Overview

th0th’s memory system enables AI assistants to remember context across sessions. Unlike conversation history that’s lost when the session ends, memories persist indefinitely and are retrieved based on semantic similarity and relevance.
Memories are organized in 4 hierarchical levels (L0-L3) with different scopes and retention policies, inspired by human memory systems.

Memory Hierarchy

Four-Level Architecture

Scope: Global across all projects and sessionsLifetime: Indefinite (never auto-deleted)Use cases:
  • Critical architectural decisions
  • Reusable design patterns
  • Important learnings from past projects
Example:
await th0th.remember({
  content: "Always use bcrypt with cost factor 12 for password hashing",
  type: MemoryType.DECISION,
  level: MemoryLevel.PERSISTENT
});

Level Determination

The MemoryService automatically determines the appropriate level:
function determineLevel(
  type: MemoryType,
  opts: { userId?, sessionId?, projectId?, agentId? }
): MemoryLevel {
  // Agent hierarchy overrides
  if (agentId === 'orchestrator' && type === 'decision') {
    return MemoryLevel.PERSISTENT;  // L0
  }
  if (agentId === 'architect' && type === 'pattern') {
    return MemoryLevel.PROJECT;     // L1
  }
  
  // Scope-based defaults
  if (projectId) return MemoryLevel.PROJECT;
  if (userId && !sessionId) return MemoryLevel.USER;
  if (sessionId) return MemoryLevel.SESSION;
  
  // Type-based defaults
  switch (type) {
    case MemoryType.DECISION: return MemoryLevel.PERSISTENT;
    case MemoryType.PATTERN: return MemoryLevel.PROJECT;
    case MemoryType.PREFERENCE: return MemoryLevel.USER;
    default: return MemoryLevel.SESSION;
  }
}
You rarely need to specify level manually—the system infers it from context (projectId, userId, sessionId) and memory type.

Memory Types

th0th supports 5 memory types optimized for different content:

DECISION

Important choices made during developmentExamples:
  • “Use PostgreSQL over MongoDB”
  • “Implement rate limiting at API gateway”

PATTERN

Reusable code patterns and architectureExamples:
  • “Use factory pattern for creating clients”
  • “Repository pattern for data access”

CODE

Code snippets and implementation detailsExamples:
  • “Error handling wrapper function location”
  • “Custom hooks in src/hooks/”

PREFERENCE

User/team preferences and styleExamples:
  • “Use Tailwind over CSS modules”
  • “Prefer async/await over promises”

CONVERSATION

Dialogue context (usually L3/session)Examples:
  • “User is debugging login flow”
  • “Working on feature: dark mode”

Semantic Retrieval

Intelligent Ranking Algorithm

Memory recall uses a multi-factor scoring system balancing stability and plasticity:
function semanticRank(
  memories: Memory[],
  queryEmbedding: number[],
  limit: number
): ScoredMemory[] {
  return memories.map(memory => {
    // 1. Semantic similarity (65% weight)
    const semanticScore = cosineSimilarity(
      queryEmbedding,
      memory.embedding
    );
    
    // 2. Temporal score (20% weight)
    const temporalScore = forgettingCurve(memory);
    
    // 3. Access frequency (10% weight)
    const accessBoost = log1p(memory.accessCount) / log(20);
    
    // 4. Memory type boost (5% weight)
    const typeBoost = getTypeBoost(memory.type);
    
    // Weighted combination
    const score = 
      semanticScore * 0.65 +
      temporalScore * 0.20 +
      accessBoost * 0.10 +
      typeBoost * 0.05;
    
    return { ...memory, score };
  })
  .sort((a, b) => b.score - a.score)
  .slice(0, limit);
}
Cosine similarity between query embedding and memory embedding.Measures how closely the query relates to the stored memory conceptually.
function cosineSimilarity(a: number[], b: number[]): number {
  let dot = 0, normA = 0, normB = 0;
  for (let i = 0; i < a.length; i++) {
    dot += a[i] * b[i];
    normA += a[i] * a[i];
    normB += b[i] * b[i];
  }
  return dot / (Math.sqrt(normA) * Math.sqrt(normB));
}
Ebbinghaus forgetting curve with 72-hour half-life.Memories fade over time unless accessed (which resets their lastAccessed timestamp).
function forgettingCurve(memory: Memory): number {
  const now = Date.now();
  const reference = memory.lastAccessed || memory.createdAt;
  const ageHours = (now - reference) / (1000 * 60 * 60);
  
  // Half-life = 72 hours
  const decay = Math.pow(0.5, ageHours / 72);
  
  // Floor at 0.1 (never completely forget)
  return Math.max(0.1, Math.min(1, decay));
}
Effect: Recent memories rank higher; old memories fade but never disappear.
Logarithmic boost for frequently accessed memories.Simulates human memory reinforcement through repetition.
function accessBoost(accessCount: number): number {
  const normalized = Math.log1p(accessCount) / Math.log(20);
  return Math.max(0.1, Math.min(1, normalized));
}
Effect: Memories accessed 20+ times get maximum boost (1.0).
Small priors favoring reusable memory types.
function getTypeBoost(type: MemoryType): number {
  switch (type) {
    case MemoryType.DECISION: return 1.0;
    case MemoryType.PATTERN: return 0.9;
    case MemoryType.PREFERENCE: return 0.85;
    case MemoryType.CODE: return 0.8;
    case MemoryType.CONVERSATION: return 0.7;
  }
}
Effect: Decisions and patterns prioritized over conversation snippets.

Memory Clustering

th0th uses redundancy filtering to avoid storing near-duplicate memories:
class MemoryClusteringService {
  async findSimilarMemories(
    content: string,
    level: MemoryLevel,
    threshold: number = 0.9
  ): Promise<Memory[]> {
    const embedding = await embeddingService.embed(content);
    const candidates = await repository.searchByLevel(level);
    
    return candidates.filter(memory => {
      const similarity = cosineSimilarity(embedding, memory.embedding);
      return similarity >= threshold;
    });
  }
}
If a new memory is 90%+ similar to an existing one, options:
  • Merge: Update existing memory with new info
  • Skip: Don’t store duplicate
  • Replace: Newer memory supersedes older
Redundancy filtering prevents memory bloat from repeated similar observations.

Memory Operations

Storing Memories

// Simple API
await th0th.remember({
  content: "Database schema uses snake_case for column names",
  type: MemoryType.PATTERN,
  projectId: "my-app"
  // level auto-determined as PROJECT
});

// Advanced options
await th0th.remember({
  content: "User prefers single quotes in JavaScript",
  type: MemoryType.PREFERENCE,
  level: MemoryLevel.USER,  // explicit level
  userId: "user123",
  importance: 0.8,           // 0-1 scale
  tags: ["style", "javascript"]
});

Recalling Memories

// Semantic search across all levels
const memories = await th0th.recall({
  query: "How do we handle authentication?",
  limit: 5
});

// Filter by level
const projectMemories = await th0th.recall({
  query: "database setup",
  level: MemoryLevel.PROJECT,
  projectId: "my-app"
});

// Filter by type
const decisions = await th0th.recall({
  query: "architecture",
  type: MemoryType.DECISION
});

Updating Memories

Accessing a memory automatically updates accessCount and lastAccessed:
const memory = memories[0];

// Before: accessCount = 5, lastAccessed = 2 hours ago
// After recall: accessCount = 6, lastAccessed = now

// This boosts the memory in future recalls

Deleting Memories

// Delete specific memory
await th0th.forget(memoryId);

// Delete all session memories (cleanup)
await th0th.forgetSession(sessionId);

// Delete all project memories
await th0th.forgetProject(projectId);

Storage Schema

SQLite Table Structure

CREATE TABLE memories (
  id TEXT PRIMARY KEY,              -- Generated ID
  content TEXT NOT NULL,            -- The memory text
  type TEXT NOT NULL,               -- DECISION, PATTERN, etc.
  level TEXT NOT NULL,              -- L0, L1, L2, L3
  
  -- Scope identifiers
  user_id TEXT,
  session_id TEXT,
  project_id TEXT,
  agent_id TEXT,
  
  -- Ranking factors
  importance REAL DEFAULT 0.5,      -- Manual importance (0-1)
  embedding BLOB,                   -- Float32Array for similarity
  tags TEXT,                        -- JSON array of tags
  
  -- Temporal tracking
  created_at INTEGER NOT NULL,
  access_count INTEGER DEFAULT 0,
  last_accessed INTEGER
);

-- Indexes for fast retrieval
CREATE INDEX idx_mem_level ON memories(level);
CREATE INDEX idx_mem_project ON memories(project_id);
CREATE INDEX idx_mem_user ON memories(user_id);
CREATE INDEX idx_mem_type ON memories(type);
CREATE INDEX idx_mem_accessed ON memories(last_accessed);

ID Generation

Memory IDs are deterministic and include metadata:
function generateMemoryId(
  type: MemoryType,
  userId?: string
): string {
  const timestamp = Date.now();
  const random = Math.random().toString(36).substring(2, 8);
  const prefix = type.substring(0, 3);  // "dec", "pat", etc.
  const userPart = userId ? `_${userId.substring(0, 4)}` : "";
  
  return `${prefix}_${timestamp}_${random}${userPart}`;
}

// Example IDs:
// dec_1709876543210_x7k2f9
// pat_1709876543211_a3m8q5_user

Use Cases

1. Architecture Decisions

Scenario: Team decides to use microservices architecture.
// Store the decision
await th0th.remember({
  content: `
    Architecture decision: Adopt microservices pattern
    Reasoning: Need independent scaling of auth, payments, and core services
    Services: auth-service, payment-service, core-api
    Communication: REST + message queue (RabbitMQ)
  `,
  type: MemoryType.DECISION,
  level: MemoryLevel.PERSISTENT,
  projectId: "ecommerce-platform",
  importance: 1.0,
  tags: ["architecture", "microservices"]
});

// Later: AI assistant recalls this when asked about service structure
const context = await th0th.recall({
  query: "How are our services organized?",
  projectId: "ecommerce-platform"
});
// Returns the architecture decision automatically

2. Code Patterns

Scenario: Establish error handling pattern.
await th0th.remember({
  content: `
    Error handling pattern:
    - Use custom AppError class extending Error
    - All errors have: code, message, statusCode, isOperational
    - Centralized error handler in src/middleware/errorHandler.ts
    - Operational errors (user mistakes) vs programmer errors
  `,
  type: MemoryType.PATTERN,
  level: MemoryLevel.PROJECT,
  projectId: "api-server",
  tags: ["errors", "patterns"]
});

// AI remembers this pattern when writing new endpoints

3. User Preferences

Scenario: User’s coding style preferences.
await th0th.remember({
  content: `
    Code style preferences:
    - Use named exports over default exports
    - Prefer const over let
    - Always use TypeScript strict mode
    - Max line length: 100 characters
    - Use Prettier with single quotes
  `,
  type: MemoryType.PREFERENCE,
  level: MemoryLevel.USER,
  userId: "dev123",
  tags: ["style", "typescript"]
});

// Applied automatically when AI generates code for this user

4. Session Context

Scenario: Track current task.
await th0th.remember({
  content: "User is refactoring authentication to support OAuth2 alongside existing JWT auth",
  type: MemoryType.CONVERSATION,
  level: MemoryLevel.SESSION,
  sessionId: "sess_abc123"
});

// AI maintains this context throughout the session
// Auto-deleted when session ends

Best Practices

What to Remember

Decisions: Important architectural or technical choicesPatterns: Reusable code structures and idiomsContext: Project-specific conventions and locationsPreferences: User/team coding stylesLearnings: Solutions to tricky problems

What NOT to Remember

Ephemeral data: Temporary variable valuesCode dumps: Large code blocks (use indexing instead)Obvious facts: “Functions should have descriptive names”Duplicates: Check for similar memories firstSecrets: Never store API keys or credentials

Memory Hygiene

Regular cleanup: Delete outdated session memoriesMerge duplicates: Use clustering to find similar memoriesUpdate, don’t duplicate: Modify existing memories when info changesTag consistently: Use standard tags for easier retrievalSet importance: Mark critical memories with high importance

Performance

Retrieval Speed

5-10ms for semantic searchAll-in-memory vector comparison

Storage Efficiency

  • Memory row size: ~1-2KB (including embedding)
  • 1000 memories: ~1-2MB
  • 10,000 memories: ~10-20MB
Embeddings are the largest component. Consider using smaller models (384-dim vs 1024-dim) if storage is a concern.

Analytics

Track memory system usage:
const analytics = await th0th.getMemoryAnalytics();

console.log(analytics);
// {
//   totalMemories: 1247,
//   byLevel: {
//     L0: 23,   // Persistent
//     L1: 456,  // Project
//     L2: 89,   // User
//     L3: 679   // Session
//   },
//   byType: {
//     decision: 34,
//     pattern: 123,
//     code: 567,
//     preference: 45,
//     conversation: 478
//   },
//   avgAccessCount: 3.2,
//   topMemories: [
//     { id: "...", content: "...", accessCount: 45 }
//   ]
// }

Future Enhancements

  • Graph relationships: Link related memories (“X was decided because of Y”)
  • Automatic summarization: Compress old memories over time
  • Conflict detection: Warn when new memory contradicts old one
  • Memory chains: Track evolution of decisions over time
  • Collaborative memories: Team-shared memories (L2.5 level)

Semantic Search

Memory retrieval uses the same semantic search engine

Architecture

How memory fits into th0th’s overall architecture

API Reference

Complete memory API documentation

Development

Extending the memory system