Memory files now reconcile to template, not just clean known fields: - normalize.py: rewrote from field-targeted cleanup to template-conformance — strips ANY key not in the template at every level (root/metadata/limits/status). Kills legacy orphans (old 'st' blocks, active_tasks, current_lines, max_lines) that field-targeted cleanup was blind to. Fixed _MEMORY_ROOT path (parents[3]) that silently skipped template loading in production. - memory_watcher.py: wired normalize_memory_file into both scan paths (check_and_rollover + on_modified) with a write-loop guard — drift now self-heals on every trigger, no manual run needed. - line_counter.py: stop writing current_lines (entry-count is the only metric). - LOCAL/OBSERVATIONS templates: removed line-count fields. Entry-count is the sole rollover metric, both files, all branches. 873 tests pass, seedgo 100%. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
MEMORY
Central memory archive — vector search, rollover, and memory management for all AIPass branches.
drone @memory <command> | Module: aipass.memory | Created: 2026-03-07
Commands
drone @memory rollover run # Execute rollover for files over limits
drone @memory rollover status # Show per-branch rollover statistics
drone @memory rollover check # Dry run — what needs rollover
drone @memory rollover sync-lines # Update line count metadata
drone @memory search "query" # Semantic search across all branch memories
drone @memory search "query" --branch X # Filter by branch
drone @memory search "query" --n 10 # Limit results
drone @memory symbolic demo # Mock analysis demonstration
drone @memory symbolic fragments "query" # Search stored symbolic fragments
drone @memory symbolic extract <file> # Extract fragments via LLM (requires API key)
drone @memory symbolic bootstrap # Populate fragments from session JSONLs
drone @memory symbolic hook-test # Test hook with sample conversation text
drone @memory templates push-templates # Push template updates to all branches
drone @memory templates diff-templates # Show template differences per branch
drone @memory templates template-status # Show template version and push status
drone @memory verify FPLAN-XXXX # Check if plan is vectorized in ChromaDB
drone @memory watch # Auto-rollover watcher daemon (Ctrl+C to stop)
Architecture
memory/
├── apps/
│ ├── memory.py # Entry point — auto-discovers modules
│ ├── modules/ # 5 modules
│ │ ├── rollover.py # Rollover orchestration, status, sync-lines
│ │ ├── search.py # Semantic query routing
│ │ ├── symbolic.py # Fragmented memory extraction and search
│ │ ├── templates.py # Template push, diff, status
│ │ └── verify.py # Plan vectorization check
│ └── handlers/ # 14 handler groups
│ ├── archive/ # indexer.py
│ ├── intake/ # plans_processor.py, pool_processor.py
│ ├── json/ # json_handler.py, memory_files.py
│ ├── learnings/ # manager.py
│ ├── monitor/ # detector.py, memory_watcher.py
│ ├── rollover/ # extractor.py, orchestrator.py
│ ├── schema/ # normalize.py
│ ├── search/ # query_executor.py, vector_search.py
│ ├── storage/ # chroma.py, chroma_subprocess.py
│ ├── symbolic/ # chroma_client, deduplicator, extractor, hook, retriever, storage
│ ├── templates/ # pusher.py, differ.py, spawn_pusher.py
│ ├── tracking/ # line_counter.py
│ ├── vector/ # embedder.py, embed_subprocess.py
│ └── central_writer.py
├── config/ # memory.config.json — per-branch rollover limits
├── templates/ # LOCAL.template.json, OBSERVATIONS.template.json
├── tests/ # 839 tests (28 test files)
├── .chroma/ # ChromaDB vector store
└── memory_json/ # Operation log files (auto-created)
Rollover Pipeline
detector.check_all_branches() # scan AIPASS_REGISTRY.json + external registries
→ _should_rollover(file) # v1: line_count >= max_lines (600)
# v2: len(sessions) >= max_sessions (20)
→ orchestrator.execute_rollover()
→ create_rollover_backup() # safety copy to branch/.backup/
→ extract_items() # v2: max(excess, 1) oldest entries
→ embed via subprocess # fastembed (ONNX) in memory .venv
→ upsert in ChromaDB # content-hash IDs (sha256[:16]), no duplicates
→ trim source file # write back with oldest removed
Subprocess Isolation
All ML operations (fastembed, chromadb) run via subprocess. The main process never imports these libraries. Python interpreter resolved via _get_memory_python() (env var AIPASS_MEMORY_PYTHON → memory/.venv/bin/python → sys.executable).
Integration Points
Depends on:
prax— logging viaget_system_logger()api— API key for symbolic extraction (get_api_key())AIPASS_REGISTRY.json— branch discovery for rollover scanning- External
*_REGISTRY.json— scanned viaAIPASS_CALLER_CWD
Provides to:
- All branches — rollover archival when
.trinity/files hit limits - All branches — semantic search across archived memories
- All branches —
.trinity/template distribution and sync
ML dependencies (memory .venv/ only):
fastembed— ONNX embeddings (model:sentence-transformers/all-MiniLM-L6-v2)chromadb— vector storage and semantic searchnumpy
Quality
- Tests: 839 passed, 0 failures, 0 skips
- Test files: 28
- Seedgo: 100% — maintained since s12
Known Issues
searchrequires fastembed in memory.venv/— fails without itrollover statusshows 0 branches when registry path not resolvedmemory_threshold_exceededtrigger event registered but never fired
Last Updated: 2026-05-16