# TrueRecall v2 - Session Notes **Last Updated:** 2026-02-25 12:04 CST **Status:** βœ… **Context Injection FIXED & Working** **Version:** v2.2.1 (Post-fix validation) --- ## πŸ”₯ CRITICAL FIXES APPLIED (2026-02-25 12:00 CST) ### Issues Found & Fixed | Issue | Root Cause | Fix Applied | |-------|------------|-------------| | **Context injection broken** | Embedding model mismatch | βœ… Changed curator from `mxbai-embed-large` to `snowflake-arctic-embed2` | | **Gems had no vectors** | `store_gem()` used wrong field | βœ… Updated to use `text` field for embedding | | **JSON parsing errors** | Complex prompt causing LLM failures | βœ… Simplified extraction prompt | | **Field mismatch** | Memories have `text`, curator expected `content` | βœ… Curator now supports both `text` and `content` fields | | **Silent embedding failures** | No error logging | βœ… Added explicit error messages | | **Gem ID collision** | Hash used non-existent fields | βœ… Hash now uses `embedding_text_for_hash[:100]` | | **Meta-gems extracted** | Curator extracted from debug output | βœ… Added SKIP_PATTERNS filter | | **gems_tr pollution** | 5 meta-gems + 1 real gem | βœ… Cleaned, now 1 real gem only | | **First-person gems** | Third person format "User decided..." | βœ… Changed to "I decided..." for better matching | ### Validation Results ```bash # Test query: "OpenClaw gateway update fixed gems" # Result: Score 0.587 - SUCCESS βœ… ``` **Current State:** - βœ… Gems in `gems_tr` now have 1024-dim vectors - βœ… Context injection returns relevant gems with scores >0.5 - βœ… Curator extracting and storing gems successfully - βœ… All 5 fixes verified and working ### Files Modified | File | Change | |------|--------| | `tr-continuous/curator_timer.py` | Embedding model, field handling, JSON parsing | | `README.md` | Updated status and embedding model info | | `function_check.md` | Added fixes section, updated sign-off | | `session.md` | This update | --- ## Session End (18:09 CST) **Reason:** User starting new session **Current State:** - Real-time watcher: βœ… Active (capturing live) - Timer curator: βœ… Deployed (every 5 min via cron) - Daily curator: ❌ Removed (replaced by timer) - Total memories: 12,729 (1,502 uncurated, 11,227 curated) - Gems: 73 (actively extracting) **Next session start:** Read this file, then check: ```bash # Quick status python3 ~/.openclaw/workspace/.local_projects/true-recall-v2/tr-continuous/curator_timer.py --status sudo systemctl status mem-qdrant-watcher curl -s http://:6333/collections/memories_tr | jq '.result.points_count' ``` --- ## Executive Summary TrueRecall v2 is a complete memory system with real-time capture, daily curation, and context injection. All components are operational. --- ## Current State (Verified 18:09 CST) ### Qdrant Collections | Collection | Points | Purpose | Status | |------------|--------|---------|--------| | `memories_tr` | **12,729** | Full text (live capture) | βœ… Active | | `gems_tr` | **73** | Curated gems (injection) | βœ… Active | | `true_recall` | existing | Legacy archive | πŸ“¦ Preserved | | `kimi_memories` | 12,223 | Original backup | πŸ“¦ Preserved | **Note:** All memories tagged with `curated: false` for timer curator. ### Services | Service | Status | Uptime | |---------|--------|--------| | `mem-qdrant-watcher` | βœ… Active | 30+ min | | OpenClaw Gateway | βœ… Running | 2026.2.23 | | memory-qdrant plugin | βœ… Loaded | recall: gems_tr, capture: memories_tr | --- ## Architecture ### v2.2: Timer-Based Curation (DEPLOYED) **Data Flow:** ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ OpenClaw Chat │────▢│ Real-Time Watcher │────▢│ memories_tr β”‚ β”‚ (Session JSONL)β”‚ β”‚ (Python daemon) β”‚ β”‚ (Qdrant) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ Every 5 min β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Timer Curator β”‚ β”‚ (cron/qwen3) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ gems_tr β”‚ β”‚ (Qdrant) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ Per turn β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ memory-qdrant β”‚ β”‚ plugin β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Key Changes:** - βœ… Replaced daily 2:45 AM batch with 5-minute timer - βœ… All memories tagged `curated: false` on write - βœ… Migration completed for 12,378 existing memories - βœ… No Redis dependency (direct Qdrant only) --- ## Components ### Curation Mode: Timer-Based (DEPLOYED v2.2) | Setting | Value | Adjustable | |---------|-------|------------| | **Trigger** | Cron timer | βœ… | | **Interval** | 5 minutes | βœ… Config file | | **Batch size** | 100 memories max | βœ… Config file | | **Minimum** | None (0 is OK) | β€” | **Config:** `/tr-continuous/curator_config.json` ```json { "timer_minutes": 30, "max_batch_size": 100, "user_id": "rob", "source_collection": "memories_tr", "target_collection": "gems_tr" } ``` **Cron:** ``` */30 * * * * cd .../tr-continuous && python3 curator_timer.py ``` **Old modes deprecated:** - ❌ Turn-based (every N turns) - ❌ Hybrid (timer + turn) - ❌ Daily batch (2:45 AM) ### 1. Real-Time Watcher (Primary Capture) **Location:** `~/.openclaw/workspace/skills/qdrant-memory/scripts/realtime_qdrant_watcher.py` **Function:** - Watches `/root/.openclaw/agents/main/sessions/*.jsonl` - Parses every conversation turn in real-time - Embeds with `snowflake-arctic-embed2` (Ollama @ ) - Stores directly to `memories_tr` (no Redis) - **Cleans content:** Removes markdown, tables, metadata, thinking tags **Service:** `mem-qdrant-watcher.service` - **Status:** Active since 16:46:53 CST - **Systemd:** Enabled, auto-restart **Log:** `journalctl -u mem-qdrant-watcher -f` --- ### 2. Content Cleaner (Existing Data) **Location:** `~/.openclaw/workspace/skills/qdrant-memory/scripts/clean_memories_tr.py` **Function:** - Batch-cleans existing `memories_tr` points - Removes: `**bold**`, `|tables|`, `` `code` ``, `---` rules, `# headers` - Flattens nested content dicts - Rate-limited to prevent Qdrant overload **Usage:** ```bash # Dry run (preview) python3 clean_memories_tr.py --dry-run # Clean all python3 clean_memories_tr.py --execute # Clean limited (test) python3 clean_memories_tr.py --execute --limit 100 ``` --- ### 3. Timer Curator (v2.2 - DEPLOYED) **Replaces:** Daily curator (2:45 AM batch) and turn-based curator **Location:** `~/.openclaw/workspace/.local_projects/true-recall-v2/tr-continuous/curator_timer.py` **Schedule:** Every 30 minutes (cron) **Flow:** 1. Query uncurated memories (`curated: false`) 2. Send batch to qwen3 (max 100) 3. Extract gems using curator prompt 4. Store gems to `gems_tr` 5. Mark processed memories as `curated: true` **Files:** | File | Purpose | |------|---------| | `curator_timer.py` | Main curator script | | `curator_config.json` | Adjustable settings | | `migrate_add_curated.py` | One-time migration (completed) | **Usage:** ```bash # Dry run (preview) python3 curator_timer.py --dry-run # Manual run python3 curator_timer.py --config curator_config.json ``` **Status:** βœ… Deployed, first run will process ~12,378 existing memories ### 5. Silent Compacting (NEW - Concept) **Idea:** Automatically remove old context from prompt when token limit approached. **Behavior:** - Trigger: Context window > 80% full - Action: Remove oldest messages (silently) - Preserve: Gems always kept, recent N turns kept - Result: Seamless conversation without "compacting" notification **Config:** ```json { "compacting": { "enabled": true, "triggerAtPercent": 80, "keepRecentTurns": 20, "preserveGems": true, "silent": true } } ``` **Status:** ⏳ Concept only - requires OpenClaw core changes ### 6. memory-qdrant Plugin **Location:** `/root/.openclaw/extensions/memory-qdrant/` **Config:** ```json { "collectionName": "gems_tr", "captureCollection": "memories_tr", "autoRecall": true, "autoCapture": true } ``` **Function:** - **Recall:** Searches `gems_tr`, injects as context (hidden) - **Capture:** Session-level capture to `memories_tr` (backup) **Status:** Loaded, dual collection support working --- ## Files & Locations ### Core Project Files ``` ~/.openclaw/workspace/.local_projects/true-recall-v2/ β”œβ”€β”€ README.md # Architecture docs β”œβ”€β”€ session.md # This file β”œβ”€β”€ curator-prompt.md # Gem extraction prompt β”œβ”€β”€ tr-daily/ # Daily batch curation β”‚ └── curate_from_qdrant.py # Daily curator (2:45 AM) β”œβ”€β”€ tr-continuous/ # Real-time curation (NEW) β”‚ β”œβ”€β”€ curator_by_count.py # Turn-based curator β”‚ β”œβ”€β”€ curator_turn_based.py # Alternative approach β”‚ β”œβ”€β”€ curator_cron.sh # Cron wrapper β”‚ β”œβ”€β”€ turn-curator.service # Systemd service β”‚ └── README.md # Documentation └── shared/ └── (shared resources) ``` ### New Files (2026-02-24 19:00) | File | Purpose | |------|---------| | `tr-continuous/curator_timer.py` | Timer-based curator (deployed) | | `tr-continuous/curator_config.json` | Curator settings | | `tr-continuous/migrate_add_curated.py` | Migration script (completed) | ### Legacy Files (Pre-v2.2) | File | Status | Note | |------|--------|------| | `tr-daily/curate_from_qdrant.py` | πŸ“¦ Archived | Replaced by timer | | `tr-continuous/curator_by_count.py` | πŸ“¦ Archived | Replaced by timer | | `tr-continuous/curator_turn_based.py` | πŸ“¦ Archived | Replaced by timer | ### System Locations | File | Purpose | |------|---------| | `/root/.openclaw/extensions/memory-qdrant/` | Plugin code | | `/root/.openclaw/openclaw.json` | Plugin configuration | | `/etc/systemd/system/mem-qdrant-watcher.service` | Systemd service | --- ## πŸ”₯ CRITICAL FIXES APPLIED (2026-02-25 12:00-12:41 CST) ### Issues Found & Fixed Today | Issue | Root Cause | Fix Applied | |-------|------------|-------------| | **Watcher stuck on old session** | Watcher only checked for new sessions when current file deleted | βœ… Restarted watcher, now follows current session (12:22) | | **Plugin capture 0 exchanges** | OpenClaw changed to OpenAI content format (array), plugin expected string | βœ… Added `extractMessageText()` to parse content arrays (12:34) | | **Session switching logic** | Old sessions persisted, watcher never switched | βœ… Fixed session detection logic in watcher | | **Plugin content extraction** | `msg.content` is now array with `{type, text}` items | βœ… Extracts text from `type: "text"` items | ### Validation Results (2026-02-25 12:41) ``` memory-qdrant: parsed 17 user, 116 assistant messages, 9 exchanges memory-qdrant: first msg role=user, contentType=array ``` **Before:** 0 exchanges extracted **After:** 9 exchanges captured per session ### Components Status | Component | Before | After | Status | |-----------|--------|-------|--------| | Real-time watcher | Stuck on Feb 24 session | Following current session | βœ… Fixed | | Plugin capture | 0 exchanges | 9 exchanges | βœ… Fixed | | Context injection | Working | Still working | βœ… Verified | ### Files Modified (2026-02-25) | File | Change | |------|--------| | `extensions/memory-qdrant/index.ts` | Added `extractMessageText()` function, removed debug logging | | `extensions/memory-qdrant/index.js` | Compiled TypeScript changes | | `session.md` | This update | | `function_check.md` | Added fixes section | --- ## Changes Made Today (2026-02-24 19:00) ### 1. Timer Curator Deployed (v2.2) - Created `curator_timer.py` β€” simplified timer-based curation - Created `curator_config.json` β€” adjustable settings - Removed daily 2:45 AM cron job - Added `*/30 * * * *` cron timer - **Status:** βœ… Deployed, logs to `/var/log/true-recall-timer.log` ### 2. Migration Completed - Created `migrate_add_curated.py` - Tagged 12,378 existing memories with `curated: false` - Updated watcher to add `curated: false` to new memories - **Status:** βœ… Complete ### 3. Simplified Architecture - ❌ Removed turn-based curator complexity - ❌ Removed daily batch processing - βœ… Single timer trigger every 30 minutes - βœ… No minimum threshold (processes 0-N memories) --- ## Configuration ### memory-qdrant Plugin **File:** `/root/.openclaw/openclaw.json` ```json { "memory-qdrant": { "config": { "autoCapture": true, "autoRecall": true, "collectionName": "gems_tr", "captureCollection": "memories_tr", "embeddingModel": "snowflake-arctic-embed2", "maxRecallResults": 2, "minRecallScore": 0.7, "ollamaUrl": "http://:11434", "qdrantUrl": "http://:6333" }, "enabled": true } } ``` ### Gateway (OpenClaw Update Fix) ```json { "gateway": { "controlUi": { "allowedOrigins": ["*"], "allowInsecureAuth": false, "dangerouslyDisableDeviceAuth": true } } } ``` --- ## Validation Commands ### Check Collections ```bash # Points count curl -s http://:6333/collections/memories_tr | jq '.result.points_count' curl -s http://:6333/collections/gems_tr | jq '.result.points_count' # Recent points curl -s -X POST http://:6333/collections/memories_tr/points/scroll \ -H "Content-Type: application/json" \ -d '{"limit": 5, "with_payload": true}' | jq '.result.points[].payload.content' ``` ### Check Services ```bash # Watcher status sudo systemctl status mem-qdrant-watcher # Watcher logs sudo journalctl -u mem-qdrant-watcher -n 20 # OpenClaw status openclaw status ``` --- ## Troubleshooting ### Issue: Watcher Not Capturing **Check:** 1. Service running? `systemctl status mem-qdrant-watcher` 2. Logs: `journalctl -u mem-qdrant-watcher -f` 3. Qdrant accessible? `curl http://:6333/` 4. Ollama accessible? `curl http://:11434/api/tags` ### Issue: Cleaner Fails **Common causes:** - Qdrant connection timeout (add `time.sleep(0.1)` between batches) - Nested content dicts (handled in updated script) - Type errors (non-string content β€” handled) ### Issue: Plugin Not Loading **Check:** 1. `openclaw.json` syntax valid? `openclaw config validate` 2. Plugin compiled? `cd /root/.openclaw/extensions/memory-qdrant && npx tsc` 3. Gateway logs: `tail /tmp/openclaw/openclaw-$(date +%Y-%m-%d).log` --- ## Cron Schedule (Updated v2.2) | Time | Job | Script | Status | |------|-----|--------|--------| | Every 30 min | Timer curator | `tr-continuous/curator_timer.py` | βœ… Active | | Per turn | Capture | `mem-qdrant-watcher` | βœ… Daemon | | Per turn | Injection | `memory-qdrant` plugin | βœ… Active | **Removed:** - ❌ 2:45 AM daily curator - ❌ Every-minute turn curator check --- ## Next Steps ### Immediate - ⏳ Monitor first timer run (logs: `/var/log/true-recall-timer.log`) - ⏳ Validate gem extraction quality from timer curator - ⏳ Archive old curator scripts if timer works ### Completed βœ… - βœ… **Compactor config** β€” Minimal overhead: `mode: default`, `reserveTokensFloor: 0`, `memoryFlush: false` ### Future - ⏳ Curator tuning based on timer results - ⏳ Silent compacting (requires OpenClaw core changes) ### Planned Features (Backlog) - ⏳ **Interactive install script** β€” Prompts for embedding model, timer interval, batch size, endpoints - ⏳ **Single embedding model option** β€” Use one model for both collections - ⏳ **Configurable thresholds** β€” Per-user customization via prompts **Compactor Settings (Applied):** ```json5 { agents: { defaults: { compaction: { mode: "default", reserveTokensFloor: 0, memoryFlush: { enabled: false } } } } } ``` **Note:** Only `mode`, `reserveTokensFloor`, and `memoryFlush` are valid under `agents.defaults.compaction`. Other settings are Pi runtime parameters. **Install script prompts:** 1. Embedding model (snowflake vs mxbai) 2. Timer interval (5 min / 30 min / hourly) 3. Batch size (50 / 100 / 500) 4. Qdrant/Ollama URLs 5. User ID --- ## Session Recovery If starting fresh: 1. Read `README.md` for architecture overview 2. Check service status: `sudo systemctl status mem-qdrant-watcher` 3. Check timer curator: `tail /var/log/true-recall-timer.log` 4. Verify collections: `curl http://:6333/collections` --- *Last Verified: 2026-02-24 19:29 CST* *Version: v2.2 (30b curator, install script planned)*