Skip to main content
Glama
8b-is
by 8b-is
index.rs17 kB
use anyhow::{Context, Result}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fs; use std::path::{Path, PathBuf}; use uuid::Uuid; /// Master index for all .m8 memory blocks and user context #[derive(Debug, Serialize, Deserialize)] pub struct Mem8Index { /// Index metadata pub metadata: IndexMetadata, /// User profile with preferences, patterns, and quirks pub user_profile: UserProfile, /// All registered memory blocks pub memory_blocks: HashMap<Uuid, MemoryBlockEntry>, /// Active projects and their status pub projects: HashMap<String, ProjectContext>, /// Relationship graph between concepts, projects, and memories pub relationships: RelationshipGraph, /// Temporal index for time-based queries pub temporal_index: TemporalIndex, } #[derive(Debug, Serialize, Deserialize)] pub struct IndexMetadata { pub version: String, pub created_at: DateTime<Utc>, pub last_updated: DateTime<Utc>, pub total_memories: usize, pub total_conversations: usize, pub compression_ratio: f32, } #[derive(Debug, Serialize, Deserialize)] pub struct UserProfile { /// User's name or identifier pub name: String, /// Technology preferences pub preferences: TechPreferences, /// Communication patterns and triggers pub communication_style: CommunicationStyle, /// Learning progress and knowledge areas pub knowledge_map: KnowledgeMap, /// Personality insights from conversations pub personality_insights: PersonalityInsights, } #[derive(Debug, Serialize, Deserialize)] pub struct TechPreferences { /// Package managers (npm -> pnpm preference) pub package_managers: HashMap<String, PreferenceLevel>, /// Programming languages by preference pub languages: HashMap<String, PreferenceLevel>, /// Operating systems and reactions pub operating_systems: HashMap<String, OSPreference>, /// Development tools and IDEs pub tools: HashMap<String, PreferenceLevel>, /// Framework choices pub frameworks: HashMap<String, PreferenceLevel>, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct PreferenceLevel { pub preference: i8, // -10 (hate) to +10 (love) pub reasons: Vec<String>, pub context: Vec<String>, // When this preference applies } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct OSPreference { pub base_preference: i8, pub reactions: Vec<String>, // "Adverse reaction when over-discussing" pub nudge_strategy: Option<String>, // "Mention WSL for compatibility" pub compatibility_focus: bool, } #[derive(Debug, Serialize, Deserialize)] pub struct CommunicationStyle { /// Topics that trigger reactions pub trigger_topics: HashMap<String, ReactionPattern>, /// Preferred explanation depth pub detail_preference: DetailLevel, /// Humor tolerance and type pub humor_style: HumorStyle, /// Learning patterns pub learning_style: LearningStyle, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct ReactionPattern { pub topic: String, pub reaction_type: String, // "adverse", "enthusiastic", "skeptical" pub suggested_approach: Option<String>, pub examples: Vec<String>, } #[derive(Debug, Serialize, Deserialize)] pub enum DetailLevel { Concise, Balanced, Comprehensive, ExtremeDetail, } #[derive(Debug, Serialize, Deserialize)] pub struct HumorStyle { pub appreciates_puns: bool, pub dark_humor_tolerance: f32, pub technical_jokes: bool, pub pop_culture_references: bool, } #[derive(Debug, Serialize, Deserialize)] pub struct LearningStyle { pub prefers_examples: bool, pub learns_by_doing: bool, pub needs_theory_first: bool, pub pattern_recognition: f32, } #[derive(Debug, Serialize, Deserialize)] pub struct KnowledgeMap { /// Areas of expertise pub expertise: HashMap<String, ExpertiseLevel>, /// Current learning topics pub learning: HashMap<String, LearningProgress>, /// Completed projects/skills pub accomplished: Vec<String>, } #[derive(Debug, Serialize, Deserialize)] pub struct ExpertiseLevel { pub level: u8, // 0-10 pub demonstrated_in: Vec<Uuid>, // Memory block references pub key_insights: Vec<String>, } #[derive(Debug, Serialize, Deserialize)] pub struct LearningProgress { pub started: DateTime<Utc>, pub current_understanding: u8, // 0-10 pub blockers: Vec<String>, pub breakthrough_moments: Vec<String>, } #[derive(Debug, Serialize, Deserialize)] pub struct PersonalityInsights { /// Work style patterns pub work_style: WorkStyle, /// Problem-solving approach pub problem_solving: ProblemSolvingStyle, /// Collaboration preferences pub collaboration: CollaborationStyle, /// Stress indicators and management pub stress_patterns: StressPatterns, } #[derive(Debug, Serialize, Deserialize)] pub struct WorkStyle { pub perfectionist_score: f32, pub experimentation_willingness: f32, pub planning_vs_doing: f32, // -1 (all planning) to +1 (all doing) pub multitasking_preference: bool, } #[derive(Debug, Serialize, Deserialize)] pub struct ProblemSolvingStyle { pub bottom_up_vs_top_down: f32, // -1 to +1 pub research_first: bool, pub trial_and_error_comfort: f32, pub asks_for_help_threshold: f32, } #[derive(Debug, Serialize, Deserialize)] pub struct CollaborationStyle { pub prefers_autonomy: bool, pub pair_programming_comfort: f32, pub feedback_style: String, // "direct", "gentle", "humor-wrapped" pub teaching_enthusiasm: f32, } #[derive(Debug, Serialize, Deserialize)] pub struct StressPatterns { pub indicators: Vec<String>, // "Increased typos", "Shorter messages" pub triggers: Vec<String>, // "Deadlines", "Unclear requirements" pub coping_mechanisms: Vec<String>, // "Humor", "Deep technical dives" } #[derive(Debug, Serialize, Deserialize)] pub struct MemoryBlockEntry { pub id: Uuid, pub file_path: PathBuf, pub source_type: String, // "claude", "chatgpt", "local" pub created_at: DateTime<Utc>, pub message_count: usize, pub compressed_size: usize, pub tags: Vec<String>, pub summary: String, pub key_concepts: Vec<String>, } #[derive(Debug, Serialize, Deserialize)] pub struct ProjectContext { pub name: String, pub path: PathBuf, pub status: ProjectStatus, pub technologies: Vec<String>, pub current_focus: Option<String>, pub blockers: Vec<String>, pub last_worked: DateTime<Utc>, pub related_memories: Vec<Uuid>, pub notes: Vec<String>, } #[derive(Debug, Serialize, Deserialize)] pub enum ProjectStatus { Active, Paused, Completed, Archived, Planning, } #[derive(Debug, Serialize, Deserialize)] pub struct RelationshipGraph { /// Concept -> Related concepts with strength pub concept_links: HashMap<String, Vec<(String, f32)>>, /// Project -> Related projects pub project_links: HashMap<String, Vec<String>>, /// Memory blocks that reference each other pub memory_links: HashMap<Uuid, Vec<Uuid>>, } #[derive(Debug, Serialize, Deserialize)] pub struct TemporalIndex { /// Date -> Memory blocks created that day pub daily_index: HashMap<String, Vec<Uuid>>, /// Week -> Summary of that week's work pub weekly_summaries: HashMap<String, WeeklySummary>, /// Patterns by time of day pub circadian_patterns: CircadianPatterns, } #[derive(Debug, Serialize, Deserialize)] pub struct WeeklySummary { pub projects_touched: Vec<String>, pub concepts_explored: Vec<String>, pub breakthrough_moments: Vec<String>, pub total_messages: usize, } #[derive(Debug, Serialize, Deserialize)] pub struct CircadianPatterns { pub most_active_hours: Vec<u8>, pub deep_work_windows: Vec<(u8, u8)>, pub communication_peaks: Vec<u8>, } impl Mem8Index { /// Load or create index at ~/.mem8/index.m8 pub fn load_or_create() -> Result<Self> { let index_path = Self::index_path()?; if index_path.exists() { let data = fs::read(&index_path)?; let decompressed = zstd::decode_all(&data[..])?; let index = rmp_serde::from_slice(&decompressed)?; Ok(index) } else { Ok(Self::new()) } } /// Create new empty index pub fn new() -> Self { Self { metadata: IndexMetadata { version: "1.0.0".to_string(), created_at: Utc::now(), last_updated: Utc::now(), total_memories: 0, total_conversations: 0, compression_ratio: 0.0, }, user_profile: UserProfile::default(), memory_blocks: HashMap::new(), projects: HashMap::new(), relationships: RelationshipGraph { concept_links: HashMap::new(), project_links: HashMap::new(), memory_links: HashMap::new(), }, temporal_index: TemporalIndex { daily_index: HashMap::new(), weekly_summaries: HashMap::new(), circadian_patterns: CircadianPatterns { most_active_hours: vec![], deep_work_windows: vec![], communication_peaks: vec![], }, }, } } /// Save index to disk pub fn save(&self) -> Result<()> { let index_path = Self::index_path()?; // Ensure directory exists if let Some(parent) = index_path.parent() { fs::create_dir_all(parent)?; } // Serialize and compress let serialized = rmp_serde::to_vec(self)?; let compressed = zstd::encode_all(&serialized[..], 3)?; fs::write(&index_path, compressed)?; Ok(()) } /// Get index file path fn index_path() -> Result<PathBuf> { let home = dirs::home_dir() .context("Could not find home directory")?; Ok(home.join(".mem8").join("index.m8")) } /// Update from conversation analysis pub fn learn_from_conversation(&mut self, messages: &[Message]) { // Extract preferences for msg in messages { self.extract_preferences(&msg.content); self.extract_project_references(&msg.content); self.update_communication_patterns(&msg.content); } self.metadata.last_updated = Utc::now(); } fn extract_preferences(&mut self, content: &str) { // Example: Detect package manager preferences if content.contains("npm") && content.contains("hate") { self.user_profile.preferences.package_managers .entry("npm".to_string()) .or_insert(PreferenceLevel { preference: -8, reasons: vec!["Expressed hatred".to_string()], context: vec![], }) .preference = -8; } if content.contains("pnpm") && (content.contains("prefer") || content.contains("love")) { self.user_profile.preferences.package_managers .entry("pnpm".to_string()) .or_insert(PreferenceLevel { preference: 8, reasons: vec!["Expressed preference".to_string()], context: vec![], }) .preference = 8; } // Detect OS reactions if content.to_lowercase().contains("windows") { let words: Vec<&str> = content.split_whitespace().collect(); let window_pos = words.iter().position(|&w| w.to_lowercase().contains("windows")); if let Some(pos) = window_pos { // Check surrounding context for reaction let negative_words = ["hate", "dislike", "avoid", "annoying", "frustrating"]; let has_negative = words.iter().any(|w| negative_words.contains(&w.to_lowercase().as_str())); if has_negative { self.user_profile.preferences.operating_systems .entry("Windows".to_string()) .or_insert(OSPreference { base_preference: -5, reactions: vec!["Adverse reaction detected".to_string()], nudge_strategy: Some("Mention WSL for compatibility".to_string()), compatibility_focus: true, }); } } } } fn extract_project_references(&mut self, content: &str) { // Look for project paths let path_regex = regex::Regex::new(r"(?:^|[\s\"\'])((?:/[\w\-\.]+)+|(?:~/[\w\-\.]+)+)").unwrap(); for cap in path_regex.captures_iter(content) { if let Some(path_match) = cap.get(1) { let path = path_match.as_str(); if path.contains("source") || path.contains("project") { // Potential project reference let project_name = path.split('/').last().unwrap_or("unknown"); self.projects.entry(project_name.to_string()) .or_insert(ProjectContext { name: project_name.to_string(), path: PathBuf::from(path), status: ProjectStatus::Active, technologies: vec![], current_focus: None, blockers: vec![], last_worked: Utc::now(), related_memories: vec![], notes: vec![], }) .last_worked = Utc::now(); } } } } fn update_communication_patterns(&mut self, content: &str) { // This would analyze communication style, but keeping it simple for now let word_count = content.split_whitespace().count(); if word_count > 200 { self.user_profile.communication_style.detail_preference = DetailLevel::Comprehensive; } } } impl Default for UserProfile { fn default() -> Self { Self { name: String::from("User"), preferences: TechPreferences { package_managers: HashMap::new(), languages: HashMap::new(), operating_systems: HashMap::new(), tools: HashMap::new(), frameworks: HashMap::new(), }, communication_style: CommunicationStyle { trigger_topics: HashMap::new(), detail_preference: DetailLevel::Balanced, humor_style: HumorStyle { appreciates_puns: true, dark_humor_tolerance: 0.5, technical_jokes: true, pop_culture_references: true, }, learning_style: LearningStyle { prefers_examples: true, learns_by_doing: true, needs_theory_first: false, pattern_recognition: 0.8, }, }, knowledge_map: KnowledgeMap { expertise: HashMap::new(), learning: HashMap::new(), accomplished: vec![], }, personality_insights: PersonalityInsights { work_style: WorkStyle { perfectionist_score: 0.5, experimentation_willingness: 0.8, planning_vs_doing: 0.3, multitasking_preference: true, }, problem_solving: ProblemSolvingStyle { bottom_up_vs_top_down: 0.0, research_first: true, trial_and_error_comfort: 0.7, asks_for_help_threshold: 0.3, }, collaboration: CollaborationStyle { prefers_autonomy: false, pair_programming_comfort: 0.8, feedback_style: "direct".to_string(), teaching_enthusiasm: 0.9, }, stress_patterns: StressPatterns { indicators: vec![], triggers: vec![], coping_mechanisms: vec![], }, }, } } } #[derive(Debug, Serialize, Deserialize)] pub struct Message { pub role: String, pub content: String, pub timestamp: Option<i64>, }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/8b-is/smart-tree'

If you have feedback or need assistance with the MCP directory API, please join our Discord server