This is page 28 of 35. Use http://codebase.md/doobidoo/mcp-memory-service?lines=false&page={x} to view the full context.
# Directory Structure
```
├── .claude
│ ├── agents
│ │ ├── amp-bridge.md
│ │ ├── amp-pr-automator.md
│ │ ├── code-quality-guard.md
│ │ ├── gemini-pr-automator.md
│ │ └── github-release-manager.md
│ ├── settings.local.json.backup
│ └── settings.local.json.local
├── .commit-message
├── .dockerignore
├── .env.example
├── .env.sqlite.backup
├── .envnn#
├── .gitattributes
├── .github
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ ├── feature_request.yml
│ │ └── performance_issue.yml
│ ├── pull_request_template.md
│ └── workflows
│ ├── bridge-tests.yml
│ ├── CACHE_FIX.md
│ ├── claude-code-review.yml
│ ├── claude.yml
│ ├── cleanup-images.yml.disabled
│ ├── dev-setup-validation.yml
│ ├── docker-publish.yml
│ ├── LATEST_FIXES.md
│ ├── main-optimized.yml.disabled
│ ├── main.yml
│ ├── publish-and-test.yml
│ ├── README_OPTIMIZATION.md
│ ├── release-tag.yml.disabled
│ ├── release.yml
│ ├── roadmap-review-reminder.yml
│ ├── SECRET_CONDITIONAL_FIX.md
│ └── WORKFLOW_FIXES.md
├── .gitignore
├── .mcp.json.backup
├── .mcp.json.template
├── .pyscn
│ ├── .gitignore
│ └── reports
│ └── analyze_20251123_214224.html
├── AGENTS.md
├── archive
│ ├── deployment
│ │ ├── deploy_fastmcp_fixed.sh
│ │ ├── deploy_http_with_mcp.sh
│ │ └── deploy_mcp_v4.sh
│ ├── deployment-configs
│ │ ├── empty_config.yml
│ │ └── smithery.yaml
│ ├── development
│ │ └── test_fastmcp.py
│ ├── docs-removed-2025-08-23
│ │ ├── authentication.md
│ │ ├── claude_integration.md
│ │ ├── claude-code-compatibility.md
│ │ ├── claude-code-integration.md
│ │ ├── claude-code-quickstart.md
│ │ ├── claude-desktop-setup.md
│ │ ├── complete-setup-guide.md
│ │ ├── database-synchronization.md
│ │ ├── development
│ │ │ ├── autonomous-memory-consolidation.md
│ │ │ ├── CLEANUP_PLAN.md
│ │ │ ├── CLEANUP_README.md
│ │ │ ├── CLEANUP_SUMMARY.md
│ │ │ ├── dream-inspired-memory-consolidation.md
│ │ │ ├── hybrid-slm-memory-consolidation.md
│ │ │ ├── mcp-milestone.md
│ │ │ ├── multi-client-architecture.md
│ │ │ ├── test-results.md
│ │ │ └── TIMESTAMP_FIX_SUMMARY.md
│ │ ├── distributed-sync.md
│ │ ├── invocation_guide.md
│ │ ├── macos-intel.md
│ │ ├── master-guide.md
│ │ ├── mcp-client-configuration.md
│ │ ├── multi-client-server.md
│ │ ├── service-installation.md
│ │ ├── sessions
│ │ │ └── MCP_ENHANCEMENT_SESSION_MEMORY_v4.1.0.md
│ │ ├── UBUNTU_SETUP.md
│ │ ├── ubuntu.md
│ │ ├── windows-setup.md
│ │ └── windows.md
│ ├── docs-root-cleanup-2025-08-23
│ │ ├── AWESOME_LIST_SUBMISSION.md
│ │ ├── CLOUDFLARE_IMPLEMENTATION.md
│ │ ├── DOCUMENTATION_ANALYSIS.md
│ │ ├── DOCUMENTATION_CLEANUP_PLAN.md
│ │ ├── DOCUMENTATION_CONSOLIDATION_COMPLETE.md
│ │ ├── LITESTREAM_SETUP_GUIDE.md
│ │ ├── lm_studio_system_prompt.md
│ │ ├── PYTORCH_DOWNLOAD_FIX.md
│ │ └── README-ORIGINAL-BACKUP.md
│ ├── investigations
│ │ └── MACOS_HOOKS_INVESTIGATION.md
│ ├── litestream-configs-v6.3.0
│ │ ├── install_service.sh
│ │ ├── litestream_master_config_fixed.yml
│ │ ├── litestream_master_config.yml
│ │ ├── litestream_replica_config_fixed.yml
│ │ ├── litestream_replica_config.yml
│ │ ├── litestream_replica_simple.yml
│ │ ├── litestream-http.service
│ │ ├── litestream.service
│ │ └── requirements-cloudflare.txt
│ ├── release-notes
│ │ └── release-notes-v7.1.4.md
│ └── setup-development
│ ├── README.md
│ ├── setup_consolidation_mdns.sh
│ ├── STARTUP_SETUP_GUIDE.md
│ └── test_service.sh
├── CHANGELOG-HISTORIC.md
├── CHANGELOG.md
├── claude_commands
│ ├── memory-context.md
│ ├── memory-health.md
│ ├── memory-ingest-dir.md
│ ├── memory-ingest.md
│ ├── memory-recall.md
│ ├── memory-search.md
│ ├── memory-store.md
│ ├── README.md
│ └── session-start.md
├── claude-hooks
│ ├── config.json
│ ├── config.template.json
│ ├── CONFIGURATION.md
│ ├── core
│ │ ├── memory-retrieval.js
│ │ ├── mid-conversation.js
│ │ ├── session-end.js
│ │ ├── session-start.js
│ │ └── topic-change.js
│ ├── debug-pattern-test.js
│ ├── install_claude_hooks_windows.ps1
│ ├── install_hooks.py
│ ├── memory-mode-controller.js
│ ├── MIGRATION.md
│ ├── README-NATURAL-TRIGGERS.md
│ ├── README-phase2.md
│ ├── README.md
│ ├── simple-test.js
│ ├── statusline.sh
│ ├── test-adaptive-weights.js
│ ├── test-dual-protocol-hook.js
│ ├── test-mcp-hook.js
│ ├── test-natural-triggers.js
│ ├── test-recency-scoring.js
│ ├── tests
│ │ ├── integration-test.js
│ │ ├── phase2-integration-test.js
│ │ ├── test-code-execution.js
│ │ ├── test-cross-session.json
│ │ ├── test-session-tracking.json
│ │ └── test-threading.json
│ ├── utilities
│ │ ├── adaptive-pattern-detector.js
│ │ ├── context-formatter.js
│ │ ├── context-shift-detector.js
│ │ ├── conversation-analyzer.js
│ │ ├── dynamic-context-updater.js
│ │ ├── git-analyzer.js
│ │ ├── mcp-client.js
│ │ ├── memory-client.js
│ │ ├── memory-scorer.js
│ │ ├── performance-manager.js
│ │ ├── project-detector.js
│ │ ├── session-tracker.js
│ │ ├── tiered-conversation-monitor.js
│ │ └── version-checker.js
│ └── WINDOWS-SESSIONSTART-BUG.md
├── CLAUDE.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Development-Sprint-November-2025.md
├── docs
│ ├── amp-cli-bridge.md
│ ├── api
│ │ ├── code-execution-interface.md
│ │ ├── memory-metadata-api.md
│ │ ├── PHASE1_IMPLEMENTATION_SUMMARY.md
│ │ ├── PHASE2_IMPLEMENTATION_SUMMARY.md
│ │ ├── PHASE2_REPORT.md
│ │ └── tag-standardization.md
│ ├── architecture
│ │ ├── search-enhancement-spec.md
│ │ └── search-examples.md
│ ├── architecture.md
│ ├── archive
│ │ └── obsolete-workflows
│ │ ├── load_memory_context.md
│ │ └── README.md
│ ├── assets
│ │ └── images
│ │ ├── dashboard-v3.3.0-preview.png
│ │ ├── memory-awareness-hooks-example.png
│ │ ├── project-infographic.svg
│ │ └── README.md
│ ├── CLAUDE_CODE_QUICK_REFERENCE.md
│ ├── cloudflare-setup.md
│ ├── deployment
│ │ ├── docker.md
│ │ ├── dual-service.md
│ │ ├── production-guide.md
│ │ └── systemd-service.md
│ ├── development
│ │ ├── ai-agent-instructions.md
│ │ ├── code-quality
│ │ │ ├── phase-2a-completion.md
│ │ │ ├── phase-2a-handle-get-prompt.md
│ │ │ ├── phase-2a-index.md
│ │ │ ├── phase-2a-install-package.md
│ │ │ └── phase-2b-session-summary.md
│ │ ├── code-quality-workflow.md
│ │ ├── dashboard-workflow.md
│ │ ├── issue-management.md
│ │ ├── pr-review-guide.md
│ │ ├── refactoring-notes.md
│ │ ├── release-checklist.md
│ │ └── todo-tracker.md
│ ├── docker-optimized-build.md
│ ├── document-ingestion.md
│ ├── DOCUMENTATION_AUDIT.md
│ ├── enhancement-roadmap-issue-14.md
│ ├── examples
│ │ ├── analysis-scripts.js
│ │ ├── maintenance-session-example.md
│ │ ├── memory-distribution-chart.jsx
│ │ └── tag-schema.json
│ ├── first-time-setup.md
│ ├── glama-deployment.md
│ ├── guides
│ │ ├── advanced-command-examples.md
│ │ ├── chromadb-migration.md
│ │ ├── commands-vs-mcp-server.md
│ │ ├── mcp-enhancements.md
│ │ ├── mdns-service-discovery.md
│ │ ├── memory-consolidation-guide.md
│ │ ├── migration.md
│ │ ├── scripts.md
│ │ └── STORAGE_BACKENDS.md
│ ├── HOOK_IMPROVEMENTS.md
│ ├── hooks
│ │ └── phase2-code-execution-migration.md
│ ├── http-server-management.md
│ ├── ide-compatability.md
│ ├── IMAGE_RETENTION_POLICY.md
│ ├── images
│ │ └── dashboard-placeholder.md
│ ├── implementation
│ │ ├── health_checks.md
│ │ └── performance.md
│ ├── IMPLEMENTATION_PLAN_HTTP_SSE.md
│ ├── integration
│ │ ├── homebrew.md
│ │ └── multi-client.md
│ ├── integrations
│ │ ├── gemini.md
│ │ ├── groq-bridge.md
│ │ ├── groq-integration-summary.md
│ │ └── groq-model-comparison.md
│ ├── integrations.md
│ ├── legacy
│ │ └── dual-protocol-hooks.md
│ ├── LM_STUDIO_COMPATIBILITY.md
│ ├── maintenance
│ │ └── memory-maintenance.md
│ ├── mastery
│ │ ├── api-reference.md
│ │ ├── architecture-overview.md
│ │ ├── configuration-guide.md
│ │ ├── local-setup-and-run.md
│ │ ├── testing-guide.md
│ │ └── troubleshooting.md
│ ├── migration
│ │ └── code-execution-api-quick-start.md
│ ├── natural-memory-triggers
│ │ ├── cli-reference.md
│ │ ├── installation-guide.md
│ │ └── performance-optimization.md
│ ├── oauth-setup.md
│ ├── pr-graphql-integration.md
│ ├── quick-setup-cloudflare-dual-environment.md
│ ├── README.md
│ ├── remote-configuration-wiki-section.md
│ ├── research
│ │ ├── code-execution-interface-implementation.md
│ │ └── code-execution-interface-summary.md
│ ├── ROADMAP.md
│ ├── sqlite-vec-backend.md
│ ├── statistics
│ │ ├── charts
│ │ │ ├── activity_patterns.png
│ │ │ ├── contributors.png
│ │ │ ├── growth_trajectory.png
│ │ │ ├── monthly_activity.png
│ │ │ └── october_sprint.png
│ │ ├── data
│ │ │ ├── activity_by_day.csv
│ │ │ ├── activity_by_hour.csv
│ │ │ ├── contributors.csv
│ │ │ └── monthly_activity.csv
│ │ ├── generate_charts.py
│ │ └── REPOSITORY_STATISTICS.md
│ ├── technical
│ │ ├── development.md
│ │ ├── memory-migration.md
│ │ ├── migration-log.md
│ │ ├── sqlite-vec-embedding-fixes.md
│ │ └── tag-storage.md
│ ├── testing
│ │ └── regression-tests.md
│ ├── testing-cloudflare-backend.md
│ ├── troubleshooting
│ │ ├── cloudflare-api-token-setup.md
│ │ ├── cloudflare-authentication.md
│ │ ├── general.md
│ │ ├── hooks-quick-reference.md
│ │ ├── pr162-schema-caching-issue.md
│ │ ├── session-end-hooks.md
│ │ └── sync-issues.md
│ └── tutorials
│ ├── advanced-techniques.md
│ ├── data-analysis.md
│ └── demo-session-walkthrough.md
├── examples
│ ├── claude_desktop_config_template.json
│ ├── claude_desktop_config_windows.json
│ ├── claude-desktop-http-config.json
│ ├── config
│ │ └── claude_desktop_config.json
│ ├── http-mcp-bridge.js
│ ├── memory_export_template.json
│ ├── README.md
│ ├── setup
│ │ └── setup_multi_client_complete.py
│ └── start_https_example.sh
├── install_service.py
├── install.py
├── LICENSE
├── NOTICE
├── pyproject.toml
├── pytest.ini
├── README.md
├── run_server.py
├── scripts
│ ├── .claude
│ │ └── settings.local.json
│ ├── archive
│ │ └── check_missing_timestamps.py
│ ├── backup
│ │ ├── backup_memories.py
│ │ ├── backup_sqlite_vec.sh
│ │ ├── export_distributable_memories.sh
│ │ └── restore_memories.py
│ ├── benchmarks
│ │ ├── benchmark_code_execution_api.py
│ │ ├── benchmark_hybrid_sync.py
│ │ └── benchmark_server_caching.py
│ ├── database
│ │ ├── analyze_sqlite_vec_db.py
│ │ ├── check_sqlite_vec_status.py
│ │ ├── db_health_check.py
│ │ └── simple_timestamp_check.py
│ ├── development
│ │ ├── debug_server_initialization.py
│ │ ├── find_orphaned_files.py
│ │ ├── fix_mdns.sh
│ │ ├── fix_sitecustomize.py
│ │ ├── remote_ingest.sh
│ │ ├── setup-git-merge-drivers.sh
│ │ ├── uv-lock-merge.sh
│ │ └── verify_hybrid_sync.py
│ ├── hooks
│ │ └── pre-commit
│ ├── installation
│ │ ├── install_linux_service.py
│ │ ├── install_macos_service.py
│ │ ├── install_uv.py
│ │ ├── install_windows_service.py
│ │ ├── install.py
│ │ ├── setup_backup_cron.sh
│ │ ├── setup_claude_mcp.sh
│ │ └── setup_cloudflare_resources.py
│ ├── linux
│ │ ├── service_status.sh
│ │ ├── start_service.sh
│ │ ├── stop_service.sh
│ │ ├── uninstall_service.sh
│ │ └── view_logs.sh
│ ├── maintenance
│ │ ├── assign_memory_types.py
│ │ ├── check_memory_types.py
│ │ ├── cleanup_corrupted_encoding.py
│ │ ├── cleanup_memories.py
│ │ ├── cleanup_organize.py
│ │ ├── consolidate_memory_types.py
│ │ ├── consolidation_mappings.json
│ │ ├── delete_orphaned_vectors_fixed.py
│ │ ├── fast_cleanup_duplicates_with_tracking.sh
│ │ ├── find_all_duplicates.py
│ │ ├── find_cloudflare_duplicates.py
│ │ ├── find_duplicates.py
│ │ ├── memory-types.md
│ │ ├── README.md
│ │ ├── recover_timestamps_from_cloudflare.py
│ │ ├── regenerate_embeddings.py
│ │ ├── repair_malformed_tags.py
│ │ ├── repair_memories.py
│ │ ├── repair_sqlite_vec_embeddings.py
│ │ ├── repair_zero_embeddings.py
│ │ ├── restore_from_json_export.py
│ │ └── scan_todos.sh
│ ├── migration
│ │ ├── cleanup_mcp_timestamps.py
│ │ ├── legacy
│ │ │ └── migrate_chroma_to_sqlite.py
│ │ ├── mcp-migration.py
│ │ ├── migrate_sqlite_vec_embeddings.py
│ │ ├── migrate_storage.py
│ │ ├── migrate_tags.py
│ │ ├── migrate_timestamps.py
│ │ ├── migrate_to_cloudflare.py
│ │ ├── migrate_to_sqlite_vec.py
│ │ ├── migrate_v5_enhanced.py
│ │ ├── TIMESTAMP_CLEANUP_README.md
│ │ └── verify_mcp_timestamps.py
│ ├── pr
│ │ ├── amp_collect_results.sh
│ │ ├── amp_detect_breaking_changes.sh
│ │ ├── amp_generate_tests.sh
│ │ ├── amp_pr_review.sh
│ │ ├── amp_quality_gate.sh
│ │ ├── amp_suggest_fixes.sh
│ │ ├── auto_review.sh
│ │ ├── detect_breaking_changes.sh
│ │ ├── generate_tests.sh
│ │ ├── lib
│ │ │ └── graphql_helpers.sh
│ │ ├── quality_gate.sh
│ │ ├── resolve_threads.sh
│ │ ├── run_pyscn_analysis.sh
│ │ ├── run_quality_checks.sh
│ │ ├── thread_status.sh
│ │ └── watch_reviews.sh
│ ├── quality
│ │ ├── fix_dead_code_install.sh
│ │ ├── phase1_dead_code_analysis.md
│ │ ├── phase2_complexity_analysis.md
│ │ ├── README_PHASE1.md
│ │ ├── README_PHASE2.md
│ │ ├── track_pyscn_metrics.sh
│ │ └── weekly_quality_review.sh
│ ├── README.md
│ ├── run
│ │ ├── run_mcp_memory.sh
│ │ ├── run-with-uv.sh
│ │ └── start_sqlite_vec.sh
│ ├── run_memory_server.py
│ ├── server
│ │ ├── check_http_server.py
│ │ ├── check_server_health.py
│ │ ├── memory_offline.py
│ │ ├── preload_models.py
│ │ ├── run_http_server.py
│ │ ├── run_memory_server.py
│ │ ├── start_http_server.bat
│ │ └── start_http_server.sh
│ ├── service
│ │ ├── deploy_dual_services.sh
│ │ ├── install_http_service.sh
│ │ ├── mcp-memory-http.service
│ │ ├── mcp-memory.service
│ │ ├── memory_service_manager.sh
│ │ ├── service_control.sh
│ │ ├── service_utils.py
│ │ └── update_service.sh
│ ├── sync
│ │ ├── check_drift.py
│ │ ├── claude_sync_commands.py
│ │ ├── export_memories.py
│ │ ├── import_memories.py
│ │ ├── litestream
│ │ │ ├── apply_local_changes.sh
│ │ │ ├── enhanced_memory_store.sh
│ │ │ ├── init_staging_db.sh
│ │ │ ├── io.litestream.replication.plist
│ │ │ ├── manual_sync.sh
│ │ │ ├── memory_sync.sh
│ │ │ ├── pull_remote_changes.sh
│ │ │ ├── push_to_remote.sh
│ │ │ ├── README.md
│ │ │ ├── resolve_conflicts.sh
│ │ │ ├── setup_local_litestream.sh
│ │ │ ├── setup_remote_litestream.sh
│ │ │ ├── staging_db_init.sql
│ │ │ ├── stash_local_changes.sh
│ │ │ ├── sync_from_remote_noconfig.sh
│ │ │ └── sync_from_remote.sh
│ │ ├── README.md
│ │ ├── safe_cloudflare_update.sh
│ │ ├── sync_memory_backends.py
│ │ └── sync_now.py
│ ├── testing
│ │ ├── run_complete_test.py
│ │ ├── run_memory_test.sh
│ │ ├── simple_test.py
│ │ ├── test_cleanup_logic.py
│ │ ├── test_cloudflare_backend.py
│ │ ├── test_docker_functionality.py
│ │ ├── test_installation.py
│ │ ├── test_mdns.py
│ │ ├── test_memory_api.py
│ │ ├── test_memory_simple.py
│ │ ├── test_migration.py
│ │ ├── test_search_api.py
│ │ ├── test_sqlite_vec_embeddings.py
│ │ ├── test_sse_events.py
│ │ ├── test-connection.py
│ │ └── test-hook.js
│ ├── utils
│ │ ├── claude_commands_utils.py
│ │ ├── generate_personalized_claude_md.sh
│ │ ├── groq
│ │ ├── groq_agent_bridge.py
│ │ ├── list-collections.py
│ │ ├── memory_wrapper_uv.py
│ │ ├── query_memories.py
│ │ ├── smithery_wrapper.py
│ │ ├── test_groq_bridge.sh
│ │ └── uv_wrapper.py
│ └── validation
│ ├── check_dev_setup.py
│ ├── check_documentation_links.py
│ ├── diagnose_backend_config.py
│ ├── validate_configuration_complete.py
│ ├── validate_memories.py
│ ├── validate_migration.py
│ ├── validate_timestamp_integrity.py
│ ├── verify_environment.py
│ ├── verify_pytorch_windows.py
│ └── verify_torch.py
├── SECURITY.md
├── selective_timestamp_recovery.py
├── SPONSORS.md
├── src
│ └── mcp_memory_service
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ ├── client.py
│ │ ├── operations.py
│ │ ├── sync_wrapper.py
│ │ └── types.py
│ ├── backup
│ │ ├── __init__.py
│ │ └── scheduler.py
│ ├── cli
│ │ ├── __init__.py
│ │ ├── ingestion.py
│ │ ├── main.py
│ │ └── utils.py
│ ├── config.py
│ ├── consolidation
│ │ ├── __init__.py
│ │ ├── associations.py
│ │ ├── base.py
│ │ ├── clustering.py
│ │ ├── compression.py
│ │ ├── consolidator.py
│ │ ├── decay.py
│ │ ├── forgetting.py
│ │ ├── health.py
│ │ └── scheduler.py
│ ├── dependency_check.py
│ ├── discovery
│ │ ├── __init__.py
│ │ ├── client.py
│ │ └── mdns_service.py
│ ├── embeddings
│ │ ├── __init__.py
│ │ └── onnx_embeddings.py
│ ├── ingestion
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── chunker.py
│ │ ├── csv_loader.py
│ │ ├── json_loader.py
│ │ ├── pdf_loader.py
│ │ ├── registry.py
│ │ ├── semtools_loader.py
│ │ └── text_loader.py
│ ├── lm_studio_compat.py
│ ├── mcp_server.py
│ ├── models
│ │ ├── __init__.py
│ │ └── memory.py
│ ├── server.py
│ ├── services
│ │ ├── __init__.py
│ │ └── memory_service.py
│ ├── storage
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── cloudflare.py
│ │ ├── factory.py
│ │ ├── http_client.py
│ │ ├── hybrid.py
│ │ └── sqlite_vec.py
│ ├── sync
│ │ ├── __init__.py
│ │ ├── exporter.py
│ │ ├── importer.py
│ │ └── litestream_config.py
│ ├── utils
│ │ ├── __init__.py
│ │ ├── cache_manager.py
│ │ ├── content_splitter.py
│ │ ├── db_utils.py
│ │ ├── debug.py
│ │ ├── document_processing.py
│ │ ├── gpu_detection.py
│ │ ├── hashing.py
│ │ ├── http_server_manager.py
│ │ ├── port_detection.py
│ │ ├── system_detection.py
│ │ └── time_parser.py
│ └── web
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ ├── analytics.py
│ │ ├── backup.py
│ │ ├── consolidation.py
│ │ ├── documents.py
│ │ ├── events.py
│ │ ├── health.py
│ │ ├── manage.py
│ │ ├── mcp.py
│ │ ├── memories.py
│ │ ├── search.py
│ │ └── sync.py
│ ├── app.py
│ ├── dependencies.py
│ ├── oauth
│ │ ├── __init__.py
│ │ ├── authorization.py
│ │ ├── discovery.py
│ │ ├── middleware.py
│ │ ├── models.py
│ │ ├── registration.py
│ │ └── storage.py
│ ├── sse.py
│ └── static
│ ├── app.js
│ ├── index.html
│ ├── README.md
│ ├── sse_test.html
│ └── style.css
├── start_http_debug.bat
├── start_http_server.sh
├── test_document.txt
├── test_version_checker.js
├── tests
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ ├── test_compact_types.py
│ │ └── test_operations.py
│ ├── bridge
│ │ ├── mock_responses.js
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ └── test_http_mcp_bridge.js
│ ├── conftest.py
│ ├── consolidation
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── test_associations.py
│ │ ├── test_clustering.py
│ │ ├── test_compression.py
│ │ ├── test_consolidator.py
│ │ ├── test_decay.py
│ │ └── test_forgetting.py
│ ├── contracts
│ │ └── api-specification.yml
│ ├── integration
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── test_api_key_fallback.py
│ │ ├── test_api_memories_chronological.py
│ │ ├── test_api_tag_time_search.py
│ │ ├── test_api_with_memory_service.py
│ │ ├── test_bridge_integration.js
│ │ ├── test_cli_interfaces.py
│ │ ├── test_cloudflare_connection.py
│ │ ├── test_concurrent_clients.py
│ │ ├── test_data_serialization_consistency.py
│ │ ├── test_http_server_startup.py
│ │ ├── test_mcp_memory.py
│ │ ├── test_mdns_integration.py
│ │ ├── test_oauth_basic_auth.py
│ │ ├── test_oauth_flow.py
│ │ ├── test_server_handlers.py
│ │ └── test_store_memory.py
│ ├── performance
│ │ ├── test_background_sync.py
│ │ └── test_hybrid_live.py
│ ├── README.md
│ ├── smithery
│ │ └── test_smithery.py
│ ├── sqlite
│ │ └── simple_sqlite_vec_test.py
│ ├── test_client.py
│ ├── test_content_splitting.py
│ ├── test_database.py
│ ├── test_hybrid_cloudflare_limits.py
│ ├── test_hybrid_storage.py
│ ├── test_memory_ops.py
│ ├── test_semantic_search.py
│ ├── test_sqlite_vec_storage.py
│ ├── test_time_parser.py
│ ├── test_timestamp_preservation.py
│ ├── timestamp
│ │ ├── test_hook_vs_manual_storage.py
│ │ ├── test_issue99_final_validation.py
│ │ ├── test_search_retrieval_inconsistency.py
│ │ ├── test_timestamp_issue.py
│ │ └── test_timestamp_simple.py
│ └── unit
│ ├── conftest.py
│ ├── test_cloudflare_storage.py
│ ├── test_csv_loader.py
│ ├── test_fastapi_dependencies.py
│ ├── test_import.py
│ ├── test_json_loader.py
│ ├── test_mdns_simple.py
│ ├── test_mdns.py
│ ├── test_memory_service.py
│ ├── test_memory.py
│ ├── test_semtools_loader.py
│ ├── test_storage_interface_compatibility.py
│ └── test_tag_time_filtering.py
├── tools
│ ├── docker
│ │ ├── DEPRECATED.md
│ │ ├── docker-compose.http.yml
│ │ ├── docker-compose.pythonpath.yml
│ │ ├── docker-compose.standalone.yml
│ │ ├── docker-compose.uv.yml
│ │ ├── docker-compose.yml
│ │ ├── docker-entrypoint-persistent.sh
│ │ ├── docker-entrypoint-unified.sh
│ │ ├── docker-entrypoint.sh
│ │ ├── Dockerfile
│ │ ├── Dockerfile.glama
│ │ ├── Dockerfile.slim
│ │ ├── README.md
│ │ └── test-docker-modes.sh
│ └── README.md
└── uv.lock
```
# Files
--------------------------------------------------------------------------------
/archive/docs-root-cleanup-2025-08-23/README-ORIGINAL-BACKUP.md:
--------------------------------------------------------------------------------
```markdown
# MCP Memory Service
[](https://opensource.org/licenses/Apache-2.0)
[](https://github.com/doobidoo/mcp-memory-service/stargazers)
[](https://github.com/doobidoo/mcp-memory-service/network/members)
[](https://github.com/doobidoo/mcp-memory-service/issues)
[](https://github.com/doobidoo/mcp-memory-service/commits)
[](https://smithery.ai/server/@doobidoo/mcp-memory-service)
[](https://mseep.ai/app/0513fb92-e941-4fe0-9948-2a1dbb870dcf)
[](https://claude.ai)
[](https://cursor.sh)
[](https://codeium.com/windsurf)
[](https://lmstudio.ai)
[](https://zed.dev)
[](https://modelcontextprotocol.io/)
[](https://github.com/doobidoo/mcp-memory-service#features)
[](https://github.com/doobidoo/mcp-memory-service#hardware-compatibility)
[](https://github.com/doobidoo/mcp-memory-service#-in-production)
[](https://github.com/doobidoo/mcp-memory-service#storage-backends)
[](https://github.com/doobidoo/mcp-memory-service#storage-backends)
A **universal MCP memory service** providing **semantic memory search**, persistent storage, and **autonomous memory consolidation** for **AI assistants** and development environments. This **Model Context Protocol server** works with **Claude Desktop, VS Code, Cursor, Continue, WindSurf, LM Studio, Zed, and 13+ AI applications**, featuring **multiple storage backends** including **SQLite-vec** for **fast local search**, **Cloudflare** for **global edge distribution**, and a revolutionary **dream-inspired consolidation system** that automatically organizes, compresses, and manages your **AI conversation history** over time, creating a **self-evolving knowledge base** for enhanced **AI productivity**.
<img width="240" alt="grafik" src="https://github.com/user-attachments/assets/eab1f341-ca54-445c-905e-273cd9e89555" />
<a href="https://glama.ai/mcp/servers/bzvl3lz34o"><img width="380" height="200" src="https://glama.ai/mcp/servers/bzvl3lz34o/badge" alt="Memory Service MCP server" /></a>
## Help
- Talk to the Repo with [TalkToGitHub](https://talktogithub.com/doobidoo/mcp-memory-service)!
- Use Gitprobe to digg deeper: [GitProbe](https://gitprobe.com/doobidoo/mcp-memory-service)!
---
## 📋 Table of Contents
### 🚀 Getting Started
- [⚡ Quick Start](#-quick-start)
- [🌍 Cloudflare Backend (v6.2.0)](#cloudflare-v620---cloud-native-)
- [🧠 Claude Code Memory Awareness (v6.0.0)](#-new-claude-code-memory-awareness-v600)
- [🎯 Claude Code Commands (v2.2.0)](#-new-claude-code-commands-v220)
- [🚀 Remote MCP Memory Service (v4.0.0)](#-new-remote-mcp-memory-service-v400)
- [🔄 Distributed Memory Synchronization (v6.3.0)](#-new-distributed-memory-synchronization-v630)
- [📦 Installation Methods](#installation-methods)
- [⚙️ Claude MCP Configuration](#claude-mcp-configuration)
### 🌟 Features & Capabilities
- [✨ Features Overview](#features)
- [🧠 Dream-Inspired Memory Consolidation](#-dream-inspired-memory-consolidation)
- [💾 Storage Backends](#storage-backends)
- [🔧 Memory Operations](#memory-operations)
### 🌐 Deployment & Multi-Client
- [🌐 Multi-Client Deployment](#-multi-client-deployment)
- [🔒 SSL/TLS Configuration](#ssltls-configuration)
- [🚀 Service Installation](#-service-installation-new)
### 📖 Documentation & Support
- [📝 Usage Guide](#usage-guide)
- [⚙️ Configuration Options](#configuration-options)
- [🖥️ Hardware Compatibility](#hardware-compatibility)
- [🧪 Testing](#testing)
- [❓ FAQ](#faq)
- [🛠️ Troubleshooting](#troubleshooting)
- [📚 Comprehensive Documentation](#-comprehensive-documentation)
### 👨💻 Development & Community
- [🏗️ Project Structure](#project-structure)
- [📋 Development Guidelines](#development-guidelines)
- [🤝 Integrations](#integrations)
- [💖 Sponsorship](#-why-sponsor-mcp-memory-service)
---
## 🚀 Quick Start
Choose your preferred installation method to get started in under 5 minutes:
### Option 1: Docker (Fastest - 2 minutes)
```bash
# Pull and run with default settings
docker pull doobidoo/mcp-memory-service:latest
docker run -d -p 8000:8000 -v $(pwd)/data:/app/data doobidoo/mcp-memory-service:latest
```
✅ **Perfect for**: Testing, production deployment, isolation
➡️ [Complete Docker Setup](#docker-installation)
### Option 2: Smithery (Simplest - 1 minute)
```bash
# Auto-install for Claude Desktop
npx -y @smithery/cli install @doobidoo/mcp-memory-service --client claude
```
✅ **Perfect for**: Claude Desktop users, zero configuration
➡️ [Smithery Details](#installing-via-smithery)
### Option 3: Python Installer (Most Flexible - 5 minutes)
```bash
# Clone and install with hardware detection
git clone https://github.com/doobidoo/mcp-memory-service.git
cd mcp-memory-service && python install.py
```
✅ **Perfect for**: Developers, customization, multi-client setup
➡️ [Full Installation Guide](#-intelligent-installer-recommended)
---
## 🧠 NEW: Claude Code Memory Awareness (v6.0.0)
**Revolutionary automatic memory injection for Claude Code sessions!**
Transform your development experience with intelligent, automatic memory context that appears seamlessly in every Claude Code session. Never lose track of decisions, insights, or architectural choices again.
### ✨ Automatic Memory Injection
```bash
# Install the memory awareness hook system
cd claude-hooks && ./install.sh
# Every Claude Code session now starts with relevant context:
# 🧠 Relevant Memory Context
#
# ## Recent Insights (Last 7 days)
# - Database Performance Issue - Resolved SQLite-vec optimization (yesterday)
# - Authentication Flow - Implemented JWT validation (3 days ago)
#
# ## Key Decisions
# - Architecture Decision - Chose React over Vue (1 week ago)
# - Database Choice - Selected PostgreSQL for production (2 weeks ago)
```
### 🎯 Features
🤖 **Zero Cognitive Load**: Memory context appears automatically without user intervention
🧠 **Intelligent Selection**: Advanced scoring algorithm chooses only relevant memories
⚡ **Lightning Fast**: Memory injection adds <2 seconds to session startup
📊 **Multi-Language Support**: Detects JavaScript, Python, Rust, Go, Java, C++ projects
🏗️ **Context-Aware**: Understands your project structure, git repo, and technology stack
📝 **Beautiful Formatting**: Categorized, markdown-rich memory presentation
🔄 **Session Learning**: Automatically stores session outcomes for future reference
✅ **100% Test Coverage**: Comprehensive testing with complete integration validation
### 🚀 Installation
```bash
# Clone repository and install hooks
git clone https://github.com/doobidoo/mcp-memory-service.git
cd mcp-memory-service/claude-hooks
./install.sh
# Verify installation
npm test # 10 tests, all passing
```
### 🏗️ How It Works
1. **Session Start**: Hook detects project context (language, framework, git info)
2. **Memory Query**: Searches memory service for relevant memories using multi-factor scoring
3. **Context Injection**: Formats and injects top 8 relevant memories as session context
4. **Session End**: Analyzes conversation and stores outcomes with intelligent tagging
### 📊 Memory Scoring Algorithm
```javascript
// Multi-factor relevance scoring
const relevanceScore = (
timeDecayScore * 0.4 + // Recent memories preferred
tagRelevanceScore * 0.3 + // Project-specific tags
contentSimilarityScore * 0.2 + // Semantic matching
memoryTypeBonusScore * 0.1 // Decision/insight bonus
);
```
➡️ [**Technical Architecture**](docs/enhancement-roadmap-issue-14.md) | [**Installation Guide**](claude-hooks/README.md) | [**Test Results**](claude-hooks/tests/)
---
## 🎯 NEW: Claude Code Commands (v2.2.0)
**Get started in 2 minutes with direct memory commands!**
```bash
# Install with Claude Code commands
python install.py --install-claude-commands
# Start using immediately
claude /memory-store "Important decision about architecture"
claude /memory-recall "what did we decide last week?"
claude /memory-search --tags "architecture,database"
claude /memory-health
```
✨ **5 conversational commands** following CCPlugins pattern
🚀 **Zero MCP server configuration** required
🧠 **Context-aware operations** with automatic project detection
🎨 **Professional interface** with comprehensive guidance
➡️ [**Quick Start Guide**](docs/guides/claude-code-quickstart.md) | [**Full Integration Guide**](docs/guides/claude-code-integration.md)
## 🚀 NEW: Remote MCP Memory Service (v4.0.0)
**Production-ready remote memory service with native MCP-over-HTTP protocol!**
### Remote Deployment
Deploy the memory service on any server for cross-device access:
```bash
# On your server
git clone https://github.com/doobidoo/mcp-memory-service.git
cd mcp-memory-service
python install.py
python scripts/run_http_server.py
```
**Server Access Points:**
- **MCP Protocol**: `http://your-server:8000/mcp` (for MCP clients)
- **Dashboard**: `http://your-server:8000/` (web interface)
- **API Docs**: `http://your-server:8000/api/docs` (interactive API)
### Remote API Access
Connect any MCP client or tool to your remote memory service:
```bash
# Test MCP connection
curl -X POST http://your-server:8000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}'
# Store memories remotely
curl -X POST http://your-server:8000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "store_memory",
"arguments": {
"content": "Your memory content",
"tags": ["tag1", "tag2"]
}
}
}'
```
**Key Benefits:**
- ✅ **Cross-Device Access**: Connect from any device running Claude Code
- ✅ **Native MCP Protocol**: Standard JSON-RPC 2.0 implementation
- ✅ **No Bridge Required**: Direct HTTP/HTTPS connection
- ✅ **Production Ready**: Proven deployment at scale
---
## 🔄 NEW: Distributed Memory Synchronization (v6.3.0)
**Git-like workflow for distributed memory systems with automatic conflict resolution!**
Transform your memory service into a distributed system with seamless synchronization between local development and remote production servers. Features intelligent conflict detection, offline capability, and real-time replication.
### ✨ Key Features
🌐 **Remote-First Architecture**: Direct API communication with local staging fallback
⚡ **Real-Time Replication**: Litestream integration for live SQLite synchronization
🔄 **Git-like Workflow**: Stage → Pull → Apply → Push with automatic conflict resolution
🏠 **Offline Capability**: Local staging database for offline development
🔍 **Content Hash Detection**: Intelligent deduplication and conflict prevention
📡 **Cross-Platform Service**: Works on Linux, macOS, and Windows servers
🎯 **Zero Configuration**: Automatic service discovery via mDNS/hostname resolution
### 🚀 Quick Setup
```bash
# Install distributed sync system
./scripts/memory_sync.sh install
# Configure remote server (one-time setup)
export REMOTE_MEMORY_HOST="narrowbox.local"
export REMOTE_MEMORY_PORT="8443"
# Initialize sync with remote server
./scripts/memory_sync.sh init
```
### 🔧 Git-like Commands
```bash
# Stage memories locally (offline mode)
./scripts/enhanced_memory_store.sh "Important development decision"
# Pull latest changes from remote
./scripts/memory_sync.sh pull
# Push local changes to remote
./scripts/memory_sync.sh push
# Full synchronization workflow
./scripts/memory_sync.sh sync
# Check sync status with colored output
./scripts/memory_sync.sh status
```
### 🏗️ Architecture Overview
```mermaid
graph TB
A[Local Client] -->|1. Try Direct API| B[Remote Server]
A -->|2. Fallback if Offline| C[Staging DB]
B -->|Real-time Sync| D[Production SQLite]
C -->|Batch Sync| E[Sync Engine]
E -->|Content Hash Check| B
F[Litestream] -->|Continuous Replication| G[Backup Storage]
D --> F
```
### 💾 Components
#### Core Sync Engine
- **`memory_sync.sh`**: Main orchestrator with colored status output
- **`enhanced_memory_store.sh`**: Remote-first storage with intelligent fallback
- **`pull_remote_changes.sh`**: Conflict-aware remote synchronization
- **`manual_sync.sh`**: HTTP-based sync with content hash validation
#### Database Infrastructure
- **`staging_db_init.sql`**: Complete SQLite staging schema with triggers
- **`litestream.yml`**: Master/replica configuration for real-time sync
- **Service files**: Cross-platform systemd/LaunchDaemon integration
#### Advanced Features
- **Content hash-based deduplication**: Prevents duplicate memories across sync
- **Staging database system**: Full offline capability with background sync
- **HTTP replica serving**: Lightweight Python server for cross-network access
- **Service management**: Native integration with system service managers
### 🔧 Advanced Configuration
```bash
# Fine-tune sync behavior
export SYNC_CONFLICT_RESOLUTION="merge" # merge, local, remote
export SYNC_BATCH_SIZE="100" # Memories per sync batch
export SYNC_RETRY_ATTEMPTS="3" # Network retry count
export SYNC_OFFLINE_THRESHOLD="5" # Seconds before offline mode
# Litestream replication settings
export LITESTREAM_REPLICA_PATH="/backup/sqlite_vec.db"
export LITESTREAM_SYNC_INTERVAL="1s" # Real-time replication
export LITESTREAM_RETENTION="72h" # Backup retention period
```
### 📊 Status Dashboard
The sync system provides comprehensive status reporting:
```bash
./scripts/memory_sync.sh status
```
**Output includes:**
- 🟢 **Remote connectivity** status with response time
- 📊 **Memory counts** (local vs remote) with sync diff
- ⏰ **Last sync** timestamp and success rate
- 🔄 **Replication status** via Litestream integration
- 🎯 **Conflict detection** and resolution recommendations
### 🛠️ Service Integration
Install as system service for automatic sync:
```bash
# Install sync service (auto-detects OS)
./scripts/memory_sync.sh install-service
# Enable automatic background sync
systemctl enable mcp-memory-sync # Linux
launchctl load ~/Library/LaunchAgents/com.mcp.memory.sync.plist # macOS
```
**Benefits:**
- ✅ **Automatic startup** on boot/login
- ✅ **Background synchronization** every 15 minutes
- ✅ **Service health monitoring** with restart on failure
- ✅ **Cross-platform compatibility** (systemd, LaunchAgent, Windows Service)
➡️ **[Complete Sync Documentation](docs/guides/distributed-sync.md)** | **[Installation Guide](docs/installation/distributed-sync.md)** | **[Troubleshooting](docs/troubleshooting/sync-issues.md)**
---
## Features
### 🌟 Universal AI Client Compatibility
**Works with 13+ AI applications and development environments** via the standard Model Context Protocol (MCP):
| Client | Status | Configuration | Notes |
|--------|--------|--------------|-------|
| **Claude Desktop** | ✅ Full | `claude_desktop_config.json` | Official MCP support |
| **Claude Code** | ✅ Full | `.claude.json` | Optionally use Claude Commands instead ([guide](CLAUDE_CODE_COMPATIBILITY.md)) |
| **Cursor** | ✅ Full | `.cursor/mcp.json` | AI-powered IDE with MCP support |
| **WindSurf** | ✅ Full | MCP config file | Codeium's AI IDE with built-in server management |
| **LM Studio** | ✅ Full | MCP configuration | Enhanced compatibility with debug output |
| **Cline** | ✅ Full | VS Code MCP config | VS Code extension, formerly Claude Dev |
| **RooCode** | ✅ Full | IDE config | Full MCP client implementation |
| **Zed** | ✅ Full | Built-in config | Native MCP support |
| **VS Code** | ✅ Full | `.vscode/mcp.json` | Via MCP extension |
| **Continue IDE** | ✅ Full | Continue configuration | Extension with MCP support |
| **Standard MCP Libraries** | ✅ Full | Various | Python `mcp`, JavaScript SDK |
| **Custom MCP Clients** | ✅ Full | Implementation-specific | Full protocol compliance |
| **HTTP API** | ✅ Full | REST endpoints | Direct API access on port 8000 |
**Core Benefits:**
- 🔄 **Cross-Client Memory Sharing**: Use memories across all your AI tools
- 🚀 **Universal Setup**: Single installation works everywhere
- 🔌 **Standard Protocol**: Full MCP compliance ensures compatibility
- 🌐 **Remote Access**: HTTP/HTTPS support for distributed teams
➡️ [**Multi-Client Setup Guide**](docs/integration/multi-client.md) | [**IDE Compatibility Details**](docs/ide-compatability.md)
### 🧠 Intelligent Memory System
#### **Autonomous Memory Consolidation**
- **Dream-inspired processing** with multi-layered time horizons (daily → yearly)
- **Creative association discovery** finding non-obvious connections between memories
- **Semantic clustering** automatically organizing related memories
- **Intelligent compression** preserving key information while reducing storage
- **Controlled forgetting** with safe archival and recovery systems
- **Performance optimized** for processing 10k+ memories efficiently
### ⚡ ONNX Runtime Support (NEW!)
- **PyTorch-free operation** using ONNX Runtime for embeddings
- **Reduced dependencies** (~500MB less disk space without PyTorch)
- **Faster startup** with pre-optimized ONNX models
- **Automatic fallback** to SentenceTransformers when needed
- **Compatible models** with the same all-MiniLM-L6-v2 embeddings
- Enable with: `export MCP_MEMORY_USE_ONNX=true`
#### **Advanced Memory Operations**
- **Semantic search** using sentence transformers or ONNX embeddings
- **Natural language time-based recall** (e.g., "last week", "yesterday morning")
- **Enhanced tag deletion system** with flexible multi-tag support
- **Tag-based memory retrieval** system with OR/AND logic
- **Exact match retrieval** and duplicate detection
- **Debug mode** for similarity analysis and troubleshooting
#### **Enhanced MCP Protocol Features** (v4.1.0+)
- **📚 URI-based Resources**: `memory://stats`, `memory://tags`, `memory://recent/{n}`, `memory://search/{query}`
- **📋 Guided Prompts**: Interactive workflows (memory_review, memory_analysis, knowledge_export)
- **📊 Progress Tracking**: Real-time notifications for long operations
- **🔄 Database Synchronization**: Multi-node sync with Litestream integration
- **🎛️ Client Optimization**: Auto-detection and optimization for Claude Desktop vs LM Studio
### 🚀 Deployment & Performance
#### **Storage Backends**
- **🪶 SQLite-vec (default)**: 10x faster startup, 75% less memory, zero network dependencies
- **📦 ChromaDB (legacy)**: Available for backward compatibility, deprecated in v6.0.0
#### **Multi-Client Architecture**
- **Production FastAPI server** with auto-generated SSL certificates
- **mDNS Service Discovery** for zero-configuration networking
- **Server-Sent Events (SSE)** with real-time updates
- **API key authentication** for secure deployments
- **Cross-platform service installation** (systemd, LaunchAgent, Windows Service)
#### **Platform Support**
- **Cross-platform compatibility**: Apple Silicon, Intel, Windows, Linux
- **Hardware-aware optimizations**: CUDA, MPS, DirectML, ROCm support
- **Graceful fallbacks** for limited hardware resources
- **Container support** with Docker images and Docker Compose configurations
### Recent Highlights
#### 🚀 Latest Features
- **v6.3.0**: 🔄 **Distributed Memory Synchronization** - Git-like workflow, real-time Litestream replication, offline capability
- **v6.2.0**: 🌍 **Native Cloudflare Backend Integration** - Global edge distribution, serverless scaling, Vectorize + D1 + R2 storage
- **v6.1.0**: 🧠 **Intelligent Context Updates (Phase 2)** - Real-time conversation analysis with dynamic memory loading
- **v6.0.0**: 🧠 **Claude Code Memory Awareness (Phase 1)** - Automatic memory injection for coding sessions
- **v5.0.2**: ONNX Runtime support for PyTorch-free embeddings and SQLite-vec consolidation fixes
- **v5.0.0**: SQLite-vec is now the default backend - 10x faster startup, 75% less memory
➡️ **[View Full Changelog](CHANGELOG.md)** for complete version history and detailed release notes
## Installation Methods
*For quick setup, see the [⚡ Quick Start](#-quick-start) section above.*
[](#docker-installation)
[](#installing-via-smithery)
[](#-intelligent-installer-recommended)
[](#uvx-installation)
### 🚀 Intelligent Installer (Recommended)
The new unified installer automatically detects your hardware and selects the optimal configuration:
```bash
# Clone the repository
git clone https://github.com/doobidoo/mcp-memory-service.git
cd mcp-memory-service
# Create and activate a virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Run the intelligent installer
python install.py
# ✨ NEW: Multi-client setup is now integrated!
# You'll be prompted to configure universal MCP client access
# for Claude Desktop, VS Code, Continue, and other MCP applications
```
### 🎯 Hardware-Specific Installation
**For Intel Macs:**
For detailed setup instructions specific to Intel Macs, see our [Intel Mac Setup Guide](docs/platforms/macos-intel.md).
**For Legacy Hardware (2013-2017 Intel Macs):**
```bash
python install.py --legacy-hardware
```
**For Server/Headless Deployment:**
```bash
python install.py --server-mode
```
**For HTTP/SSE API Development:**
```bash
python install.py --enable-http-api
```
**For Migration from ChromaDB:**
```bash
python install.py --migrate-from-chromadb
```
**For Multi-Client Setup:**
```bash
# Automatic multi-client setup during installation
python install.py --setup-multi-client
# Skip the interactive multi-client prompt
python install.py --skip-multi-client-prompt
```
**For Claude Code Commands:**
```bash
# Install with Claude Code commands (prompts if CLI detected)
python install.py --install-claude-commands
# Skip the interactive Claude Code commands prompt
python install.py --skip-claude-commands-prompt
```
### 🧠 What the Installer Does
1. **Hardware Detection**: CPU, GPU, memory, and platform analysis
2. **Intelligent Backend Selection**: SQLite-vec by default, with ChromaDB as legacy option
3. **Platform Optimization**: macOS Intel fixes, Windows CUDA setup, Linux variations
4. **Dependency Management**: Compatible PyTorch and ML library versions
5. **Auto-Configuration**: Claude Desktop config and environment variables
6. **Migration Support**: Seamless ChromaDB to SQLite-vec migration
### 📊 Storage Backend Selection
**SQLite-vec (default)**: 10x faster startup, zero dependencies, recommended for all users
**ChromaDB (deprecated)**: Legacy support only, will be removed in v6.0.0
➡️ **[Detailed Storage Backend Comparison](#storage-backends)**
To explicitly select a backend during installation:
```bash
python install.py # Uses SQLite-vec by default
python install.py --storage-backend sqlite_vec # Explicitly use SQLite-vec
python install.py --storage-backend chromadb # Use legacy ChromaDB (not recommended)
```
### Docker Installation
#### Docker Hub (Recommended)
The easiest way to run the Memory Service is using our pre-built Docker images. We provide **two variants** optimized for different use cases:
##### Standard Image (Full Features)
```bash
# Pull the standard image (includes PyTorch + CUDA support)
docker pull doobidoo/mcp-memory-service:latest
# Run with default settings (for MCP clients)
docker run -d -p 8000:8000 \
-v $(pwd)/data/sqlite_db:/app/sqlite_db \
-v $(pwd)/data/backups:/app/backups \
doobidoo/mcp-memory-service:latest
```
##### Slim Image (90% Smaller - Recommended for CPU-only deployments)
```bash
# Pull the slim image (ONNX + sqlite-vec only, ~300MB vs 3GB+)
docker pull doobidoo/mcp-memory-service:slim
# Run optimized for CPU-only performance
docker run -d -p 8000:8000 \
-v $(pwd)/data/sqlite_db:/app/sqlite_db \
-v $(pwd)/data/backups:/app/backups \
doobidoo/mcp-memory-service:slim
```
**Image Comparison:**
- **Standard**: ~3.4GB (PyTorch + CUDA libraries) - Best for GPU acceleration
- **Slim**: ~300MB (ONNX + sqlite-vec only) - Best for CPU-only deployments, faster pulls
##### Advanced Usage
```bash
# Run in standalone mode (for testing/development)
docker run -d -p 8000:8000 \
-e MCP_STANDALONE_MODE=1 \
-v $(pwd)/data/sqlite_db:/app/sqlite_db \
-v $(pwd)/data/backups:/app/backups \
doobidoo/mcp-memory-service:slim
```
#### Docker Compose
We provide multiple Docker Compose configurations for different scenarios:
- `docker-compose.yml` - Standard configuration for MCP clients
- `docker-compose.standalone.yml` - **Standalone mode** for testing/development (prevents boot loops)
- `docker-compose.uv.yml` - Alternative configuration using UV package manager
- `docker-compose.pythonpath.yml` - Configuration with explicit PYTHONPATH settings
```bash
# Using Docker Compose (recommended)
docker-compose up
# Standalone mode (prevents boot loops)
docker-compose -f docker-compose.standalone.yml up
```
#### Building from Source
If you need to build the Docker image yourself:
```bash
# Build the image
docker build -t mcp-memory-service .
# Run the container
docker run -p 8000:8000 \
-v $(pwd)/data/chroma_db:/app/chroma_db \
-v $(pwd)/data/backups:/app/backups \
mcp-memory-service
```
### uvx Installation
You can install and run the Memory Service using uvx for isolated execution:
```bash
# Install uv (which includes uvx) if not already installed
pip install uv
# Or use the installer script:
# curl -LsSf https://astral.sh/uv/install.sh | sh
# Install and run the memory service
uvx mcp-memory-service
# Or install from GitHub
uvx --from git+https://github.com/doobidoo/mcp-memory-service.git mcp-memory-service
```
### Windows Installation (Special Case)
Windows users may encounter PyTorch installation issues due to platform-specific wheel availability. Use our Windows-specific installation script:
```bash
# After activating your virtual environment
python scripts/install_windows.py
```
This script handles:
1. Detecting CUDA availability and version
2. Installing the appropriate PyTorch version from the correct index URL
3. Installing other dependencies without conflicting with PyTorch
4. Verifying the installation
### Installing via Smithery
To install Memory Service for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@doobidoo/mcp-memory-service):
```bash
npx -y @smithery/cli install @doobidoo/mcp-memory-service --client claude
```
### Detailed Installation Guide
For comprehensive installation instructions and troubleshooting, see the [Installation Guide](docs/installation/master-guide.md).
## Configuration
### Basic Client Configuration
#### Claude Desktop Configuration
Add to your `claude_desktop_config.json` file:
```json
{
"memory": {
"command": "uv",
"args": ["--directory", "/path/to/mcp-memory-service", "run", "memory"],
"env": {
"MCP_MEMORY_STORAGE_BACKEND": "sqlite_vec",
"MCP_MEMORY_SQLITE_PATH": "/path/to/sqlite_vec.db",
"MCP_MEMORY_BACKUPS_PATH": "/path/to/backups"
}
}
}
```
#### Windows-Specific Configuration
For Windows, use the wrapper script for PyTorch compatibility:
```json
{
"memory": {
"command": "python",
"args": ["C:\\path\\to\\mcp-memory-service\\memory_wrapper.py"],
"env": {
"MCP_MEMORY_STORAGE_BACKEND": "sqlite_vec",
"MCP_MEMORY_SQLITE_PATH": "C:\\Users\\YourUsername\\AppData\\Local\\mcp-memory\\sqlite_vec.db",
"MCP_MEMORY_BACKUPS_PATH": "C:\\Users\\YourUsername\\AppData\\Local\\mcp-memory\\backups"
}
}
}
```
➡️ **[Multi-Client Setup Guide](#-multi-client-deployment)** for Claude Desktop + VS Code + other MCP clients
### Environment Variables
#### Core Configuration
```bash
# Storage Backend
MCP_MEMORY_STORAGE_BACKEND=sqlite_vec # sqlite_vec (default) or chromadb
MCP_MEMORY_SQLITE_PATH=/path/to/database.db # SQLite database location
MCP_MEMORY_BACKUPS_PATH=/path/to/backups # Backup directory
# Performance & Hardware
MCP_MEMORY_BATCH_SIZE=32 # Processing batch size
MCP_MEMORY_MODEL_NAME=all-MiniLM-L6-v2 # Embedding model
PYTORCH_ENABLE_MPS_FALLBACK=1 # Apple Silicon fallback
MCP_MEMORY_USE_ONNX=0 # CPU-only mode
LOG_LEVEL=INFO # Logging level
```
#### HTTP API & Remote Access
```bash
# Server Configuration
MCP_HTTP_ENABLED=true # Enable HTTP server
MCP_HTTP_HOST=0.0.0.0 # Bind to all interfaces
MCP_HTTP_PORT=8000 # Server port
# Security
MCP_API_KEY="your-secure-api-key" # API authentication
MCP_HTTPS_ENABLED=true # Enable SSL/TLS
MCP_HTTPS_PORT=8443 # HTTPS port
```
### Advanced Configuration
#### SSL/TLS Setup
For production deployments with HTTPS:
```bash
# Enable HTTPS with custom certificates
export MCP_HTTPS_ENABLED=true
export MCP_SSL_CERT_FILE="/path/to/certificate.pem"
export MCP_SSL_KEY_FILE="/path/to/private-key.pem"
# Generate secure API key
export MCP_API_KEY="$(openssl rand -base64 32)"
```
**Local Development with mkcert:**
```bash
# Install mkcert for trusted local certificates
brew install mkcert # macOS
sudo apt install mkcert # Linux
# Generate local certificates
mkcert -install
mkcert localhost 127.0.0.1 your-domain.local
```
#### Memory Consolidation
```bash
# Enable autonomous memory consolidation
MCP_CONSOLIDATION_ENABLED=true
MCP_CONSOLIDATION_ARCHIVE_PATH=/path/to/archive
# Retention periods (days)
MCP_RETENTION_CRITICAL=365
MCP_RETENTION_REFERENCE=180
MCP_RETENTION_STANDARD=30
MCP_RETENTION_TEMPORARY=7
```
## 🌐 Multi-Client Deployment
**NEW**: Deploy MCP Memory Service for multiple clients sharing the same memory database!
### 🚀 Centralized Server Deployment (Recommended)
Perfect for distributed teams, multiple devices, or cloud deployment:
```bash
# Install and start HTTP/SSE server
python install.py --server-mode --enable-http-api
export MCP_HTTP_HOST=0.0.0.0 # Allow external connections
export MCP_API_KEY="your-secure-key" # Optional authentication
python scripts/run_http_server.py
```
**✅ Benefits:**
- 🔄 **Real-time sync** across all clients via Server-Sent Events (SSE)
- 🌍 **Cross-platform** - works from any device with HTTP access
- 🔒 **Secure** with optional API key authentication
- 📈 **Scalable** - handles many concurrent clients
- ☁️ **Cloud-ready** - deploy on AWS, DigitalOcean, Docker, etc.
**Access via:**
- **API Docs**: `http://your-server:8000/api/docs`
- **Web Dashboard**: `http://your-server:8000/`
- **REST API**: All MCP operations available via HTTP
### ⚠️ Why NOT Cloud Storage (Dropbox/OneDrive/Google Drive)
**Direct SQLite on cloud storage DOES NOT WORK** for multi-client access:
❌ **File locking conflicts** - Cloud sync breaks SQLite's locking mechanism
❌ **Data corruption** - Incomplete syncs can corrupt the database
❌ **Sync conflicts** - Multiple clients create "conflicted copy" files
❌ **Performance issues** - Full database re-upload on every change
**✅ Solution**: Use centralized HTTP server deployment instead!
### 🔗 Local Multi-Client Coordination
**For local development with multiple MCP clients** (Claude Desktop + VS Code + Continue, etc.):
The MCP Memory Service features **universal multi-client coordination** for seamless concurrent access:
**🚀 Integrated Setup (Recommended):**
```bash
python install.py # Automatically detects and configures all MCP clients
```
**Key Benefits:**
- ✅ **Automatic Coordination**: Intelligent detection of optimal access mode
- ✅ **Universal Setup**: Works with any MCP-compatible application
- ✅ **Shared Memory**: All clients access the same memory database
- ✅ **No Lock Conflicts**: WAL mode prevents database locking issues
- ✅ **IDE-Agnostic**: Switch between development tools while maintaining context
**Supported Clients:** Claude Desktop, Claude Code, VS Code, Continue IDE, Cursor, Cline, Zed, and more
### 📖 Complete Documentation
For detailed deployment guides, configuration options, and troubleshooting:
📚 **[Multi-Client Deployment Guide](docs/integration/multi-client.md)**
Covers:
- **Centralized HTTP/SSE Server** setup and configuration
- **Shared File Access** for local networks (limited scenarios)
- **Cloud Platform Deployment** (AWS, DigitalOcean, Docker)
- **Security & Authentication** setup
- **Performance Tuning** for high-load environments
- **Troubleshooting** common multi-client issues
## Usage Guide
For detailed instructions on how to interact with the memory service in Claude Desktop:
- [Invocation Guide](docs/guides/invocation_guide.md) - Learn the specific keywords and phrases that trigger memory operations in Claude
- [Installation Guide](docs/installation/master-guide.md) - Detailed setup instructions
- **[Demo Session Walkthrough](docs/tutorials/demo-session-walkthrough.md)** - Real-world development session showcasing advanced features
The memory service is invoked through natural language commands in your conversations with Claude. For example:
- To store: "Please remember that my project deadline is May 15th."
- To retrieve: "Do you remember what I told you about my project deadline?"
### Claude Code Commands Usage
With the optional Claude Code commands installed, you can also use direct command syntax:
```bash
# Store information with context
claude /memory-store "Important architectural decision about database backend"
# Recall memories by time
claude /memory-recall "what did we decide about the database last week?"
# Search by tags or content
claude /memory-search --tags "architecture,database"
# Capture current session context
claude /memory-context --summary "Development planning session"
# Check service health
claude /memory-health
```
- To delete: "Please forget what I told you about my address."
See the [Invocation Guide](docs/guides/invocation_guide.md) for a complete list of commands and detailed usage examples.
## Storage Backends
The MCP Memory Service supports multiple storage backends to suit different use cases:
### SQLite-vec (Default - Recommended)
- **Best for**: Local development, personal use, single-user deployments
- **Features**: Single-file database, 75% lower memory usage, zero network dependencies
- **Memory usage**: Minimal (~50MB for 1K memories)
- **Setup**: Automatically configured, works offline immediately
### Cloudflare (v6.2.0 - Cloud-Native) 🚀
- **Best for**: Production deployments, global scale, multi-user applications
- **Features**: Global edge network, serverless scaling, zero infrastructure management
- **Storage**: Vectorize + D1 + R2, Workers AI embeddings
- **Memory usage**: Minimal local footprint, cloud-based storage
- **Setup**: [Cloudflare Setup Guide](docs/cloudflare-setup.md)
### ChromaDB (Legacy - Deprecated)
⚠️ **DEPRECATED**: Will be removed in v7.0.0. Please migrate to SQLite-vec or Cloudflare.
- **Previous use cases**: Large memory collections, advanced vector metrics
- **Issues**: Network dependencies, Hugging Face download failures, high resource usage
- **Memory usage**: Higher (~200MB for 1K memories)
- **Migration**: Run `python scripts/migrate_to_sqlite_vec.py` or `python scripts/migrate_to_cloudflare.py`
#### Quick Setup for SQLite-vec
```bash
# Install sqlite-vec (if using installation script, this is handled automatically)
pip install sqlite-vec
# Configure the backend
export MCP_MEMORY_STORAGE_BACKEND=sqlite_vec
export MCP_MEMORY_SQLITE_PATH=/path/to/sqlite_vec.db
# Optional: For CPU-only mode without PyTorch (much lighter resource usage)
export MCP_MEMORY_USE_ONNX=1
# Restart Claude Desktop
```
#### SQLite-vec with Optional PyTorch
The SQLite-vec backend now works with or without PyTorch installed:
- **With PyTorch**: Full functionality including embedding generation
- **Without PyTorch**: Basic functionality using pre-computed embeddings and ONNX runtime
- **With Homebrew PyTorch**: Integration with macOS Homebrew PyTorch installation
To install optional machine learning dependencies:
```bash
# Add ML dependencies for embedding generation
pip install 'mcp-memory-service[ml]'
```
#### Quick Setup for Cloudflare Backend
```bash
# Install additional dependencies
pip install -r requirements-cloudflare.txt
# Create Cloudflare resources (using Wrangler CLI)
wrangler vectorize create mcp-memory-index --dimensions=768 --metric=cosine
wrangler d1 create mcp-memory-db
# Configure environment variables
export MCP_MEMORY_STORAGE_BACKEND=cloudflare
export CLOUDFLARE_API_TOKEN="your-api-token"
export CLOUDFLARE_ACCOUNT_ID="your-account-id"
export CLOUDFLARE_VECTORIZE_INDEX="mcp-memory-index"
export CLOUDFLARE_D1_DATABASE_ID="your-d1-database-id"
# Optional: R2 bucket for large content
export CLOUDFLARE_R2_BUCKET="mcp-memory-content"
# Start the service
uv run memory server
```
📖 **[Complete Cloudflare Setup Guide](docs/cloudflare-setup.md)**
#### Homebrew PyTorch Integration
For macOS users who prefer to use Homebrew's PyTorch installation:
```bash
# Install PyTorch via Homebrew
brew install pytorch
# Run MCP Memory Service with Homebrew PyTorch integration
./run_with_homebrew.sh
```
This integration offers several benefits:
- Uses Homebrew's isolated Python environment for PyTorch
- Avoids dependency conflicts with Claude Desktop
- Reduces memory usage in the main process
- Provides better stability in resource-constrained environments
For detailed documentation on the Homebrew PyTorch integration:
- [Homebrew Integration Guide](docs/integration/homebrew.md) - Technical journey and solution architecture
#### Migration Between Backends
```bash
# Migrate from ChromaDB to SQLite-vec
python migrate_to_sqlite_vec.py
# Full migration with backup
python scripts/migrate_storage.py \
--from chroma --to sqlite_vec \
--backup --backup-path backup.json
```
For detailed SQLite-vec setup, migration, and troubleshooting, see the [SQLite-vec Backend Guide](docs/sqlite-vec-backend.md).
## Memory Operations
The memory service provides the following operations through the MCP server:
### Core Memory Operations
1. `store_memory` - Store new information with optional tags
2. `retrieve_memory` - Perform semantic search for relevant memories
3. `recall_memory` - Retrieve memories using natural language time expressions
4. `search_by_tag` - Find memories using specific tags
5. `exact_match_retrieve` - Find memories with exact content match
6. `debug_retrieve` - Retrieve memories with similarity scores
### Database Management
7. `create_backup` - Create database backup
8. `get_stats` - Get memory statistics
9. `optimize_db` - Optimize database performance
10. `check_database_health` - Get database health metrics
11. `check_embedding_model` - Verify model status
### Memory Management
12. `delete_memory` - Delete specific memory by hash
13. `delete_by_tag` - **Enhanced**: Delete memories with specific tag(s) - supports both single tags and multiple tags
14. `delete_by_tags` - **New**: Explicitly delete memories containing any of the specified tags (OR logic)
15. `delete_by_all_tags` - **New**: Delete memories containing all specified tags (AND logic)
16. `cleanup_duplicates` - Remove duplicate entries
### API Consistency Improvements
**Issue 5 Resolution**: Enhanced tag deletion functionality for consistent API design.
- **Before**: `search_by_tag` accepted arrays, `delete_by_tag` only accepted single strings
- **After**: Both operations now support flexible tag handling
```javascript
// Single tag deletion (backward compatible)
delete_by_tag("temporary")
// Multiple tag deletion (new!)
delete_by_tag(["temporary", "outdated", "test"]) // OR logic
// Explicit methods for clarity
delete_by_tags(["tag1", "tag2"]) // OR logic
delete_by_all_tags(["urgent", "important"]) // AND logic
```
### Example Usage
```javascript
// Store memories with tags
store_memory("Project deadline is May 15th", {tags: ["work", "deadlines", "important"]})
store_memory("Grocery list: milk, eggs, bread", {tags: ["personal", "shopping"]})
store_memory("Meeting notes from sprint planning", {tags: ["work", "meetings", "important"]})
// Search by multiple tags (existing functionality)
search_by_tag(["work", "important"]) // Returns memories with either tag
// Enhanced deletion options (new!)
delete_by_tag("temporary") // Delete single tag (backward compatible)
delete_by_tag(["temporary", "outdated"]) // Delete memories with any of these tags
delete_by_tags(["personal", "shopping"]) // Explicit multi-tag deletion
delete_by_all_tags(["work", "important"]) // Delete only memories with BOTH tags
```
## 🧠 Dream-Inspired Memory Consolidation
The memory consolidation system operates autonomously in the background, inspired by how human memory works during sleep cycles. It automatically organizes, compresses, and manages your memories across multiple time horizons.
### Quick Start
Enable consolidation with a single environment variable:
```bash
export MCP_CONSOLIDATION_ENABLED=true
```
### How It Works
- **Daily consolidation** (light processing): Updates memory relevance and basic organization
- **Weekly consolidation**: Discovers creative associations between memories
- **Monthly consolidation**: Performs semantic clustering and intelligent compression
- **Quarterly/Yearly consolidation**: Deep archival and long-term memory management
### New MCP Tools Available
Once enabled, you get access to powerful new consolidation tools:
- `consolidate_memories` - Manually trigger consolidation for any time horizon
- `get_consolidation_health` - Monitor system health and performance
- `get_consolidation_stats` - View processing statistics and insights
- `schedule_consolidation` - Configure autonomous scheduling
- `get_memory_associations` - Explore discovered memory connections
- `get_memory_clusters` - Browse semantic memory clusters
- `get_consolidation_recommendations` - Get AI-powered memory management advice
### Advanced Configuration
Fine-tune the consolidation system through environment variables:
```bash
# Archive location (default: ~/.mcp_memory_archive)
export MCP_CONSOLIDATION_ARCHIVE_PATH=/path/to/archive
# Retention periods (days)
export MCP_RETENTION_CRITICAL=365 # Critical memories
export MCP_RETENTION_REFERENCE=180 # Reference materials
export MCP_RETENTION_STANDARD=30 # Standard memories
export MCP_RETENTION_TEMPORARY=7 # Temporary memories
# Association discovery settings
export MCP_ASSOCIATION_MIN_SIMILARITY=0.3 # Sweet spot range
export MCP_ASSOCIATION_MAX_SIMILARITY=0.7 # for creative connections
# Autonomous scheduling (cron-style)
export MCP_SCHEDULE_DAILY="02:00" # 2 AM daily
export MCP_SCHEDULE_WEEKLY="SUN 03:00" # 3 AM on Sundays
export MCP_SCHEDULE_MONTHLY="01 04:00" # 4 AM on 1st of month
```
### Performance
- Designed to process 10k+ memories efficiently
- Automatic hardware optimization (CPU/GPU/MPS)
- Safe archival system - no data is ever permanently deleted
- Full recovery capabilities for all archived memories
## 🚀 Service Installation (NEW!)
Install MCP Memory Service as a native system service for automatic startup:
### Cross-Platform Service Installer
```bash
# Install as a service (auto-detects OS)
python install_service.py
# Start the service
python install_service.py --start
# Check service status
python install_service.py --status
# Stop the service
python install_service.py --stop
# Uninstall the service
python install_service.py --uninstall
```
The installer provides:
- ✅ **Automatic OS detection** (Windows, macOS, Linux)
- ✅ **Native service integration** (systemd, LaunchAgent, Windows Service)
- ✅ **Automatic startup** on boot/login
- ✅ **Service management commands**
- ✅ **Secure API key generation**
- ✅ **Platform-specific optimizations**
For detailed instructions, see the [Service Installation Guide](docs/guides/service-installation.md).
## Hardware Compatibility
| Platform | Architecture | Accelerator | Status | Notes |
|----------|--------------|-------------|--------|-------|
| macOS | Apple Silicon (M1/M2/M3) | MPS | ✅ Fully supported | Best performance |
| macOS | Apple Silicon under Rosetta 2 | CPU | ✅ Supported with fallbacks | Good performance |
| macOS | Intel | CPU | ✅ Fully supported | Good with optimized settings |
| Windows | x86_64 | CUDA | ✅ Fully supported | Best performance |
| Windows | x86_64 | DirectML | ✅ Supported | Good performance |
| Windows | x86_64 | CPU | ✅ Supported with fallbacks | Slower but works |
| Linux | x86_64 | CUDA | ✅ Fully supported | Best performance |
| Linux | x86_64 | ROCm | ✅ Supported | Good performance |
| Linux | x86_64 | CPU | ✅ Supported with fallbacks | Slower but works |
| Linux | ARM64 | CPU | ✅ Supported with fallbacks | Slower but works |
| Any | Any | No PyTorch | ✅ Supported with SQLite-vec | Limited functionality, very lightweight |
## Testing
```bash
# Install test dependencies
pip install pytest pytest-asyncio
# Run all tests
pytest tests/
# Run specific test categories
pytest tests/test_memory_ops.py
pytest tests/test_semantic_search.py
pytest tests/test_database.py
# Verify environment compatibility
python scripts/verify_environment_enhanced.py
# Verify PyTorch installation on Windows
python scripts/verify_pytorch_windows.py
# Perform comprehensive installation verification
python scripts/test_installation.py
```
## FAQ
### Can I use MCP Memory Service with multiple AI clients simultaneously?
**Yes!** The service features universal multi-client coordination for seamless concurrent access across Claude Desktop, VS Code, Continue, Cursor, and other MCP clients. See the [Local Multi-Client Coordination](#-local-multi-client-coordination) section for details.
### What's the difference between SQLite-vec and ChromaDB backends?
**SQLite-vec (recommended)**: 10x faster startup, zero network dependencies, 75% less memory usage, single-file database
**ChromaDB (deprecated)**: Legacy support only, requires network access for models, will be removed in v6.0.0
➡️ **[Detailed Backend Comparison](#storage-backends)**
### How do I migrate from ChromaDB to SQLite-vec?
Run the migration script to safely transfer your existing memories:
```bash
python scripts/migrate_to_sqlite_vec.py
```
The process preserves all memories, tags, and metadata while improving performance.
### Can I deploy MCP Memory Service on a remote server?
**Yes!** The service supports production deployment with HTTP/HTTPS server, API authentication, SSL certificates, and Docker containers. Perfect for teams and cross-device access.
➡️ **[Remote Server Deployment](#-centralized-server-deployment-recommended)**
### Why does my installation fail on Apple Silicon Macs?
Use the intelligent installer which handles Apple Silicon optimizations automatically:
```bash
python install.py
```
It detects MPS support, configures fallbacks, and selects compatible PyTorch versions.
### How much memory and storage does the service use?
**SQLite-vec**: ~50MB RAM for 1K memories, single database file
**ChromaDB**: ~200MB RAM for 1K memories, multiple files
Storage scales linearly: ~1MB per 1000 memories with SQLite-vec.
### Is my data secure and private?
**Yes!** All data is stored locally by default. For remote deployments, the service supports API key authentication, HTTPS encryption, and runs in user-space (not as root) for security.
## Troubleshooting
See the [Installation Guide](docs/installation/master-guide.md) and [Troubleshooting Guide](docs/troubleshooting/general.md) for detailed troubleshooting steps.
### Quick Troubleshooting Tips
- **Windows PyTorch errors**: Use `python scripts/install_windows.py`
- **macOS Intel dependency conflicts**: Use `python install.py --force-compatible-deps`
- **Recursion errors**: Run `python scripts/fix_sitecustomize.py`
- **Environment verification**: Run `python scripts/verify_environment_enhanced.py`
- **Memory issues**: Set `MCP_MEMORY_BATCH_SIZE=4` and try a smaller model
- **Apple Silicon**: Ensure Python 3.10+ built for ARM64, set `PYTORCH_ENABLE_MPS_FALLBACK=1`
- **Installation testing**: Run `python scripts/test_installation.py`
## 📚 Comprehensive Documentation
### Installation & Setup
- **[Master Installation Guide](docs/installation/master-guide.md)** - Complete installation guide with hardware-specific paths
- **[Storage Backend Guide](docs/guides/STORAGE_BACKENDS.md)** ⭐ **NEW** - Comprehensive CLI options including multi-client setup
- **[Multi-Client Setup](docs/integration/multi-client.md)** ⭐ **NEW** - Integrated setup for any MCP application
- **[Storage Backend Comparison](docs/guides/STORAGE_BACKENDS.md)** - Detailed comparison and selection guide
- **[Migration Guide](docs/guides/migration.md)** - ChromaDB to SQLite-vec migration instructions
### Platform-Specific Guides
- **[Intel Mac Setup Guide](docs/platforms/macos-intel.md)** - Comprehensive guide for Intel Mac users
- **[Legacy Mac Guide](docs/platforms/macos-intel.md)** - Optimized for 2015 MacBook Pro and older Intel Macs
- **[Windows Setup](docs/guides/windows-setup.md)** - Windows-specific installation and troubleshooting
- **[Ubuntu Setup](docs/guides/UBUNTU_SETUP.md)** - Linux server installation guide
### API & Integration
- **[HTTP/SSE API](docs/IMPLEMENTATION_PLAN_HTTP_SSE.md)** - New web interface documentation
- **[Claude Desktop Integration](docs/guides/claude_integration.md)** - Configuration examples
- **[Integrations](docs/integrations.md)** - Third-party tools and extensions
### Advanced Topics
- **[Multi-Client Architecture](docs/development/multi-client-architecture.md)** ⭐ **NEW** - Technical implementation details
- **[Homebrew PyTorch Integration](docs/integration/homebrew.md)** - Using system PyTorch
- **[Docker Deployment](docs/deployment/docker.md)** - Container-based deployment
- **[Performance Optimization](docs/implementation/performance.md)** - Tuning for different hardware
### Troubleshooting & Support
- **[General Troubleshooting](docs/troubleshooting/general.md)** - Common issues and solutions
- **[Hardware Compatibility](docs/DOCUMENTATION_AUDIT.md)** - Compatibility matrix and known issues
### Quick Commands
```bash
# Get personalized setup recommendations
python install.py --help-detailed
# Generate hardware-specific setup guide
python install.py --generate-docs
# Test your installation
python scripts/test_memory_simple.py
```
## Project Structure
```
mcp-memory-service/
├── src/mcp_memory_service/ # Core package code
│ ├── __init__.py
│ ├── config.py # Configuration utilities
│ ├── models/ # Data models
│ ├── storage/ # Storage implementations
│ ├── utils/ # Utility functions
│ └── server.py # Main MCP server
├── scripts/ # Helper scripts
├── memory_wrapper.py # Windows wrapper script
├── install.py # Enhanced installation script
└── tests/ # Test suite
```
## Development Guidelines
- Python 3.10+ with type hints
- Use dataclasses for models
- Triple-quoted docstrings for modules and functions
- Async/await pattern for all I/O operations
- Follow PEP 8 style guidelines
- Include tests for new features
### Git Setup for Contributors
After cloning the repository, run the setup script to configure automated `uv.lock` conflict resolution:
```bash
./scripts/setup-git-merge-drivers.sh
```
This enables automatic resolution of `uv.lock` merge conflicts by:
1. Using the incoming version to resolve conflicts
2. Automatically running `uv sync` to regenerate the lock file
3. Ensuring consistent dependency resolution across all environments
The setup is required only once per clone and benefits all contributors by eliminating manual conflict resolution.
## License
MIT License - See LICENSE file for details
## Acknowledgments
- ChromaDB team for the vector database
- Sentence Transformers project for embedding models
- MCP project for the protocol specification
## 🎯 Why Sponsor MCP Memory Service?
## 🏆 In Production
- Deployed on Glama.ai
- Managing 300+ enterprise memories
- Processing queries in <1 second
### Production Impact
- **319+ memories** actively managed
- **828ms** average query response time
- **100%** cache hit ratio performance
- **20MB** efficient vector storage
### Developer Community
- Complete MCP protocol implementation
- Cross-platform compatibility
- React dashboard with real-time statistics
- Comprehensive documentation
### Enterprise Features
- Semantic search with sentence-transformers
- Tag-based categorization system
- Automatic backup and optimization
- Health monitoring dashboard
## Contact
[Telegram](https://t.me/doobeedoo)
## Integrations
The MCP Memory Service can be extended with various tools and utilities. See [Integrations](docs/integrations.md) for a list of available options, including:
- [MCP Memory Dashboard](https://github.com/doobidoo/mcp-memory-dashboard) - Web UI for browsing and managing memories
- [Claude Memory Context](https://github.com/doobidoo/claude-memory-context) - Inject memory context into Claude project instructions
```
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
```markdown
# Changelog
**Recent releases for MCP Memory Service (v8.0.0 and later)**
All notable changes to the MCP Memory Service project will be documented in this file.
For older releases, see [CHANGELOG-HISTORIC.md](./CHANGELOG-HISTORIC.md).
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [8.42.0] - 2025-11-27
### Added
- **Visible Memory Injection Display** - Users now see injected memories at session start (commit TBD)
- Added `showInjectedMemories` config option to display top 3 memories with relevance scores
- Shows memory age (e.g., "2 days ago"), tags, and relevance scores
- Formatted with colored output box for clear visibility
- Helps users understand what context the AI assistant is using
- Configurable via `~/.claude/hooks/config.json`
### Changed
- **Session-End Hook Quality Improvements** - Raised quality thresholds to prevent generic boilerplate (commit TBD)
- Increased `minSessionLength` from 100 → 200 characters (requires more substantial content)
- Increased `minConfidence` from 0.1 → 0.5 (requires 5+ meaningful items vs 1+)
- Added optional LLM-powered session summarizer using Gemini CLI
- New files: `llm-session-summarizer.js` utility and `session-end-llm.js` core hook
- Prevents low-quality memories like "User asked Claude to review code" from polluting database
- Database cleaned from 3352 → 3185 memories (167 generic entries removed)
### Fixed
- **Duplicate MCP Fallback Messages** - Fixed duplicate "MCP Fallback → Using standard MCP tools" log messages (commit TBD)
- Added module-level flag to track if fallback message was already logged
- Message now appears once per session instead of once per query
- Improved session start hook output clarity
### Performance
- **Configuration Improvements** - Better defaults for session analysis
- Enabled relevance scores in context formatting
- Improved memory scoring to prioritize quality over recency for generic content
- Session-end hook re-enabled with improved quality gates
## [8.41.2] - 2025-11-27
### Fixed
- **Hook Installer Utility File Deployment** - Installer now copies ALL utility files instead of hardcoded lists (commit 557be0e)
- **BREAKING**: Previous installer only copied 8/14 basic utilities and 5/14 enhanced utilities
- Updated files like `memory-scorer.js` and `context-formatter.js` were not deployed with `--natural-triggers` flag
- Replaced hardcoded file lists with glob pattern (`*.js`) to automatically include all utility files
- Ensures v8.41.0/v8.41.1 project affinity filtering fixes get properly deployed
- Future utility file additions automatically included without manual list maintenance
- **Impact**: Users running `python install_hooks.py --natural-triggers` now get all 14 utility files, preventing stale hooks
## [8.41.1] - 2025-11-27
### Fixed
- **Context Formatter Memory Sorting** - Memories now sorted by recency within each category (commit 2ede2a8)
- Added sorting by `created_at_iso` (descending) after grouping memories into categories
- Ensures most recent memories appear first in each section for better context relevance
- Applied in `context-formatter.js` after category grouping logic
- Improves user experience by prioritizing newest information in memory context
## [8.41.0] - 2025-11-27
### Fixed
- **Session Start Hook Reliability** - Improved session start hook reliability and memory filtering (commit 924962a)
- **Error Suppression**: Suppressed Code Execution ModuleNotFoundError spam
- Added `suppressErrors: true` to Code Execution call configuration
- Eliminates console noise from module import errors during session start
- **Clean Output**: Removed duplicate "Injected Memory Context" output
- Removed duplicate stdout console.log that caused double messages
- Session start output now cleaner and easier to read
- **Memory Filtering**: Added project affinity scoring to prevent cross-project memory pollution
- New `calculateProjectAffinity()` function in `memory-scorer.js`
- Hard filters out memories without project tag when in a project context
- Soft scoring penalty (0.3x) for memories from different projects
- Prevents Azure/Terraform memories from appearing in mcp-memory-service context
- **Classification Fix**: Session summaries no longer misclassified as "Current Problems"
- Excludes `session`, `session-summary`, and `session-end` memory types from problem classification
- Prevents confusion between historical session notes and actual current issues
- **Path Display**: "Unknown location" now shows actual path via `process.cwd()` fallback
- When git repository detection fails, uses `process.cwd()` instead of "Unknown location"
- Provides better context awareness even in non-git directories
## [8.40.0] - 2025-11-27
### Added
- **Session Start Version Display** - Automatic version information display during session startup (commit f2f7d2b, fixes #250)
- **Version Checker Utility**: New `version-checker.js` utility in `claude-hooks/utilities/`
- Reads local version from `src/mcp_memory_service/__init__.py`
- Fetches latest published version from PyPI API
- Compares versions and displays status labels (published/development/outdated)
- Configurable timeout for PyPI API requests
- **Session Start Integration**: Version information now appears automatically during session initialization
- Displays format: `📦 Version → X.Y.Z (local) • PyPI: X.Y.Z`
- Shows after storage backend information
- Provides immediate visibility into version status
- **Testing**: Includes `test_version_checker.js` for utility validation
- **Benefits**:
- Quick version verification without manual checks
- Early detection of outdated installations
- Improved development workflow transparency
- Helps users stay current with latest features and fixes
## [8.39.1] - 2025-11-27
### Fixed
- **Dashboard Analytics Bugs** - Fixed three critical bugs in the analytics section (commit c898a72, fixes #253)
- **Top Tags filtering**: Now correctly filters tags by selected timeframe (7d/30d/90d)
- Implemented time-based filtering using `get_memories_by_time_range()`
- Counts tags only from memories within the selected period
- Maintains backward compatibility with all storage backends
- **Recent Activity display**: Bars now show percentage distribution
- Enhanced display to show both count and percentage of total
- Tooltip includes both absolute count and percentage
- Activity count label shows percentage (e.g., '42 (23.5%)')
- **Storage Report field mismatches**: Fixed "undefined chars" display
- Fixed field name: `size_kb` instead of `size`
- Fixed field name: `preview` instead of `content_preview`
- Fixed date parsing: `created_at` is ISO string, not timestamp
- Added null safety and proper size display (KB with bytes fallback)
## [8.39.0] - 2025-11-26
### Performance
- **Analytics date-range filtering**: Moved from application layer to storage layer for 10x performance improvement (#238)
- Added `get_memories_by_time_range()` to Cloudflare backend with D1 database filtering
- Updated memory growth endpoint to use database-layer queries instead of fetching all memories
- **Performance gains**:
- Reduced data transfer: 50MB → 1.5MB (97% reduction for 10,000 memories)
- Response time (SQLite-vec): ~500ms → ~50ms (10x improvement)
- Response time (Cloudflare): ~2-3s → ~200ms (10-15x improvement)
- **Scalability**: Now handles databases with >10,000 memories efficiently
- **Benefits**: Pushes filtering to database WHERE clauses, leverages indexes on `created_at`
## [8.38.1] - 2025-11-26
### Fixed
- **HTTP MCP Transport: JSON-RPC 2.0 Compliance** - Fixed critical bug where HTTP MCP responses violated JSON-RPC 2.0 specification (PR #249, fixes #236)
- **Problem**: FastAPI ignored Pydantic's `ConfigDict(exclude_none=True)` when directly returning models, causing responses to include null fields (`"error": null` in success, `"result": null` in errors)
- **Impact**: Claude Code/Desktop rejected all HTTP MCP communications due to spec violation
- **Solution**: Wrapped all `MCPResponse` returns in `JSONResponse` with explicit `.model_dump(exclude_none=True)` serialization
- **Verification**:
- Success responses now contain ONLY: `jsonrpc`, `id`, `result`
- Error responses now contain ONLY: `jsonrpc`, `id`, `error`
- **Testing**: Validated with curl commands against all 5 MCP endpoint response paths
- **Credits**: @timkjr (Tim Knauff) for identifying root cause and implementing proper fix
## [8.38.0] - 2025-11-25
### Improved
- **Code Quality: Phase 2b Duplicate Consolidation COMPLETE** - Eliminated ~176-186 lines of duplicate code (issue #246)
- **Document chunk processing consolidation (Group 3)**:
- Extracted `process_document_chunk()` helper function from duplicate implementations
- Consolidated chunk_text/chunk_size/chunk_overlap pattern across document ingestion tools
- 2 occurrences reduced to 1 canonical implementation with consistent metadata handling
- **MCP response parsing consolidation (Group 3)**:
- Extracted `parse_mcp_response()` helper for isError/error/content pattern
- Standardized error handling across MCP tool invocations
- 2 occurrences reduced to 1 canonical implementation
- **Cache statistics logging consolidation (Group 5)**:
- Extracted `log_cache_statistics()` helper for storage/service cache metrics
- Standardized cache performance logging format (hits, misses, hit rates)
- 2 occurrences reduced to 1 canonical implementation with consistent percentage formatting
- **Winter season boundary logic consolidation (Group 7)**:
- Extracted `is_winter_boundary_case()` helper for cross-year winter season handling
- Centralized December-January transition logic (Dec 21 - Mar 20 spans years)
- 2 occurrences reduced to 1 canonical implementation
- **Test tempfile setup consolidation (Groups 10, 11)**:
- Extracted `create_test_document()` helper for pytest tmp_path fixture patterns
- Standardized temporary file creation across document ingestion tests
- 6 occurrences reduced to 2 canonical implementations (PDF, DOCX variants)
- **MCP server configuration consolidation (Phase 2b-3)**:
- Consolidated duplicate server config sections in install.py and scripts/installation/install.py
- Unified JSON serialization logic for mcpServers configuration blocks
- Improved maintainability through shared configuration structure
- **User input prompt consolidation (Phase 2b-2)**:
- Extracted shared prompt logic for backend selection and configuration
- Standardized input validation patterns across installation scripts
- Reduced code duplication in interactive installation workflows
- **Additional GPU detection consolidation (Phase 2b-1)**:
- Completed GPU platform detection consolidation from Phase 2a
- Refined helper function extraction for test_gpu_platform() and related utilities
- Enhanced configuration-driven GPU detection architecture
- **Consolidation Summary**:
- Total duplicate code eliminated: ~176-186 lines across 10 consolidation commits
- Functions/patterns consolidated: 10+ duplicate implementations → canonical versions
- Strategic deference: 5 groups intentionally skipped (high-risk/low-benefit per session analysis)
- Code maintainability: Enhanced through focused helper methods and consistent patterns
- 100% backward compatibility maintained (no breaking changes)
- Test coverage: 100% maintained across all consolidations
### Code Quality
- **Phase 2b Duplicate Consolidation**: 10 consolidation commits addressing multiple duplication groups
- **Duplication Score**: Reduced from 5.5% (Phase 2a baseline) to estimated 4.5-4.7%
- **Complexity Reduction**: Helper extraction pattern applied consistently across codebase
- **Expected Impact**:
- Duplication Score: Approaching <3% target with strategic consolidation
- Complexity Score: Improved through helper function extraction
- Overall Health Score: Strong progress toward 75+ target
- **Remaining Work**: 5 duplication groups intentionally deferred (high-risk backend logic, low-benefit shared imports)
- **Related**: Issue #246 Phase 2b (Duplicate Consolidation Strategy COMPLETE)
## [8.37.0] - 2025-11-24
### Improved
- **Code Quality: Phase 2a Duplicate Consolidation COMPLETE** - Eliminated 5 duplicate high-complexity functions (issue #246)
- **detect_gpu() consolidation (3 duplicates → 1 canonical)**:
- Consolidated ROOT install.py::detect_gpu() (119 lines, complexity 30) with refactored scripts/installation/install.py version (187 lines, configuration-driven)
- Refactored scripts/validation/verify_environment.py::EnvironmentVerifier.detect_gpu() (123 lines, complexity 27) to use helper-based architecture
- Final canonical implementation in install.py: GPU_PLATFORM_CHECKS config dict + test_gpu_platform() helper + CUDA_VERSION_PARSER
- Impact: -4% high-complexity functions (27 → 26), improved maintainability
- **verify_installation() consolidation (2 duplicates → 1 canonical)**:
- Replaced scripts/installation/install.py simplified version with canonical ROOT install.py implementation
- Added tokenizers check for ONNX dependencies, safer DirectML version handling
- Improved error messaging and user guidance
- **Consolidation Summary**:
- Total duplicate functions eliminated: 5 (3x detect_gpu + 2x verify_installation)
- High-complexity functions reduced: 27 → 24 (-11%)
- Code maintainability improved through focused helper methods and configuration-driven design
- 100% backward compatibility maintained (no breaking changes)
### Code Quality
- **Phase 2a Duplicate Consolidation**: 5 of 5 target functions consolidated (100% complete)
- **High-Complexity Functions**: Reduced from 27 to 24 (-11%)
- **Complexity Reduction**: Configuration-driven patterns replace monolithic if/elif chains
- **Expected Impact**:
- Duplication Score: Reduced toward <3% target
- Complexity Score: Improved through helper extraction
- Overall Health Score: On track for 75+ target
- **Related**: Issue #246 Phase 2a (Duplicate Consolidation Strategy COMPLETE)
## [8.36.1] - 2025-11-24
### Fixed
- **CRITICAL**: HTTP server crash on v8.36.0 startup - forward reference error in analytics.py (issue #247)
- Added `from __future__ import annotations` to enable forward references in type hints
- Added `Tuple` to typing imports for Python 3.9 compatibility
- Impact: Unblocks all v8.36.0 users experiencing startup failures
- Root cause: PR #244 refactoring introduced forward references without future annotations import
- Fix verified: HTTP server starts successfully, all 10 analytics routes registered
## [8.36.0] - 2025-11-24
### Improved
- **Code Quality: Phase 2 COMPLETE - 100% of Target Achieved** - Refactored final 7 functions, -19 complexity points (issue #240 PR #244)
- **consolidator.py (-8 points)**:
- `consolidate()`: 12 → 8 - Introduced SyncPauseContext for cleaner sync state management + extracted `check_horizon_requirements()` helper
- `_get_memories_for_horizon()`: 10 → 8 - Replaced conditional logic with data-driven HORIZON_CONFIGS dict lookup
- **analytics.py (-8 points)**:
- `get_tag_usage_analytics()`: 10 → 6 - Extracted `fetch_storage_stats()` and `calculate_tag_statistics()` helpers (40+ lines)
- `get_activity_breakdown()`: 9 → 7 - Extracted `calculate_activity_time_ranges()` helper (70+ lines)
- `get_memory_type_distribution()`: 9 → 7 - Extracted `aggregate_type_statistics()` helper
- **install.py (-2 points)**:
- `detect_gpu()`: 10 → 8 - Data-driven GPU_PLATFORM_CHECKS dict + extracted `test_gpu_platform()` helper
- **cloudflare.py (-1 point)**:
- `get_memory_timestamps()`: 9 → 8 - Extracted `_fetch_d1_timestamps()` method for D1 query logic
- **Gemini Review Improvements (5 iterations)**:
- **Critical Fixes**:
- Fixed timezone bug: `datetime.now()` → `datetime.now(timezone.utc)` in consolidator
- Fixed analytics double-counting: proper use of `count_all_memories()`
- CUDA/ROCm robustness: try all detection paths before failing
- **Quality Improvements**:
- Modernized deprecated APIs: `pkg_resources` → `importlib.metadata`, `universal_newlines` → `text=True`
- Enhanced error logging with `exc_info=True` for better debugging
- Improved code consistency and structure across all refactored functions
### Code Quality
- **Phase 2 Complete**: 10 of 10 functions refactored (100%)
- **Complexity Reduction**: -39 of -39 points achieved (100% of target)
- **Total Batches**:
- v8.34.0 (PR #242): `analytics.py::get_memory_growth()` (-5 points)
- v8.35.0 (PR #243): `install.py::configure_paths()`, `cloudflare.py::_search_by_tags_internal()` (-15 points)
- v8.36.0 (PR #244): Remaining 7 functions (-19 points)
- **Expected Impact**:
- Complexity Score: 40 → 51+ (+11 points, exceeded +10 target)
- Overall Health Score: 63 → 68-72 (Grade B achieved!)
- **Related**: Issue #240 Phase 2 (100% COMPLETE), Phase 1: v8.33.0 (dead code removal, +5-9 health points)
## [8.35.0] - 2025-11-24
### Improved
- **Code Quality: Phase 2 Batch 1 Complete** - Refactored 2 high-priority functions (issue #240 PR #243)
- **install.py::configure_paths()**: Complexity reduced from 15 → 5 (-10 points)
- Extracted 4 helper functions for better separation of concerns
- Main function reduced from 80 → ~30 lines
- Improved testability and maintainability
- **cloudflare.py::_search_by_tags_internal()**: Complexity reduced from 13 → 8 (-5 points)
- Extracted 3 helper functions for tag normalization and query building
- Method reduced from 75 → ~45 lines
- Better code organization
- **Gemini Review Improvements**:
- Dynamic PROJECT_ROOT detection in scripts
- Specific exception handling (OSError, IOError, PermissionError)
- Portable documentation paths
### Code Quality
- **Phase 2 Progress**: 3 of 10 functions refactored (30% complete)
- **Complexity Reduction**: -20 points achieved of -39 point target (51% of target)
- **Remaining Work**: 7 functions with implementation plans ready
- **Overall Health**: On track for 75+ target score
## [8.34.0] - 2025-11-24
### Improved
- **Code Quality: Phase 2 Complexity Reduction** - Refactored `analytics.py::get_memory_growth()` function (issue #240 Phase 2)
- Complexity reduced from 11 → 6-7 (-4 to -5 points, exceeding -3 point target)
- Introduced PeriodType Enum for type-safe period validation
- Data-driven period configuration with PERIOD_CONFIGS dict
- Data-driven label formatting with PERIOD_LABEL_FORMATTERS dict
- Improved maintainability and extensibility for analytics endpoints
### Code Quality
- Phase 2 Progress: 1 of 10 functions refactored
- Complexity Score: Estimated +1 point improvement (partial Phase 2)
- Overall Health: On track for 70+ target
## [8.33.0] - 2025-11-24
### Fixed
- **Critical Installation Bug**: Fixed early return in `install.py` that prevented Claude Desktop MCP configuration from executing (issue #240 Phase 1)
- 77 lines of Claude Desktop setup code now properly runs during installation
- Users will now get automatic MCP server configuration when running `install.py`
- Bug was at line 1358 - early `return False` in exception handler made lines 1360-1436 unreachable
- Resolves all 27 pyscn dead code violations identified in issue #240 Phase 1
### Improved
- Modernized `install.py` with pathlib throughout (via Gemini Code Assist automated review)
- Specific exception handling (OSError, PermissionError, JSONDecodeError) instead of bare `except`
- Fixed Windows `memory_wrapper.py` path resolution bug (now uses `resolve()` for absolute paths)
- Added config structure validation to prevent TypeError on malformed JSON
- Import optimization and better error messages
- Code structure improvements from 10+ Gemini Code Assist review iterations
### Code Quality
- **Dead Code Score**: 70 → 85-90 (projected +15-20 points from removing 27 violations)
- **Overall Health Score**: 63 → 68-72 (projected +5-9 points)
- All improvements applied via automated Gemini PR review workflow
## [8.32.0] - 2025-11-24
### Added
- **pyscn Static Analysis Integration**: Multi-layer quality workflow with comprehensive static analysis
- New `scripts/pr/run_pyscn_analysis.sh` for PR-time analysis with health score thresholds (blocks <50)
- New `scripts/quality/track_pyscn_metrics.sh` for historical metrics tracking (CSV storage)
- New `scripts/quality/weekly_quality_review.sh` for automated weekly reviews with regression detection
- Enhanced `scripts/pr/quality_gate.sh` with `--with-pyscn` flag for comprehensive checks
- Three-layer quality strategy: Pre-commit (Groq/Gemini LLM) → PR Gate (standard + pyscn) → Periodic (weekly)
- 6 comprehensive metrics: cyclomatic complexity, dead code, duplication, coupling, dependencies, architecture
- Health score thresholds: <50 (blocker), 50-69 (action required), 70-84 (good), 85+ (excellent)
- Complete documentation in `docs/development/code-quality-workflow.md` (651 lines)
- Integration guide in `.claude/agents/code-quality-guard.md`
- Updated `CLAUDE.md` with "Code Quality Monitoring" section
## [8.31.0] - 2025-11-23
### Added
- **Revolutionary Batch Update Performance** - Memory consolidation now 21,428x faster with new batch update API (#241)
- **Performance Improvement**: 300 seconds → 0.014 seconds for 500 memory batch updates (21,428x speedup)
- **Consolidation Workflow**: Complete consolidation time reduced from 5+ minutes to <1 second for 500 memories
- **New API Method**: `update_memories_batch()` in storage backends for atomic batch operations
- **Implementation**:
- **SQLite Backend**: Single transaction with executemany for 21,428x speedup
- **Cloudflare Backend**: Parallel batch updates with proper vectorize sync
- **Hybrid Backend**: Optimized dual-backend batch sync with queue processing
- **Backward Compatible**: Existing single-update code paths continue working
- **Real-world Impact**: Memory consolidation that previously took 5+ minutes now completes in <1 second
- **Files Modified**:
- `src/mcp_memory_service/storage/sqlite_vec.py` (lines 542-571): Batch update implementation
- `src/mcp_memory_service/storage/cloudflare.py` (lines 673-728): Cloudflare batch updates
- `src/mcp_memory_service/storage/hybrid.py` (lines 772-822): Hybrid backend batch sync
- `src/mcp_memory_service/consolidation/service.py` (line 472): Using batch update in consolidation
### Performance
- **Memory Consolidation**: 21,428x faster batch metadata updates (300s → 0.014s for 500 memories)
- **Consolidation Workflow**: Complete workflow time reduced from 5+ minutes to <1 second for 500 memories
- **Database Efficiency**: Single transaction instead of 500 individual updates with commit overhead
## [8.30.0] - 2025-11-23
### Added
- **Adaptive Chart Granularity** - Analytics charts now use semantically appropriate time intervals for better trend visualization
- **Last Month view**: Changed from 3-day intervals to weekly aggregation for clearer monthly trends
- **Last Year view**: Uses monthly aggregation for annual overview
- **Human-readable labels**: Charts display clear interval formatting:
- Daily view: "Nov 15" format
- Weekly aggregation: "Week of Nov 15" format
- Monthly aggregation: "November 2024" format
- **Improved UX**: Better semantic alignment between time period and chart granularity
- **Files Modified**: `src/mcp_memory_service/web/api/analytics.py` (lines 307-345), `src/mcp_memory_service/web/static/app.js` (line 3661)
### Fixed
- **CRITICAL: Interval Aggregation Bug** - Multi-day intervals (weekly, monthly) now correctly aggregate across entire period
- **Problem**: Intervals were only counting memories from the first day of the interval, not the entire period
- **Impact**: Analytics showed wildly inaccurate data (e.g., 0 memories instead of 427 for Oct 24-30 week)
- **Root Cause**: `strftime` format in date grouping only used the first timestamp, not the interval's date range
- **Solution**: Updated aggregation logic to properly filter and count all memories within each interval
- **Files Modified**: `src/mcp_memory_service/web/api/analytics.py` (lines 242-267)
- **CRITICAL: Data Sampling Bug** - Analytics now fetch complete historical data with proper date range filtering
- **Problem**: API only fetched 1,000 most recent memories, missing historical data for longer time periods
- **Impact**: Charts showed incomplete or missing data for older time ranges
- **Solution**: Increased fetch limit to 10,000 memories with proper `created_at >= start_date` filtering
- **Files Modified**: `src/mcp_memory_service/web/api/analytics.py` (lines 56-62)
- **Performance**: Maintains fast response times (<200ms) even with larger dataset
### Changed
- **Analytics API**: Improved data fetching with larger limits and proper date filtering for accurate historical analysis
## [8.29.0] - 2025-11-23
### Added
- **Dashboard Quick Actions: Sync Controls Widget** - Compact, real-time sync management for hybrid backend users (#234, fixes #233)
- **Real-time sync status indicator**: Visual states for synced/syncing/pending/error/paused with color-coded icons
- **Pause/Resume controls**: Safely pause background sync for database maintenance or offline work
- **Force sync button**: Manual trigger for immediate synchronization
- **Sync metrics**: Display last sync time and pending operations count
- **Clean layout**: Removed redundant sync status bar between header and body, moved to sidebar widget
- **Backend-aware**: Widget automatically hides for sqlite-vec only users (hybrid-specific feature)
- **API endpoints**:
- `POST /api/sync/pause` - Pause background sync
- `POST /api/sync/resume` - Resume background sync
- **Hybrid backend methods**: Added `pause_sync()` and `resume_sync()` for sync control
- **Automatic Scheduled Backup System** - Enterprise-grade backup with retention policies and scheduling (#234, fixes #233)
- **New backup module**: `src/mcp_memory_service/backup/` with `BackupService` and `BackupScheduler`
- **SQLite native backup API**: Uses safe `sqlite3.backup()` to prevent corruption (no file copying)
- **Async I/O**: Non-blocking backup operations with `asyncio.to_thread`
- **Flexible scheduling**: Hourly, daily, or weekly automatic backups
- **Retention policies**: Configurable by days and max backup count
- **Dashboard widget**: Backup status, last backup time, manual trigger, backup count, next scheduled time
- **Configuration via environment variables**:
- `MCP_BACKUP_ENABLED=true` (default: true)
- `MCP_BACKUP_INTERVAL=daily` (hourly/daily/weekly, default: daily)
- `MCP_BACKUP_RETENTION=7` (days, default: 7)
- `MCP_BACKUP_MAX_COUNT=10` (max backups, default: 10)
- **API endpoints**:
- `GET /api/backup/status` - Get backup status and scheduler info
- `POST /api/backup/now` - Trigger manual backup
- `GET /api/backup/list` - List available backups with metadata
- **Security**: OAuth protection on backup endpoints, no file path exposure in responses
- **Safari compatibility**: Improved event listener handling with lazy initialization
### Changed
- **Quick Actions Layout**: Moved sync controls from top status bar to sidebar widget for cleaner, more accessible UI
- **Sync State Persistence**: Pause state is now preserved during force sync operations
- **Dashboard Feedback**: Added toast notifications for sync and backup operations
### Fixed
- **Sync Button Click Events**: Resolved DOM timing issues with lazy event listeners for reliable button interactions
- **Spinner Animation**: Fixed syncing state visual feedback with proper CSS animations
- **Security**: Removed file path exposure from backup API responses (used backup IDs instead)
## [8.28.1] - 2025-11-22
### Fixed
- **CRITICAL: HTTP MCP Transport JSON-RPC 2.0 Compliance** - Fixed protocol violation causing Claude Code rejection (#236)
- **Problem**: HTTP MCP server returned `"error": null` in successful responses, violating JSON-RPC 2.0 spec which requires successful responses to OMIT the error field entirely (not include it as null)
- **Impact**: Claude Code's strict schema validation rejected all HTTP MCP responses with "Unrecognized key(s) in object: 'error'" errors, making HTTP transport completely unusable
- **Root Cause**: MCPResponse Pydantic model included both `result` and `error` fields in all responses, serializing null values
- **Solution**:
- Added `ConfigDict(exclude_none=True)` to MCPResponse model to exclude null fields from serialization
- Updated docstring to document JSON-RPC 2.0 compliance requirements
- Replaced deprecated `.dict()` with `.model_dump()` for Pydantic V2 compatibility
- Moved json import to top of file per PEP 8 style guidelines
- **Files Modified**:
- `src/mcp_memory_service/web/api/mcp.py` - Added ConfigDict, updated serialization
- **Affected Users**: All users attempting to use HTTP MCP transport with Claude Code or other strict JSON-RPC 2.0 clients
- **Testing**: Verified successful responses exclude `error` field and error responses exclude `result` field
- **Credits**: Thanks to @timkjr for identifying the issue and providing the fix
## [8.28.0] - 2025-11-21
### Added
- **Cloudflare Tag Filtering** - AND/OR operations for tag searches with unified API contracts (#228)
- Added `search_by_tags(tags, operation, time_start, time_end)` to the storage base class and implemented it across SQLite, Cloudflare, Hybrid, and HTTP client backends
- Normalized Cloudflare SQL to use `GROUP BY` + `HAVING COUNT(DISTINCT ...)` for AND semantics while supporting optional time ranges
- Introduced `get_all_tags_with_counts()` for Cloudflare to power analytics dashboards without extra queries
### Changed
- **Tag Filtering Behavior** - `get_all_memories(tags=...)` now performs exact tag comparisons with AND logic instead of substring OR matching, and hybrid storage exposes the same `operation` parameter for parity across backends.
## [8.27.2] - 2025-11-18
### Fixed
- **Memory Type Loss During Cloudflare-to-SQLite Sync** - Fixed `memory_type` not being preserved in sync script
- **Problem**: `scripts/sync/sync_memory_backends.py` did not extract or pass `memory_type` when syncing from Cloudflare to SQLite-vec
- **Impact**: All memories synced via `--direction cf-to-sqlite` showed as "untyped" (100%) in dashboard analytics
- **Root Cause**: Missing `memory_type` field in both memory dict extraction and Memory object creation
- **Solution**:
- Added `memory_type` to memory dictionary extraction from source
- Added `memory_type` and `updated_at` parameters when creating Memory objects for target storage
- **Files Modified**:
- `scripts/sync/sync_memory_backends.py` - Added memory_type and updated_at handling
- **Affected Users**: Users who ran `python scripts/sync/sync_memory_backends.py --direction cf-to-sqlite`
- **Recovery**: Re-run sync from Cloudflare to restore memory types (Cloudflare preserves original types)
## [8.27.1] - 2025-11-18
### Fixed
- **CRITICAL: Timestamp Regression Bug** - Fixed `created_at` timestamps being reset during metadata sync
- **Problem**: Bidirectional sync and drift detection (v8.25.0-v8.27.0) incorrectly reset `created_at` timestamps to current time during metadata updates
- **Impact**: All memories synced from Cloudflare → SQLite-vec appeared "just created", destroying historical timestamp data
- **Root Cause**: `preserve_timestamps=False` parameter reset **both** `created_at` and `updated_at`, when it should only update `updated_at`
- **Solution**:
- Modified `update_memory_metadata()` to preserve `created_at` from source memory during sync
- Hybrid storage now passes all 4 timestamp fields (`created_at`, `created_at_iso`, `updated_at`, `updated_at_iso`) during drift detection
- Cloudflare storage updated to handle timestamps consistently with SQLite-vec
- **Files Modified**:
- `src/mcp_memory_service/storage/sqlite_vec.py:1389-1406` - Fixed timestamp handling logic
- `src/mcp_memory_service/storage/hybrid.py:625-637, 935-947` - Pass source timestamps during sync
- `src/mcp_memory_service/storage/cloudflare.py:833-864` - Consistent timestamp handling
- **Tests Added**: `tests/test_timestamp_preservation.py` - Comprehensive test suite with 7 tests covering:
- Timestamp preservation with `preserve_timestamps=True`
- Regression test for `created_at` preservation without source timestamps
- Drift detection scenario
- Multiple sync operations
- Initial memory storage
- **Recovery Tools**:
- `scripts/validation/validate_timestamp_integrity.py` - Detect timestamp anomalies
- `scripts/maintenance/recover_timestamps_from_cloudflare.py` - Restore corrupted timestamps from Cloudflare
- **Affected Versions**: v8.25.0 (drift detection), v8.27.0 (bidirectional sync)
- **Affected Users**: Hybrid backend users who experienced automatic drift detection or initial sync
- **Data Recovery**: If using hybrid backend and Cloudflare has correct timestamps, run recovery script:
```bash
# Preview recovery
python scripts/maintenance/recover_timestamps_from_cloudflare.py --dry-run
# Apply recovery
python scripts/maintenance/recover_timestamps_from_cloudflare.py --apply
```
### Changed
- **Timestamp Handling Semantics** - Clarified `preserve_timestamps` parameter behavior:
- `preserve_timestamps=True` (default): Only updates `updated_at` to current time, preserves `created_at`
- `preserve_timestamps=False`: Uses timestamps from `updates` dict if provided, otherwise preserves existing `created_at`
- **Never** resets `created_at` to current time (this was the bug)
### Added
- **Timestamp Integrity Validation** - New script to detect timestamp anomalies:
```bash
python scripts/validation/validate_timestamp_integrity.py
```
- Checks for impossible timestamps (`created_at > updated_at`)
- Detects suspicious timestamp clusters (bulk reset indicators)
- Analyzes timestamp distribution for anomalies
- Provides detailed statistics and warnings
## [8.27.0] - 2025-11-17
### Added
- **Hybrid Storage Sync Performance Optimization** - Dramatic initial sync speed improvement (3-5x faster)
- **Performance Metrics**:
- **Before**: ~5.5 memories/second (8 minutes for 2,619 memories)
- **After**: ~15-30 memories/second (1.5-3 minutes for 2,619 memories)
- **3-5x faster** initial sync from Cloudflare to local SQLite
- **Optimizations**:
- **Bulk Existence Check**: `get_all_content_hashes()` method eliminates 2,619 individual DB queries
- **Parallel Processing**: `asyncio.gather()` with Semaphore(15) for concurrent memory processing
- **Larger Batch Sizes**: Increased from 100 to 500 memories per Cloudflare API call (5x fewer requests)
- **Files Modified**:
- `src/mcp_memory_service/storage/sqlite_vec.py` - Added `get_all_content_hashes()` method (lines 1208-1227)
- `src/mcp_memory_service/storage/hybrid.py` - Parallel sync implementation (lines 859-921)
- `scripts/benchmarks/benchmark_hybrid_sync.py` - Performance validation script
- **Backward Compatibility**: Zero breaking changes, transparent optimization for all sync operations
- **Use Case**: Users with large memory databases (1000+ memories) will see significantly faster initial sync times
### Changed
- **Hybrid Initial Sync Architecture** - Refactored sync loop for better performance
- O(1) hash lookups instead of O(n) individual queries
- Concurrent processing with controlled parallelism (15 simultaneous operations)
- Reduced Cloudflare API overhead with larger batches (6 API calls vs 27)
- Maintains full drift detection and metadata synchronization capabilities
### Fixed
- **Duplicate Sync Queue Architecture** - Resolved inefficient dual-sync issue
- **Problem**: MCP server and HTTP server each created separate HybridStorage instances with independent sync queues
- **Impact**: Duplicate sync work, potential race conditions, memory not immediately visible across servers
- **Solution**: New `MCP_HYBRID_SYNC_OWNER` configuration to control which process handles Cloudflare sync
- **Configuration Options**:
- `"http"` - HTTP server only handles sync (recommended - avoids duplicate work)
- `"mcp"` - MCP server only handles sync
- `"both"` - Both servers sync independently (default for backward compatibility)
- **Files Modified**:
- `src/mcp_memory_service/config.py` - Added `HYBRID_SYNC_OWNER` configuration (lines 424-427)
- `src/mcp_memory_service/storage/factory.py` - Server-type aware storage creation (lines 76-110)
- `src/mcp_memory_service/mcp_server.py` - Pass server_type="mcp" (line 143)
- `src/mcp_memory_service/web/dependencies.py` - Pass server_type="http" (line 65)
- **Migration Guide**:
```bash
# Recommended: Set HTTP server as sync owner to eliminate duplicate sync
export MCP_HYBRID_SYNC_OWNER=http
```
- **Backward Compatibility**: Defaults to "both" (existing behavior), no breaking changes
### Performance
- **Benchmark Results** (`python scripts/benchmarks/benchmark_hybrid_sync.py`):
- Bulk hash loading: 2,619 hashes loaded in ~100ms (vs ~13,000ms for individual queries)
- Parallel processing: 15x concurrency reduces CPU idle time
- Batch size optimization: 78% reduction in API calls (27 → 6 for 2,619 memories)
- Combined speedup: 3-5x faster initial sync
## [8.26.0] - 2025-11-16
### Added
- **Global MCP Server Caching** - Revolutionary performance improvement for MCP tools (PR #227)
- **Performance Metrics**:
- **534,628x faster** on cache hits (1,810ms → 0.01ms per MCP tool call)
- **99.9996% latency reduction** for cached operations
- **90%+ cache hit rate** in normal usage patterns
- **MCP tools now 41x faster** than HTTP API after warm-up
- **New MCP Tool**: `get_cache_stats` - Real-time cache performance monitoring
- Track hits/misses, hit rate percentage
- Monitor storage and service cache sizes
- View initialization time statistics (avg/min/max)
- **Infrastructure**:
- Global cache structures: `_STORAGE_CACHE`, `_MEMORY_SERVICE_CACHE`, `_CACHE_STATS`
- Thread-safe concurrent access via `asyncio.Lock`
- Automatic cleanup on server shutdown (no memory leaks)
- **Files Modified**:
- `src/mcp_memory_service/server.py` - Production MCP server caching
- `src/mcp_memory_service/mcp_server.py` - FastMCP server caching
- `src/mcp_memory_service/utils/cache_manager.py` - New cache management utilities
- `scripts/benchmarks/benchmark_server_caching.py` - Cache effectiveness validation
- **Backward Compatibility**: Zero breaking changes, transparent caching for all MCP clients
- **Use Case**: MCP tools in Claude Desktop and Claude Code are now the fastest method for memory operations
### Changed
- **Code Quality Improvements** - Gemini Code Assist review implementation (PR #227)
- Eliminated code duplication across `server.py` and `mcp_server.py`
- Created shared `CacheManager.calculate_stats()` utility for statistics
- Enhanced PEP 8 compliance with proper naming conventions
- Added comprehensive inline documentation for cache implementation
### Fixed
- **Security Vulnerability** - Removed unsafe `eval()` usage in benchmark script (PR #227)
- Replaced `eval(stats_str)` with safe `json.loads()` for parsing cache statistics
- Eliminated arbitrary code execution risk in development tools
- Improved benchmark script robustness
### Performance
- **Benchmark Results** (10 consecutive MCP tool calls):
- First Call (Cache Miss): ~2,485ms
- Cached Calls Average: ~0.01ms
- Speedup Factor: 534,628x
- Cache Hit Rate: 90%
- **Impact**: MCP tools are now the recommended method for Claude Desktop and Claude Code users
- **Technical Details**:
- Caches persist across stateless HTTP calls
- Storage instances keyed by "{backend}:{path}"
- MemoryService instances keyed by storage ID
- Lazy initialization preserved to prevent startup hangs
### Documentation
- Updated Wiki: 05-Performance-Optimization.md with cache architecture
- Added cache monitoring guide using `get_cache_stats` tool
- Performance comparison tables now show MCP as fastest method
## [8.25.2] - 2025-11-16
### Changed
- **Drift Detection Script Refactoring** - Improved code maintainability in `check_drift.py` (PR #226)
- **Refactored**: Cloudflare config dictionary construction to use dictionary comprehension
- **Improvement**: Separated configuration keys list from transformation logic
- **Benefit**: Easier to maintain and modify configuration keys
- **Code Quality**: More Pythonic, cleaner, and more readable
- **Impact**: No functional changes, pure code quality improvement
- **File Modified**: `scripts/sync/check_drift.py`
- **Credit**: Implements Gemini code review suggestions from PR #224
## [8.25.1] - 2025-11-16
### Fixed
- **Drift Detection Script Initialization** - Corrected critical bugs in `check_drift.py` (PR #224)
- **Bug 1**: Fixed incorrect config attribute `SQLITE_DB_PATH` → `SQLITE_VEC_PATH` in AppConfig
- **Bug 2**: Added missing `cloudflare_config` parameter to HybridMemoryStorage initialization
- **Impact**: Script was completely broken for Cloudflare/Hybrid backends - now initializes successfully
- **Error prevented**: `AttributeError: 'AppConfig' object has no attribute 'SQLITE_DB_PATH'`
- **File Modified**: `scripts/sync/check_drift.py`
- **Severity**: High - Script was non-functional for users with hybrid or cloudflare backends
- **CI Test Infrastructure** - Added HuggingFace model caching to prevent network-related test failures (PR #225)
- **Root Cause**: GitHub Actions runners cannot access huggingface.co during test runs
- **Solution**: Implemented `actions/cache@v3` for `~/.cache/huggingface` directory
- **Pre-download step**: Downloads `all-MiniLM-L6-v2` model after dependency installation
- **Impact**: Fixes all future PR test failures caused by model download restrictions
- **Cache Strategy**: Key includes `pyproject.toml` hash for dependency tracking
- **Performance**: First run downloads model, subsequent runs use cache
- **File Modified**: `.github/workflows/main.yml`
### Technical Details
- **PR #224**: Drift detection script now properly initializes Cloudflare backend with all required parameters (api_token, account_id, d1_database_id, vectorize_index)
- **PR #225**: CI environment now caches embedding models, eliminating network dependency during test execution
- **Testing**: Both fixes validated in PR test runs - drift detection now works, tests pass consistently
## [8.25.0] - 2025-11-15
### Added
- **Hybrid Backend Drift Detection** - Automatic metadata synchronization using `updated_at` timestamps (issue #202)
- **Bidirectional awareness**: Detects metadata changes on either backend (SQLite-vec ↔ Cloudflare)
- **Periodic drift checks**: Configurable interval via `MCP_HYBRID_DRIFT_CHECK_INTERVAL` (default: 1 hour)
- **"Newer timestamp wins" conflict resolution**: Prevents data loss during metadata updates
- **Dry-run support**: Preview changes via `python scripts/sync/check_drift.py`
- **New configuration variables**:
- `MCP_HYBRID_SYNC_UPDATES` - Enable metadata sync (default: true)
- `MCP_HYBRID_DRIFT_CHECK_INTERVAL` - Seconds between drift checks (default: 3600)
- `MCP_HYBRID_DRIFT_BATCH_SIZE` - Memories to check per scan (default: 100)
- **New methods**:
- `BackgroundSyncService._detect_and_sync_drift()` - Core drift detection logic with dry-run mode
- `CloudflareStorage.get_memories_updated_since()` - Query memories by update timestamp
- **Enhanced initial sync**: Now detects and syncs metadata drift for existing memories
### Fixed
- **Issue #202** - Hybrid backend now syncs metadata updates (tags, types, custom fields)
- Previous behavior only detected missing memories, ignoring metadata changes
- Prevented silent data loss when memories updated on one backend but not synced
- Tag fixes in Cloudflare now properly propagate to local SQLite
- Metadata updates no longer diverge between backends
### Changed
- Initial sync (`_perform_initial_sync`) now compares timestamps for existing memories
- Periodic sync includes drift detection checks at configurable intervals
- Sync statistics tracking expanded with drift detection metrics
### Technical Details
- **Files Modified**:
- `src/mcp_memory_service/config.py` - Added 3 configuration variables
- `src/mcp_memory_service/storage/hybrid.py` - Drift detection implementation (~150 lines)
- `src/mcp_memory_service/storage/cloudflare.py` - Added `get_memories_updated_since()` method
- `scripts/sync/check_drift.py` - New dry-run validation script
- **Architecture**: Timestamp-based drift detection with 1-second clock skew tolerance
- **Performance**: Non-blocking async operations, configurable batch sizes
- **Safety**: Opt-in feature, dry-run mode, comprehensive audit logging
## [8.24.4] - 2025-11-15
### Changed
- **Code Quality Improvements** - Applied Gemini Code Assist review suggestions (issue #180)
- **documents.py:87** - Replaced chained `.replace()` calls with `re.sub()` for path separator sanitization
- **app.js:751-762** - Cached DOM elements in setProcessingMode to reduce query overhead
- **app.js:551-553, 778-780** - Cached upload option elements to optimize handleDocumentUpload
- **index.html:357, 570** - Fixed indentation consistency for closing `</div>` tags
- Performance impact: Minor - reduced DOM query overhead
- Breaking changes: None
### Technical Details
- **Files Modified**: `src/mcp_memory_service/web/api/documents.py`, `src/mcp_memory_service/web/static/app.js`, `src/mcp_memory_service/web/static/index.html`
- **Code Quality**: Regex-based sanitization more scalable, DOM element caching reduces redundant queries
- **Commit**: ffc6246 - refactor: code quality improvements from Gemini review (issue #180)
## [8.24.3] - 2025-11-15
### Fixed
- **GitHub Release Manager Agent** - Resolved systematic version history omission in README.md (commit ccf959a)
- Fixed agent behavior that was omitting previous versions from "Previous Releases" section
- Added v8.24.1 to Previous Releases list (was missing despite being valid release)
- Enhanced agent instructions with CRITICAL section for maintaining version history integrity
- Added quality assurance checklist item to prevent future omissions
- Root cause: Agent was replacing entire Previous Releases section instead of prepending new version
### Added
- **Test Coverage for Tag+Time Filtering** - Comprehensive test suite for issue #216 (commit ebff282)
- 10 unit tests passing across SQLite-vec, Cloudflare, and Hybrid backends
- Validates PR #215 functionality (tag+time filtering to fix semantic over-filtering bug #214)
- Tests verify memories can be retrieved using both tag criteria AND time range filters
- API integration tests created (with known threading issues documented for future fix)
- Ensures regression prevention for semantic search over-filtering bug
### Changed
- GitHub release workflow now more reliable with enhanced agent guardrails
- Test suite provides better coverage for multi-filter memory retrieval scenarios
### Technical Details
- **Files Modified**:
- `.claude/agents/github-release-manager.md` - Added CRITICAL section for Previous Releases maintenance
- `tests/test_time_filtering.py` - 10 new unit tests for tag+time filtering
- `tests/integration/test_api_time_search.py` - API integration tests (threading issues documented)
- **Test Execution**: All 10 unit tests passing, API tests have known threading limitations
- **Impact**: Prevents version history loss in future releases, ensures tag+time filtering remains functional
## [8.24.2] - 2025-11-15
### Fixed
- **CI/CD Workflow Infrastructure** - Development Setup Validation workflow fixes (issue #217 related)
- Fixed bash errexit handling in workflow tests - prevents premature exit on intentional test failures
- Corrected exit code capture using EXIT_CODE=0 and || EXIT_CODE=$? pattern
- All 5 workflow tests now passing: version consistency, pre-commit hooks, server warnings, developer prompts, docs accuracy
- Root cause: bash runs with -e flag (errexit), which exits immediately when commands return non-zero exit codes
- Tests intentionally run check_dev_setup.py expecting exit code 1, but bash was exiting before capture
- Commits: b4f9a5a, d1bcd67
### Changed
- Workflow tests can now properly validate that the development setup validator correctly detects problems
- Exit code capture no longer uses "|| true" pattern (was making all commands return 0)
### Technical Details
- **Files Modified**: .github/workflows/dev-setup-validation.yml
- **Pattern Change**:
- Before: `python script.py || true` (always returns 0, breaks exit code testing)
- After: `EXIT_CODE=0; python script.py || EXIT_CODE=$?` (captures actual exit code, prevents bash exit)
- **Test Jobs**: All 5 jobs in dev-setup-validation workflow now pass consistently
- **Context**: Part of test infrastructure improvement efforts (issue #217)
## [8.24.1] - 2025-11-15
### Fixed
- **Test Infrastructure Failures** - Resolved 27 pre-existing test failures (issue #217)
- Fixed async fixture incompatibility in 6 test files (19+ failures)
- Corrected missing imports (MCPMemoryServer → MemoryServer, removed MemoryMetadata)
- Added missing content_hash parameter to Memory() instantiations
- Updated hardcoded version strings (6.3.0 → 8.24.0)
- Improved test pass rate from 63% to 71% (412/584 tests passing)
- Execution: Automated via amp-bridge agent
### Changed
- Test suite now has cleaner baseline for detecting new regressions
- All async test fixtures now use @pytest_asyncio.fixture decorator
### Technical Details
- **Automated Fix**: Used amp-bridge agent for pattern-based refactoring
- **Execution Time**: ~15 minutes (vs 1-2 hours manual)
- **Files Modified**: 11 test files across tests/ and tests/integration/
- **Root Causes**: Test infrastructure issues, not code bugs
- **Remaining Failures**: 172 failures remain (backend config, performance, actual bugs)
## [8.24.0] - 2025-11-12
### Added
- **PyPI Publishing Automation** - Package now available via `pip install mcp-memory-service`
- **Workflow Automation**: Configured GitHub Actions workflow to automatically publish to PyPI on tag pushes
- **Installation Simplification**: Users can now install directly via `pip install mcp-memory-service` or `uv pip install mcp-memory-service`
- **Accessibility**: Resolves installation barriers for users without git access or familiarity
- **Token Configuration**: Secured with `PYPI_TOKEN` GitHub secret for automated publishing
- **Quality Gates**: Publishes only after successful test suite execution
### Changed
- **Distribution Method**: Added PyPI as primary distribution channel alongside GitHub releases
- **Installation Documentation**: Updated guides to include pip-based installation as recommended method
### Technical Details
- **Files Modified**:
- `.github/workflows/publish.yml` - NEW workflow for automated PyPI publishing
- GitHub repository secrets - Added `PYPI_TOKEN` for authentication
- **Trigger**: Workflow runs automatically on git tag creation (pattern: `v*.*.*`)
- **Build System**: Uses Hatchling build backend with `python-semantic-release`
### Migration Notes
- **For New Users**: Preferred installation is now `pip install mcp-memory-service`
- **For Existing Users**: No action required - git-based installation continues to work
- **For Contributors**: Tag creation now triggers PyPI publishing automatically
## [8.23.1] - 2025-11-10
### Fixed
- **Stale Virtual Environment Prevention System** - Comprehensive 6-layer strategy to prevent "stale venv vs source code" version mismatches
- **Root Cause**: MCP servers load from site-packages, not source files. System restart doesn't help - it relaunches with same stale package
- **Impact**: Prevented issue that caused v8.23.0 tag validation bug to persist despite v8.22.2 fix (source showed v8.23.0 while venv had v8.5.3)
### Added
- **Phase 1: Automated Detection**
- New `scripts/validation/check_dev_setup.py` - Validates source/venv version consistency, detects editable installs
- Enhanced `scripts/hooks/pre-commit` - Blocks commits when venv is stale, provides actionable error messages
- Added CLAUDE.md development setup section with explicit `pip install -e .` guidance
- **Phase 2: Runtime Warnings**
- Added `check_version_consistency()` function in `src/mcp_memory_service/server.py`
- Server startup warnings when version mismatch detected (source vs package)
- Updated README.md developer section with editable install instructions
- Enhanced `docs/development/ai-agent-instructions.md` with proper setup commands
- **Phase 3: Interactive Onboarding**
- Enhanced `scripts/installation/install.py` with developer detection (checks for git repo)
- Interactive prompt guides developers to use `pip install -e .` for editable installs
- New CI/CD workflow `.github/workflows/dev-setup-validation.yml` with 5 comprehensive test jobs:
1. Version consistency validation
2. Pre-commit hook functionality
3. Server startup warnings
4. Interactive developer prompts
5. Documentation accuracy checks
### Changed
- **Developer Workflow**: Developers now automatically guided to use `pip install -e .` for proper setup
- **Pre-commit Hook**: Now validates venv consistency before allowing commits
- **Installation Process**: Detects developer mode and provides targeted guidance
### Technical Details
- **6-Layer Prevention System**:
1. **Development**: Pre-commit hook blocks bad commits, detection script validates setup
2. **Runtime**: Server startup warnings catch edge cases
3. **Documentation**: CLAUDE.md, README.md, ai-agent-instructions.md all updated
4. **Automation**: check_dev_setup.py, pre-commit hook, CI/CD workflow
5. **Interactive**: install.py prompts developers for editable install
6. **Testing**: CI/CD workflow with 5 comprehensive test jobs
- **Files Modified**:
- `scripts/validation/check_dev_setup.py` - NEW automated detection script
- `scripts/hooks/pre-commit` - Enhanced with venv validation
- `CLAUDE.md` - Added development setup guidance
- `src/mcp_memory_service/server.py` - Added runtime version check
- `README.md` - Updated developer section
- `docs/development/ai-agent-instructions.md` - Updated setup commands
- `scripts/installation/install.py` - Added developer detection
- `.github/workflows/dev-setup-validation.yml` - NEW CI/CD validation
### Migration Notes
- **For Developers**: Run `pip install -e .` to install in editable mode (will be prompted by install.py)
- **For Users**: No action required - prevention system is transparent for production use
- **Pre-commit Hook**: Automatically installed during `install.py`, validates on every commit
### Commits Included
- `670fb74` - Phase 1: Automated detection (check_dev_setup.py, pre-commit hook, CLAUDE.md)
- `9537259` - Phase 2: Runtime warnings (server.py) + developer documentation
- `a17bcc7` - Phase 3: Interactive onboarding (install.py) + CI/CD validation
```
--------------------------------------------------------------------------------
/claude-hooks/core/session-start.js:
--------------------------------------------------------------------------------
```javascript
/**
* Claude Code Session Start Hook
* Automatically injects relevant memories at the beginning of each session
*/
const fs = require('fs').promises;
const path = require('path');
// Import utilities
const { detectProjectContext } = require('../utilities/project-detector');
const { scoreMemoryRelevance, analyzeMemoryAgeDistribution, calculateAdaptiveGitWeight } = require('../utilities/memory-scorer');
const { formatMemoriesForContext } = require('../utilities/context-formatter');
const { detectContextShift, extractCurrentContext, determineRefreshStrategy } = require('../utilities/context-shift-detector');
const { analyzeGitContext, buildGitContextQuery } = require('../utilities/git-analyzer');
const { MemoryClient } = require('../utilities/memory-client');
const { getVersionInfo, formatVersionDisplay } = require('../utilities/version-checker');
/**
* Load hook configuration
*/
async function loadConfig() {
try {
const configPath = path.join(__dirname, '../config.json');
const configData = await fs.readFile(configPath, 'utf8');
return JSON.parse(configData);
} catch (error) {
console.warn('[Memory Hook] Using default configuration:', error.message);
return {
memoryService: {
protocol: 'auto',
preferredProtocol: 'http',
fallbackEnabled: true,
http: {
endpoint: 'http://127.0.0.1:8889',
apiKey: 'test-key-123',
healthCheckTimeout: 3000,
useDetailedHealthCheck: false
},
mcp: {
serverCommand: ['uv', 'run', 'memory', 'server'],
serverWorkingDir: null,
connectionTimeout: 5000,
toolCallTimeout: 10000
},
defaultTags: ['claude-code', 'auto-generated'],
maxMemoriesPerSession: 8,
injectAfterCompacting: false
},
projectDetection: {
gitRepository: true,
packageFiles: ['package.json', 'pyproject.toml', 'Cargo.toml'],
frameworkDetection: true,
languageDetection: true
},
output: {
verbose: true, // Default to verbose for backward compatibility
showMemoryDetails: false, // Hide detailed memory scoring by default
showProjectDetails: true, // Show project detection by default
showScoringDetails: false, // Hide detailed scoring breakdown
cleanMode: false // Default to normal output
}
};
}
}
/**
* Query memory service for health information (supports both HTTP and MCP)
*/
async function queryMemoryHealth(memoryClient) {
try {
const healthResult = await memoryClient.getHealthStatus();
return healthResult;
} catch (error) {
return {
success: false,
error: error.message,
fallback: true
};
}
}
/**
* Parse health data into storage info structure (supports both HTTP and MCP responses)
*/
function parseHealthDataToStorageInfo(healthData) {
try {
// Handle MCP tool response format
if (healthData.content && Array.isArray(healthData.content)) {
const textContent = healthData.content.find(c => c.type === 'text')?.text;
if (textContent) {
try {
// Parse JSON from MCP response
const parsedData = JSON.parse(textContent.replace(/'/g, '"').replace(/True/g, 'true').replace(/False/g, 'false').replace(/None/g, 'null'));
return parseHealthDataToStorageInfo(parsedData);
} catch (parseError) {
console.warn('[Memory Hook] Could not parse MCP health response:', parseError.message);
return getUnknownStorageInfo();
}
}
}
// Handle direct health data object
const storage = healthData.storage || healthData || {};
const system = healthData.system || {};
const statistics = healthData.statistics || healthData.stats || {};
// Determine icon based on backend
let icon = '💾';
switch (storage.backend?.toLowerCase()) {
case 'sqlite-vec':
case 'sqlite_vec':
icon = '🪶';
break;
case 'chromadb':
case 'chroma':
icon = '📦';
break;
case 'cloudflare':
icon = '☁️';
break;
}
// Build description with status
const backendName = storage.backend ? storage.backend.replace('_', '-') : 'Unknown';
const statusText = storage.status === 'connected' ? 'Connected' :
storage.status === 'disconnected' ? 'Disconnected' :
storage.status || 'Unknown';
const description = `${backendName} (${statusText})`;
// Build location info (use cwd as better fallback than "Unknown")
let location = storage.database_path || storage.location || process.cwd();
if (location.length > 50) {
location = '...' + location.substring(location.length - 47);
}
// Determine type (local/remote/cloud)
let type = 'unknown';
if (storage.backend === 'cloudflare') {
type = 'cloud';
} else if (storage.database_path && storage.database_path.startsWith('/')) {
type = 'local';
} else if (location.includes('://')) {
type = 'remote';
} else {
type = 'local';
}
return {
backend: storage.backend || 'unknown',
type: type,
location: location,
description: description,
icon: icon,
// Rich health data
health: {
status: storage.status,
totalMemories: statistics.total_memories || storage.total_memories || 0,
databaseSizeMB: statistics.database_size_mb || storage.database_size_mb || 0,
uniqueTags: statistics.unique_tags || storage.unique_tags || 0,
embeddingModel: storage.embedding_model || 'Unknown',
platform: system.platform,
uptime: healthData.uptime_seconds,
accessible: storage.accessible
}
};
} catch (error) {
return getUnknownStorageInfo();
}
}
/**
* Get unknown storage info structure
*/
function getUnknownStorageInfo() {
return {
backend: 'unknown',
type: 'unknown',
location: 'Health parse error',
description: 'Unknown Storage',
icon: '❓',
health: { status: 'error', totalMemories: 0 }
};
}
/**
* Detect storage backend configuration (fallback method)
*/
function detectStorageBackendFallback(config) {
try {
// Check environment variable first
const envBackend = process.env.MCP_MEMORY_STORAGE_BACKEND?.toLowerCase();
const endpoint = config.memoryService?.http?.endpoint || 'http://127.0.0.1:8889';
// Parse endpoint to determine if local or remote
const url = new URL(endpoint);
const isLocal = url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname.endsWith('.local');
let storageInfo = {
backend: 'unknown',
type: 'unknown',
location: endpoint,
description: 'Unknown Storage',
icon: '💾',
health: { status: 'unknown', totalMemories: 0 }
};
if (envBackend) {
switch (envBackend) {
case 'sqlite_vec':
storageInfo = {
backend: 'sqlite_vec',
type: 'local',
location: process.env.MCP_MEMORY_SQLITE_PATH || '~/.mcp-memory/memories.db',
description: 'SQLite-vec (Config)',
icon: '🪶',
health: { status: 'unknown', totalMemories: 0 }
};
break;
case 'chromadb':
case 'chroma':
const chromaHost = process.env.MCP_MEMORY_CHROMADB_HOST;
const chromaPath = process.env.MCP_MEMORY_CHROMA_PATH;
if (chromaHost) {
// Remote ChromaDB
const chromaPort = process.env.MCP_MEMORY_CHROMADB_PORT || '8000';
const ssl = process.env.MCP_MEMORY_CHROMADB_SSL === 'true';
const protocol = ssl ? 'https' : 'http';
storageInfo = {
backend: 'chromadb',
type: 'remote',
location: `${protocol}://${chromaHost}:${chromaPort}`,
description: 'ChromaDB (Remote Config)',
icon: '🌐',
health: { status: 'unknown', totalMemories: 0 }
};
} else {
// Local ChromaDB
storageInfo = {
backend: 'chromadb',
type: 'local',
location: chromaPath || '~/.mcp-memory/chroma',
description: 'ChromaDB (Config)',
icon: '📦',
health: { status: 'unknown', totalMemories: 0 }
};
}
break;
case 'cloudflare':
const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
storageInfo = {
backend: 'cloudflare',
type: 'cloud',
location: accountId ? `Account: ${accountId.substring(0, 8)}...` : 'Cloudflare Workers',
description: 'Cloudflare Vector (Config)',
icon: '☁️',
health: { status: 'unknown', totalMemories: 0 }
};
break;
}
} else {
// Fallback: infer from endpoint
if (isLocal) {
storageInfo = {
backend: 'local_service',
type: 'local',
location: endpoint,
description: 'Local MCP Service',
icon: '💾',
health: { status: 'unknown', totalMemories: 0 }
};
} else {
storageInfo = {
backend: 'remote_service',
type: 'remote',
location: endpoint,
description: 'Remote MCP Service',
icon: '🌐',
health: { status: 'unknown', totalMemories: 0 }
};
}
}
return storageInfo;
} catch (error) {
return {
backend: 'unknown',
type: 'unknown',
location: 'Configuration Error',
description: 'Unknown Storage',
icon: '❓',
health: { status: 'error', totalMemories: 0 }
};
}
}
/**
* Query memory service using code execution (token-efficient)
*/
async function queryMemoryServiceViaCode(query, config) {
const startTime = Date.now();
const enableMetrics = config?.codeExecution?.enableMetrics !== false;
try {
const { execSync } = require('child_process');
// Escape query strings for safe shell execution
const escapeForPython = (str) => str.replace(/"/g, '\\"').replace(/\n/g, '\\n');
// Build Python code for memory search with time filter support
// Use v8.19.0+ Code Execution Interface API for optimal performance
const pythonCode = query.timeFilter ? `
import sys
import json
from datetime import datetime
from mcp_memory_service.api import search
try:
# Execute search with time filter (v8.21.0+ API enhancement)
results = search("${escapeForPython(query.semanticQuery || '')}", limit=${query.limit || 8}, time_filter="${escapeForPython(query.timeFilter)}")
# Format compact output
output = {
'success': True,
'memories': [
{
'hash': m.hash,
'preview': m.preview,
'tags': list(m.tags),
'created': m.created,
'created_at': m.created,
'created_at_iso': datetime.fromtimestamp(m.created).isoformat(),
'score': m.score,
'content': m.preview # Use preview as content for compatibility
}
for m in results.memories
],
'total': results.total,
'method': 'code_execution'
}
print(json.dumps(output))
sys.exit(0)
except Exception as e:
print(json.dumps({'success': False, 'error': str(e), 'method': 'code_execution'}))
sys.exit(1)
` : `
import sys
import json
from datetime import datetime
from mcp_memory_service.api import search
try:
# Execute search with semantic query and limit
results = search("${escapeForPython(query.semanticQuery || '')}", limit=${query.limit || 8})
# Format compact output
output = {
'success': True,
'memories': [
{
'hash': m.hash,
'preview': m.preview,
'tags': list(m.tags),
'created': m.created,
'created_at': m.created,
'created_at_iso': datetime.fromtimestamp(m.created).isoformat(),
'score': m.score,
'content': m.preview # Use preview as content for compatibility
}
for m in results.memories
],
'total': results.total,
'method': 'code_execution'
}
print(json.dumps(output))
sys.exit(0)
except Exception as e:
print(json.dumps({'success': False, 'error': str(e), 'method': 'code_execution'}))
sys.exit(1)
`;
// Get Python path from config
const pythonPath = config?.codeExecution?.pythonPath || 'python3';
const timeout = config?.codeExecution?.timeout || 5000;
// Execute Python code with timeout
const result = execSync(`${pythonPath} -c "${pythonCode.replace(/"/g, '\\"')}"`, {
encoding: 'utf-8',
timeout: timeout,
stdio: ['pipe', 'pipe', 'pipe']
});
const parsed = JSON.parse(result);
if (parsed.success) {
const executionTime = Date.now() - startTime;
// Calculate token savings estimate
const memoriesRetrieved = (parsed.memories || []).length;
const mcpTokens = 1200 + (memoriesRetrieved * 300); // Conservative MCP estimate
const codeTokens = 20 + (memoriesRetrieved * 25); // Code execution tokens
const tokensSaved = mcpTokens - codeTokens;
const reductionPercent = ((tokensSaved / mcpTokens) * 100).toFixed(1);
// Store metrics for reporting
if (enableMetrics) {
parsed._metrics = {
executionTime,
memoriesRetrieved,
mcpTokensEstimate: mcpTokens,
codeTokensEstimate: codeTokens,
tokensSaved,
reductionPercent
};
}
return parsed.memories || [];
} else {
throw new Error(parsed.error || 'Code execution failed');
}
} catch (error) {
// Silently return null to trigger MCP fallback
// Error logging suppressed - fallback is expected when module not installed
return null;
}
}
/**
* Query memory service for relevant memories (supports code execution with MCP fallback)
*/
async function queryMemoryService(memoryClient, query, config) {
const startTime = Date.now();
try {
// Check if code execution is enabled
const codeExecutionEnabled = config?.codeExecution?.enabled !== false; // Default true
const fallbackToMCP = config?.codeExecution?.fallbackToMCP !== false; // Default true
const enableMetrics = config?.codeExecution?.enableMetrics !== false;
// Phase 1: Try code execution first (75% token reduction)
if (codeExecutionEnabled) {
const codeResult = await queryMemoryServiceViaCode(query, config);
if (codeResult !== null) {
const executionTime = Date.now() - startTime;
// Extract metrics if available
const metrics = codeResult._metrics || {};
// Success! Log token savings
if (config?.output?.verbose && config?.output?.showMemoryDetails && enableMetrics) {
const tokenInfo = metrics.reductionPercent ?
` ${CONSOLE_COLORS.GRAY}(${metrics.reductionPercent}% reduction, ${metrics.tokensSaved} tokens saved)${CONSOLE_COLORS.RESET}` :
` ${CONSOLE_COLORS.GRAY}(75% reduction)${CONSOLE_COLORS.RESET}`;
console.log(`${CONSOLE_COLORS.GREEN}⚡ Code Execution${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} Token-efficient path${tokenInfo}`);
}
return codeResult;
}
}
// Phase 2: Fallback to MCP tools if code execution failed
if (fallbackToMCP && memoryClient) {
if (config?.output?.verbose && config?.output?.showMemoryDetails) {
console.log(`${CONSOLE_COLORS.YELLOW}↩️ MCP Fallback${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}Using standard MCP tools${CONSOLE_COLORS.RESET}`);
}
// Add timeout for each individual query (2 seconds max)
const queryTimeout = new Promise((resolve) =>
setTimeout(() => resolve([]), 2000)
);
let memories = [];
// Use time-based queries with semantic filtering for relevant recent memories
const queryPromise = query.timeFilter ?
memoryClient.queryMemoriesByTime(query.timeFilter, query.limit, query.semanticQuery) :
memoryClient.queryMemories(query.semanticQuery, query.limit);
memories = await Promise.race([queryPromise, queryTimeout]);
return memories || [];
}
return [];
} catch (error) {
console.warn('[Memory Hook] Memory query error:', error.message);
return [];
}
}
// ANSI Colors for console output
const CONSOLE_COLORS = {
RESET: '\x1b[0m',
BRIGHT: '\x1b[1m',
DIM: '\x1b[2m',
CYAN: '\x1b[36m',
GREEN: '\x1b[32m',
BLUE: '\x1b[34m',
YELLOW: '\x1b[33m',
GRAY: '\x1b[90m',
RED: '\x1b[31m'
};
/**
* Main session start hook function with enhanced visual output
*/
async function onSessionStart(context) {
// Global timeout wrapper to prevent hook from hanging
// Config specifies 10s, we use 9.5s to leave 0.5s buffer for cleanup
// With 1 git query + 1 recent query, expect ~9.5s total (4.5s each due to Python cold-start)
const HOOK_TIMEOUT = 9500; // 9.5 seconds (reduced Phase 0 from 2 to 1 query)
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Hook timeout - completing early')), HOOK_TIMEOUT);
});
try {
return await Promise.race([
executeSessionStart(context),
timeoutPromise
]);
} catch (error) {
if (error.message.includes('Hook timeout')) {
console.log(`${CONSOLE_COLORS.YELLOW}⏱️ Memory Hook${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}Completed with timeout (normal for slow connections)${CONSOLE_COLORS.RESET}`);
return;
}
throw error;
}
}
/**
* Main execution logic (wrapped by timeout)
*/
async function executeSessionStart(context) {
try {
// Load configuration first to check verbosity settings
const config = await loadConfig();
const verbose = config.output?.verbose !== false; // Default to true
const cleanMode = config.output?.cleanMode === true; // Default to false
const showMemoryDetails = config.output?.showMemoryDetails === true;
const showProjectDetails = config.output?.showProjectDetails !== false; // Default to true
if (verbose && !cleanMode) {
console.log(`${CONSOLE_COLORS.CYAN}🧠 Memory Hook${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} Initializing session awareness...`);
}
// Check if this is triggered by a compacting event and skip if configured to do so
if (context.trigger === 'compacting' || context.event === 'memory-compacted') {
if (!config.memoryService.injectAfterCompacting) {
console.log(`${CONSOLE_COLORS.YELLOW}⏸️ Memory Hook${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} Skipping injection after compacting`);
return;
}
console.log(`${CONSOLE_COLORS.GREEN}▶️ Memory Hook${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} Proceeding with injection after compacting`);
}
// For non-session-start events, use smart timing to decide if refresh is needed
if (context.trigger !== 'session-start' && context.trigger !== 'start') {
const currentContext = extractCurrentContext(context.conversationState || {}, context.workingDirectory);
const previousContext = context.previousContext || context.conversationState?.previousContext;
if (previousContext) {
const shiftDetection = detectContextShift(currentContext, previousContext);
if (!shiftDetection.shouldRefresh) {
console.log(`${CONSOLE_COLORS.GRAY}⏸️ Memory Hook${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}No context shift detected, skipping${CONSOLE_COLORS.RESET}`);
return;
}
console.log(`${CONSOLE_COLORS.BLUE}🔄 Memory Hook${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} Context shift: ${shiftDetection.description}`);
}
}
// Detect project context
const projectContext = await detectProjectContext(context.workingDirectory || process.cwd());
if (verbose && showProjectDetails && !cleanMode) {
const projectDisplay = `${CONSOLE_COLORS.BRIGHT}${projectContext.name}${CONSOLE_COLORS.RESET}`;
const typeDisplay = projectContext.language !== 'Unknown' ? ` ${CONSOLE_COLORS.GRAY}(${projectContext.language})${CONSOLE_COLORS.RESET}` : '';
console.log(`${CONSOLE_COLORS.BLUE}📂 Project Detector${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} Analyzing ${projectDisplay}${typeDisplay}`);
}
// Initialize memory client and detect storage backend
const showStorageSource = config.memoryService?.showStorageSource !== false; // Default to true
const sourceDisplayMode = config.memoryService?.sourceDisplayMode || 'brief';
let memoryClient = null;
let storageInfo = null;
let connectionInfo = null;
if (showStorageSource && verbose && !cleanMode) {
// Initialize unified memory client for health check and memory queries
try {
memoryClient = new MemoryClient(config.memoryService);
const connection = await memoryClient.connect();
connectionInfo = memoryClient.getConnectionInfo();
if (verbose && showMemoryDetails && !cleanMode && connectionInfo?.activeProtocol) {
console.log(`${CONSOLE_COLORS.CYAN}🔗 Connection${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} Using ${CONSOLE_COLORS.BRIGHT}${connectionInfo.activeProtocol.toUpperCase()}${CONSOLE_COLORS.RESET} protocol`);
}
const healthResult = await queryMemoryHealth(memoryClient);
if (healthResult.success) {
storageInfo = parseHealthDataToStorageInfo(healthResult.data);
// Display based on mode with rich health information
if (sourceDisplayMode === 'detailed') {
console.log(`${CONSOLE_COLORS.CYAN}💾 Storage${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${storageInfo.icon} ${CONSOLE_COLORS.BRIGHT}${storageInfo.description}${CONSOLE_COLORS.RESET}`);
console.log(`${CONSOLE_COLORS.CYAN}📍 Location${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}${storageInfo.location}${CONSOLE_COLORS.RESET}`);
if (storageInfo.health.totalMemories > 0) {
console.log(`${CONSOLE_COLORS.CYAN}📊 Database${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GREEN}${storageInfo.health.totalMemories} memories${CONSOLE_COLORS.RESET}, ${CONSOLE_COLORS.YELLOW}${storageInfo.health.databaseSizeMB}MB${CONSOLE_COLORS.RESET}, ${CONSOLE_COLORS.BLUE}${storageInfo.health.uniqueTags} tags${CONSOLE_COLORS.RESET}`);
}
} else if (sourceDisplayMode === 'brief') {
const memoryCount = storageInfo.health.totalMemories > 0 ? ` • ${storageInfo.health.totalMemories} memories` : '';
const sizeInfo = storageInfo.health.databaseSizeMB > 0 ? ` • ${storageInfo.health.databaseSizeMB}MB` : '';
console.log(`${CONSOLE_COLORS.CYAN}💾 Storage${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${storageInfo.icon} ${CONSOLE_COLORS.BRIGHT}${storageInfo.description}${CONSOLE_COLORS.RESET}${memoryCount}${sizeInfo}`);
if (storageInfo.location && sourceDisplayMode === 'brief') {
console.log(`${CONSOLE_COLORS.CYAN}📍 Path${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}${storageInfo.location}${CONSOLE_COLORS.RESET}`);
}
} else if (sourceDisplayMode === 'icon-only') {
console.log(`${CONSOLE_COLORS.CYAN}💾 Storage${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${storageInfo.icon} ${storageInfo.backend} • ${storageInfo.health.totalMemories} memories`);
}
} else {
// Fallback to environment/config detection when MCP health check fails
if (verbose && showMemoryDetails && !cleanMode) {
console.log(`${CONSOLE_COLORS.YELLOW}⚠️ MCP Health Check${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}${healthResult.error}, using config fallback${CONSOLE_COLORS.RESET}`);
}
storageInfo = detectStorageBackendFallback(config);
if (sourceDisplayMode === 'detailed') {
console.log(`${CONSOLE_COLORS.CYAN}💾 Storage${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${storageInfo.icon} ${CONSOLE_COLORS.BRIGHT}${storageInfo.description}${CONSOLE_COLORS.RESET}`);
console.log(`${CONSOLE_COLORS.CYAN}📍 Location${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}${storageInfo.location}${CONSOLE_COLORS.RESET}`);
} else if (sourceDisplayMode === 'brief') {
console.log(`${CONSOLE_COLORS.CYAN}💾 Storage${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${storageInfo.icon} ${CONSOLE_COLORS.BRIGHT}${storageInfo.description}${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}(${storageInfo.location})${CONSOLE_COLORS.RESET}`);
} else if (sourceDisplayMode === 'icon-only') {
console.log(`${CONSOLE_COLORS.CYAN}💾 Storage${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${storageInfo.icon} ${storageInfo.backend}`);
}
}
} catch (error) {
// Memory client connection failed, fall back to environment detection
if (verbose && showMemoryDetails && !cleanMode) {
console.log(`${CONSOLE_COLORS.YELLOW}⚠️ Memory Connection${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}${error.message}, using environment fallback${CONSOLE_COLORS.RESET}`);
}
storageInfo = detectStorageBackendFallback(config);
if (sourceDisplayMode === 'brief') {
console.log(`${CONSOLE_COLORS.CYAN}💾 Storage${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${storageInfo.icon} ${CONSOLE_COLORS.BRIGHT}${storageInfo.description}${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}(${storageInfo.location})${CONSOLE_COLORS.RESET}`);
}
}
} else {
// Health check disabled, use config fallback
storageInfo = detectStorageBackendFallback(config);
if (sourceDisplayMode === 'detailed') {
console.log(`${CONSOLE_COLORS.CYAN}💾 Storage${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${storageInfo.icon} ${CONSOLE_COLORS.BRIGHT}${storageInfo.description}${CONSOLE_COLORS.RESET}`);
console.log(`${CONSOLE_COLORS.CYAN}📍 Location${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}${storageInfo.location}${CONSOLE_COLORS.RESET}`);
} else if (sourceDisplayMode === 'brief') {
console.log(`${CONSOLE_COLORS.CYAN}💾 Storage${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${storageInfo.icon} ${CONSOLE_COLORS.BRIGHT}${storageInfo.description}${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}(${storageInfo.location})${CONSOLE_COLORS.RESET}`);
} else if (sourceDisplayMode === 'icon-only') {
console.log(`${CONSOLE_COLORS.CYAN}💾 Storage${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${storageInfo.icon} ${storageInfo.backend}`);
}
}
// Display version information
const showVersionInfo = config.versionCheck?.enabled !== false; // Default to true
if (showVersionInfo && verbose && !cleanMode) {
try {
const versionInfo = await getVersionInfo(context.workingDirectory || process.cwd(), {
checkPyPI: config.versionCheck?.checkPyPI !== false,
timeout: config.versionCheck?.timeout || 2000
});
const versionDisplay = formatVersionDisplay(versionInfo, CONSOLE_COLORS);
console.log(versionDisplay);
} catch (error) {
// Silently fail - version check is informational, not critical
if (verbose && showMemoryDetails) {
console.warn(`[Memory Hook] Version check failed: ${error.message}`);
}
}
}
// Analyze git context if enabled
const gitAnalysisEnabled = config.gitAnalysis?.enabled !== false; // Default to true
const showGitAnalysis = config.output?.showGitAnalysis !== false; // Default to true
let gitContext = null;
if (gitAnalysisEnabled) {
if (verbose && showGitAnalysis && !cleanMode) {
console.log(`${CONSOLE_COLORS.CYAN}📊 Git Analysis${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} Analyzing repository context...`);
}
gitContext = await analyzeGitContext(context.workingDirectory || process.cwd(), {
commitLookback: config.gitAnalysis?.commitLookback || 14,
maxCommits: config.gitAnalysis?.maxCommits || 20,
includeChangelog: config.gitAnalysis?.includeChangelog !== false,
verbose: showGitAnalysis && showMemoryDetails && !cleanMode
});
if (gitContext && verbose && showGitAnalysis && !cleanMode) {
const { commits, changelogEntries, repositoryActivity, developmentKeywords } = gitContext;
console.log(`${CONSOLE_COLORS.CYAN}📊 Git Context${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${commits.length} commits, ${changelogEntries?.length || 0} changelog entries`);
if (showMemoryDetails) {
const topKeywords = developmentKeywords.keywords.slice(0, 5).join(', ');
if (topKeywords) {
console.log(`${CONSOLE_COLORS.CYAN}🔑 Keywords${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.YELLOW}${topKeywords}${CONSOLE_COLORS.RESET}`);
}
}
}
}
// Initialize memory client for memory queries if not already connected
if (!memoryClient) {
try {
// Add quick timeout for initial connection
const connectionTimeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Quick connection timeout')), 2000)
);
memoryClient = new MemoryClient(config.memoryService);
await Promise.race([
memoryClient.connect(),
connectionTimeout
]);
connectionInfo = memoryClient.getConnectionInfo();
} catch (error) {
if (verbose && !cleanMode) {
console.log(`${CONSOLE_COLORS.YELLOW}⚠️ Memory Connection${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}Failed to connect for memory queries: ${error.message}${CONSOLE_COLORS.RESET}`);
}
memoryClient = null;
}
}
// Multi-phase memory retrieval for better recency prioritization
const allMemories = [];
const maxMemories = config.memoryService.maxMemoriesPerSession;
const recentFirstMode = config.memoryService.recentFirstMode !== false; // Default to true
const recentRatio = config.memoryService.recentMemoryRatio || 0.6;
const recentTimeWindow = config.memoryService.recentTimeWindow || 'last-week';
const fallbackTimeWindow = config.memoryService.fallbackTimeWindow || 'last-month';
// Extract memory scoring configuration
const scoringWeights = config.memoryScoring?.weights || {};
const timeDecayRate = config.memoryScoring?.timeDecayRate || 0.1;
const enableConversationContext = config.memoryScoring?.enableConversationContext || false;
const minRelevanceScore = config.memoryScoring?.minRelevanceScore || 0.3;
const showPhaseDetails = config.output?.showPhaseDetails !== false && config.output?.style !== 'balanced'; // Hide in balanced mode
if (recentFirstMode) {
// Phase 0: Git Context Phase (NEW - highest priority for repository-aware memories)
if (gitContext && gitContext.developmentKeywords.keywords.length > 0) {
const maxGitMemories = config.gitAnalysis?.maxGitMemories || 3;
const gitQueries = buildGitContextQuery(projectContext, gitContext.developmentKeywords, context.userMessage);
if (verbose && showPhaseDetails && !cleanMode && gitQueries.length > 0) {
console.log(`${CONSOLE_COLORS.GREEN}⚡ Phase 0${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} Git-aware memory search (${maxGitMemories} slots, 1 of ${gitQueries.length} queries for 8s timeout)`);
}
// Execute git-context queries
for (const gitQuery of gitQueries.slice(0, 1)) { // Limit to top 1 query to stay within 8s timeout
if (allMemories.length >= maxGitMemories) break;
const gitMemories = await queryMemoryService(memoryClient, {
semanticQuery: gitQuery.semanticQuery,
limit: Math.min(maxGitMemories - allMemories.length, 3),
timeFilter: 'last-2-weeks' // Focus on recent memories for git context
}, config);
if (gitMemories && gitMemories.length > 0) {
// Mark these memories as git-context derived for scoring
const markedMemories = gitMemories.map(mem => ({
...mem,
_gitContextType: gitQuery.type,
_gitContextSource: gitQuery.source,
_gitContextWeight: config.gitAnalysis?.gitContextWeight || 1.2
}));
// Avoid duplicates from previous git queries
const newGitMemories = markedMemories.filter(newMem =>
!allMemories.some(existing =>
existing.content && newMem.content &&
existing.content.substring(0, 100) === newMem.content.substring(0, 100)
)
);
allMemories.push(...newGitMemories);
if (verbose && showMemoryDetails && !cleanMode && newGitMemories.length > 0) {
console.log(`${CONSOLE_COLORS.GREEN} 📋 Git Query${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} [${gitQuery.type}] found ${newGitMemories.length} memories`);
}
}
}
}
// Phase 1: Recent memories - high priority
const remainingSlotsAfterGit = Math.max(0, maxMemories - allMemories.length);
if (remainingSlotsAfterGit > 0) {
// Build enhanced semantic query with git context
let recentSemanticQuery = context.userMessage ?
`recent ${projectContext.name} ${context.userMessage}` :
`recent ${projectContext.name} development decisions insights`;
// Add git context if available
if (projectContext.git?.branch) {
recentSemanticQuery += ` ${projectContext.git.branch}`;
}
if (projectContext.git?.lastCommit) {
recentSemanticQuery += ` latest changes commit`;
}
// Add development keywords from git analysis
if (gitContext && gitContext.developmentKeywords.keywords.length > 0) {
const topKeywords = gitContext.developmentKeywords.keywords.slice(0, 3).join(' ');
recentSemanticQuery += ` ${topKeywords}`;
}
const recentQuery = {
semanticQuery: recentSemanticQuery,
limit: Math.max(Math.floor(remainingSlotsAfterGit * recentRatio), 2), // Adjusted for remaining slots
timeFilter: recentTimeWindow
};
if (verbose && showMemoryDetails && showPhaseDetails && !cleanMode) {
console.log(`${CONSOLE_COLORS.BLUE}🕒 Phase 1${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} Searching recent memories (${recentTimeWindow}, ${recentQuery.limit} slots)`);
}
const recentMemories = await queryMemoryService(memoryClient, recentQuery, config);
// Filter out duplicates from git context phase
if (recentMemories && recentMemories.length > 0) {
const newRecentMemories = recentMemories.filter(newMem =>
!allMemories.some(existing =>
existing.content && newMem.content &&
existing.content.substring(0, 100) === newMem.content.substring(0, 100)
)
);
allMemories.push(...newRecentMemories);
}
}
// Phase 2: Important tagged memories - fill remaining slots
const remainingSlots = maxMemories - allMemories.length;
if (remainingSlots > 0) {
// Build tag list for important memories
const importantTags = [
projectContext.name,
'key-decisions',
'architecture',
'claude-code-reference'
].filter(Boolean);
const timeFilter = 'last-2-weeks';
if (verbose && showMemoryDetails && showPhaseDetails && !cleanMode) {
console.log(`${CONSOLE_COLORS.BLUE}🎯 Phase 2${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} Searching important tagged memories (${remainingSlots} slots)`);
}
// Use new tag-time filtering method for efficient recency prioritization
const importantMemories = memoryClient ?
await memoryClient.queryMemoriesByTagsAndTime(importantTags, timeFilter, remainingSlots, false) :
[];
// Avoid duplicates by checking content similarity
const newMemories = (importantMemories || []).filter(newMem =>
!allMemories.some(existing =>
existing.content && newMem.content &&
existing.content.substring(0, 100) === newMem.content.substring(0, 100)
)
);
allMemories.push(...newMemories);
}
// Phase 3: Fallback to general project context if still need more
const stillRemaining = maxMemories - allMemories.length;
if (stillRemaining > 0 && allMemories.length < 3) {
const fallbackQuery = {
semanticQuery: `${projectContext.name} project context`,
limit: stillRemaining,
timeFilter: fallbackTimeWindow
};
if (verbose && showMemoryDetails && showPhaseDetails && !cleanMode) {
console.log(`${CONSOLE_COLORS.BLUE}🔄 Phase 3${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} Fallback general context (${stillRemaining} slots, ${fallbackTimeWindow})`);
}
const fallbackMemories = await queryMemoryService(memoryClient, fallbackQuery, config);
const newFallbackMemories = (fallbackMemories || []).filter(newMem =>
!allMemories.some(existing =>
existing.content && newMem.content &&
existing.content.substring(0, 100) === newMem.content.substring(0, 100)
)
);
allMemories.push(...newFallbackMemories);
}
} else {
// Legacy single-phase approach
const memoryQuery = {
tags: [
projectContext.name,
`language:${projectContext.language}`,
'key-decisions',
'architecture',
'recent-insights',
'claude-code-reference'
].filter(Boolean),
semanticQuery: context.userMessage ?
`${projectContext.name} ${context.userMessage}` :
`${projectContext.name} project context decisions architecture`,
limit: maxMemories,
timeFilter: 'last-2-weeks'
};
const legacyMemories = await queryMemoryService(memoryClient, memoryQuery, config);
allMemories.push(...(legacyMemories || []));
}
// Skip memory retrieval if no memory client available
if (!memoryClient) {
if (verbose && !cleanMode) {
console.log(`${CONSOLE_COLORS.YELLOW}⚠️ Memory Retrieval${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}Skipped due to connection failure${CONSOLE_COLORS.RESET}`);
}
// Skip memory operations but don't return - still complete the hook
if (verbose && showMemoryDetails && !cleanMode) {
console.log(`${CONSOLE_COLORS.YELLOW}📭 Memory Search${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}No memory service available${CONSOLE_COLORS.RESET}`);
}
}
// Use the collected memories from all phases
const memories = allMemories.slice(0, maxMemories);
if (memories.length > 0) {
// Analyze memory recency for better reporting
const now = new Date();
const recentCount = memories.filter(m => {
if (!m.created_at_iso) return false;
const memDate = new Date(m.created_at_iso);
const daysDiff = (now - memDate) / (1000 * 60 * 60 * 24);
return daysDiff <= 7; // Within last week
}).length;
if (verbose && !cleanMode) {
const recentText = recentCount > 0 ? ` ${CONSOLE_COLORS.GREEN}(${recentCount} recent)${CONSOLE_COLORS.RESET}` : '';
console.log(`${CONSOLE_COLORS.GREEN}📚 Memory Search${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} Found ${CONSOLE_COLORS.BRIGHT}${memories.length}${CONSOLE_COLORS.RESET} relevant memories${recentText}`);
}
// Analyze memory age distribution for adaptive weight adjustment
const ageAnalysis = analyzeMemoryAgeDistribution(memories, { verbose: showMemoryDetails && !cleanMode });
// Apply auto-calibration if enabled
const autoCalibrate = config.memoryScoring?.autoCalibrate !== false; // Default true
let adjustedWeights = { ...scoringWeights };
if (autoCalibrate && ageAnalysis.isStale && ageAnalysis.recommendedAdjustments.timeDecay) {
adjustedWeights = {
...adjustedWeights,
timeDecay: ageAnalysis.recommendedAdjustments.timeDecay,
tagRelevance: ageAnalysis.recommendedAdjustments.tagRelevance
};
if (verbose && showMemoryDetails && !cleanMode) {
console.log(`${CONSOLE_COLORS.CYAN}🎯 Auto-Calibration${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}${ageAnalysis.recommendedAdjustments.reason}${CONSOLE_COLORS.RESET}`);
console.log(`${CONSOLE_COLORS.CYAN} Adjusted Weights${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} timeDecay: ${adjustedWeights.timeDecay.toFixed(2)}, tagRelevance: ${adjustedWeights.tagRelevance.toFixed(2)}`);
}
}
// Score memories for relevance (with enhanced recency weighting and auto-calibrated weights)
let scoredMemories = scoreMemoryRelevance(memories, projectContext, {
verbose: showMemoryDetails,
enhanceRecency: recentFirstMode,
weights: adjustedWeights,
timeDecayRate: timeDecayRate,
includeConversationContext: enableConversationContext
});
// Calculate adaptive git context weight
// v8.5.1+ Dynamic git weight based on memory age and commit activity
const configuredGitWeight = config.gitAnalysis?.gitContextWeight || 1.2;
const adaptiveGitEnabled = config.gitAnalysis?.adaptiveGitWeight !== false; // Default true
let gitWeightResult;
if (adaptiveGitEnabled && gitContext) {
gitWeightResult = calculateAdaptiveGitWeight(
gitContext,
ageAnalysis,
configuredGitWeight,
{ verbose: showMemoryDetails && !cleanMode }
);
} else {
gitWeightResult = { weight: configuredGitWeight, reason: 'Adaptive git weight disabled', adjusted: false };
}
const gitWeight = gitWeightResult.weight;
// Show git weight info
if (verbose && showMemoryDetails && !cleanMode) {
if (gitWeightResult.adjusted) {
console.log(`${CONSOLE_COLORS.CYAN}⚙️ Adaptive Git Weight${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}${gitWeightResult.reason}${CONSOLE_COLORS.RESET}`);
}
if (configuredGitWeight > 1.5 && !gitWeightResult.adjusted) {
console.log(`${CONSOLE_COLORS.YELLOW}⚠️ Git Weight${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}High git context weight (${gitWeight.toFixed(1)}x) may prioritize git-related memories excessively${CONSOLE_COLORS.RESET}`);
console.log(`${CONSOLE_COLORS.YELLOW} Recommended${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}1.1-1.3x for balanced recency${CONSOLE_COLORS.RESET}`);
}
}
// Apply git context weight boost to git-derived memories
scoredMemories = scoredMemories.map(memory => {
if (memory._gitContextWeight && memory._gitContextWeight !== 1.0) {
const originalScore = memory.relevanceScore;
const boostedScore = Math.min(1.0, originalScore * memory._gitContextWeight);
// Store original score for transparency
return {
...memory,
_originalScore: originalScore,
relevanceScore: boostedScore,
_wasBoosted: true
};
}
return memory;
}).sort((a, b) => b.relevanceScore - a.relevanceScore); // Re-sort after boost
// Filter out zero-scored memories (project affinity filtered)
const preFilterCount = scoredMemories.length;
scoredMemories = scoredMemories.filter(m => m.relevanceScore > 0);
if (verbose && showMemoryDetails && !cleanMode && preFilterCount !== scoredMemories.length) {
console.log(`[Memory Filter] Removed ${preFilterCount - scoredMemories.length} unrelated memories (no project affinity)`);
}
// Show top scoring memories with recency info and detailed breakdown
if (verbose && showMemoryDetails && scoredMemories.length > 0 && !cleanMode) {
const topMemories = scoredMemories.slice(0, 3);
const memoryInfo = topMemories.map((m, idx) => {
const score = `${(m.relevanceScore * 100).toFixed(0)}%`;
let recencyFlag = '';
let ageText = '';
if (m.created_at_iso) {
const daysDiff = (now - new Date(m.created_at_iso)) / (1000 * 60 * 60 * 24);
if (daysDiff <= 1) {
recencyFlag = '🕒';
ageText = 'today';
} else if (daysDiff <= 7) {
recencyFlag = '📅';
ageText = `${Math.floor(daysDiff)}d ago`;
} else if (daysDiff <= 30) {
ageText = `${Math.floor(daysDiff)}d ago`;
} else {
ageText = `${Math.floor(daysDiff)}d ago`;
}
}
// Show detailed breakdown for top memory (only if explicitly enabled)
if (idx === 0 && m.scoreBreakdown) {
const bd = m.scoreBreakdown;
const showBreakdown = config.output?.showScoringBreakdown === true;
if (showBreakdown) {
console.log(`${CONSOLE_COLORS.CYAN} 📊 Top Memory Breakdown${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET}`);
console.log(`${CONSOLE_COLORS.CYAN} • Time Decay${CONSOLE_COLORS.RESET}: ${(bd.timeDecay * 100).toFixed(0)}% ${CONSOLE_COLORS.GRAY}(${ageText})${CONSOLE_COLORS.RESET}`);
console.log(`${CONSOLE_COLORS.CYAN} • Tag Match${CONSOLE_COLORS.RESET}: ${(bd.tagRelevance * 100).toFixed(0)}%`);
console.log(`${CONSOLE_COLORS.CYAN} • Content${CONSOLE_COLORS.RESET}: ${(bd.contentRelevance * 100).toFixed(0)}%`);
console.log(`${CONSOLE_COLORS.CYAN} • Quality${CONSOLE_COLORS.RESET}: ${(bd.contentQuality * 100).toFixed(0)}%`);
if (bd.recencyBonus > 0) {
console.log(`${CONSOLE_COLORS.CYAN} • Recency Bonus${CONSOLE_COLORS.RESET}: ${CONSOLE_COLORS.GREEN}+${(bd.recencyBonus * 100).toFixed(0)}%${CONSOLE_COLORS.RESET}`);
}
// Show git context boost if applied
if (m._wasBoosted && m._originalScore) {
const boostAmount = ((m.relevanceScore - m._originalScore) * 100).toFixed(0);
console.log(`${CONSOLE_COLORS.CYAN} • Git Boost${CONSOLE_COLORS.RESET}: ${CONSOLE_COLORS.YELLOW}+${boostAmount}%${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}(${(m._originalScore * 100).toFixed(0)}% → ${(m.relevanceScore * 100).toFixed(0)}%)${CONSOLE_COLORS.RESET}`);
}
} else if (config.logging?.enableDebug) {
// Log to debug file instead of console
const debugMsg = `[Memory Scorer] Top memory breakdown: TimeDecay=${(bd.timeDecay * 100).toFixed(0)}%, TagMatch=${(bd.tagRelevance * 100).toFixed(0)}%, Content=${(bd.contentRelevance * 100).toFixed(0)}%, Quality=${(bd.contentQuality * 100).toFixed(0)}%, RecencyBonus=${(bd.recencyBonus * 100).toFixed(0)}%`;
console.log(debugMsg);
}
}
return ageText ? `${score}${recencyFlag} (${ageText})` : `${score}${recencyFlag}`;
}).join(', ');
console.log(`${CONSOLE_COLORS.CYAN}🎯 Scoring${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} Top relevance: ${CONSOLE_COLORS.YELLOW}${memoryInfo}${CONSOLE_COLORS.RESET}`);
}
// Determine refresh strategy based on context
const strategy = context.trigger && context.previousContext ?
determineRefreshStrategy(detectContextShift(
extractCurrentContext(context.conversationState || {}, context.workingDirectory),
context.previousContext
)) : {
maxMemories: config.memoryService.maxMemoriesPerSession,
includeScore: false,
message: '🧠 Loading relevant memory context...'
};
// Take top scored memories based on strategy
const maxMemories = Math.min(strategy.maxMemories || config.memoryService.maxMemoriesPerSession, scoredMemories.length);
const topMemories = scoredMemories.slice(0, maxMemories);
// Show actual memory processing info (moved from deduplication)
if (verbose && showMemoryDetails && !cleanMode) {
const totalCollected = allMemories.length;
const actualUsed = Math.min(maxMemories, scoredMemories.length);
if (totalCollected > actualUsed) {
console.log(`[Context Formatter] Selected ${actualUsed} from ${totalCollected} collected memories`);
}
console.log(`${CONSOLE_COLORS.CYAN}🔄 Processing${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${actualUsed} memories selected`);
}
// Format memories for context injection with strategy-based options
const contextMessage = formatMemoriesForContext(topMemories, projectContext, {
includeScore: strategy.includeScore || false,
groupByCategory: maxMemories > 3,
maxMemories: maxMemories,
includeTimestamp: true,
maxContentLength: config.contextFormatting?.maxContentLength || 500,
maxContentLengthCLI: config.contextFormatting?.maxContentLengthCLI || 400,
maxContentLengthCategorized: config.contextFormatting?.maxContentLengthCategorized || 350,
storageInfo: showStorageSource ? (storageInfo || detectStorageBackend(config)) : null,
adaptiveTruncation: config.output?.adaptiveTruncation !== false,
contentLengthConfig: config.contentLength
});
// Inject context into session
if (context.injectSystemMessage) {
await context.injectSystemMessage(contextMessage);
// Note: Don't console.log here - injectSystemMessage handles display
// console.log would cause duplicate output in Claude Code
// Write detailed session context log file (Option 3)
try {
const os = require('os');
const logPath = path.join(os.homedir(), '.claude', 'last-session-context.txt');
const recencyPercent = maxMemories > 0 ? ((recentCount / maxMemories) * 100).toFixed(0) : 0;
let logContent = `Session Started: ${new Date().toISOString()}\n`;
logContent += `Session ID: ${context.sessionId || 'unknown'}\n\n`;
logContent += `=== Project Context ===\n`;
logContent += `Project: ${projectContext.name}\n`;
logContent += `Language: ${projectContext.language}\n`;
if (projectContext.frameworks && projectContext.frameworks.length > 0) {
logContent += `Frameworks: ${projectContext.frameworks.join(', ')}\n`;
}
if (projectContext.git) {
logContent += `Git Branch: ${projectContext.git.branch || 'unknown'}\n`;
}
logContent += `\n=== Storage Backend ===\n`;
if (storageInfo) {
logContent += `Backend: ${storageInfo.backend}\n`;
logContent += `Type: ${storageInfo.type}\n`;
logContent += `Location: ${storageInfo.location}\n`;
if (storageInfo.health.totalMemories > 0) {
logContent += `Total Memories in DB: ${storageInfo.health.totalMemories}\n`;
}
}
logContent += `\n=== Memory Statistics ===\n`;
logContent += `Memories Loaded: ${maxMemories}\n`;
logContent += `Recent (last week): ${recentCount} (${recencyPercent}%)\n`;
if (gitContext) {
logContent += `\n=== Git Context ===\n`;
logContent += `Commits Analyzed: ${gitContext.commits.length}\n`;
logContent += `Changelog Entries: ${gitContext.changelogEntries?.length || 0}\n`;
logContent += `Top Keywords: ${gitContext.developmentKeywords.keywords.slice(0, 5).join(', ')}\n`;
}
if (topMemories.length > 0) {
logContent += `\n=== Top Loaded Memories ===\n`;
topMemories.slice(0, 3).forEach((m, idx) => {
const preview = m.content ? m.content.substring(0, 150).replace(/\n/g, ' ') : 'No content';
const ageInfo = m.created_at_iso ? ` (${Math.floor((now - new Date(m.created_at_iso)) / (1000 * 60 * 60 * 24))}d ago)` : '';
logContent += `\n${idx + 1}. Score: ${(m.relevanceScore * 100).toFixed(0)}%${ageInfo}\n`;
logContent += ` ${preview}...\n`;
});
}
await fs.writeFile(logPath, logContent, 'utf8');
} catch (error) {
// Silently fail - log file is nice-to-have, not critical
if (verbose && showMemoryDetails) {
console.warn(`[Memory Hook] Failed to write log file: ${error.message}`);
}
}
// Write status line cache file (Option 4)
try {
const cachePath = path.join(__dirname, '../utilities/session-cache.json');
const cacheData = {
timestamp: new Date().toISOString(),
sessionId: context.sessionId || 'unknown',
project: projectContext.name,
memoriesLoaded: maxMemories,
recentCount: recentCount,
gitCommits: gitContext ? gitContext.commits.length : 0,
gitKeywords: gitContext ? gitContext.developmentKeywords.keywords.slice(0, 3) : [],
storageBackend: storageInfo ? storageInfo.backend : 'unknown'
};
await fs.writeFile(cachePath, JSON.stringify(cacheData, null, 2), 'utf8');
} catch (error) {
// Silently fail - status line cache is optional
if (verbose && showMemoryDetails) {
console.warn(`[Memory Hook] Failed to write status line cache: ${error.message}`);
}
}
} else if (verbose && !cleanMode) {
// Fallback: log context for manual copying with styling
console.log(`\n${CONSOLE_COLORS.CYAN}╭──────────────────────────────────────────╮${CONSOLE_COLORS.RESET}`);
console.log(`${CONSOLE_COLORS.CYAN}│${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.BRIGHT}Memory Context for Manual Copy${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.CYAN}│${CONSOLE_COLORS.RESET}`);
console.log(`${CONSOLE_COLORS.CYAN}╰──────────────────────────────────────────╯${CONSOLE_COLORS.RESET}`);
// Clean output to remove session-start-hook wrapper tags
const cleanedMessage = contextMessage.replace(/<\/?session-start-hook>/g, '');
console.log(cleanedMessage);
console.log(`${CONSOLE_COLORS.CYAN}╰──────────────────────────────────────────╯${CONSOLE_COLORS.RESET}\n`);
}
} else if (verbose && showMemoryDetails && !cleanMode) {
console.log(`${CONSOLE_COLORS.YELLOW}📭 Memory Search${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.GRAY}No relevant memories found${CONSOLE_COLORS.RESET}`);
}
} catch (error) {
console.error(`${CONSOLE_COLORS.RED}❌ Memory Hook Error${CONSOLE_COLORS.RESET} ${CONSOLE_COLORS.DIM}→${CONSOLE_COLORS.RESET} ${error.message}`);
// Fail gracefully - don't prevent session from starting
} finally {
// Ensure MCP client cleanup even on error
try {
if (memoryClient && typeof memoryClient.disconnect === 'function') {
await memoryClient.disconnect();
}
} catch (error) {
// Ignore cleanup errors silently
}
}
}
/**
* Hook metadata for Claude Code
*/
module.exports = {
name: 'memory-awareness-session-start',
version: '2.3.0',
description: 'Automatically inject relevant memories at session start with git-aware repository context',
trigger: 'session-start',
handler: onSessionStart,
config: {
async: true,
timeout: 15000, // Increased timeout for git analysis
priority: 'high'
}
};
// Direct execution support for testing
if (require.main === module) {
// Test the hook with mock context
const mockContext = {
workingDirectory: process.cwd(),
sessionId: 'test-session',
injectSystemMessage: async (message) => {
// Just print the message - it already has its own formatting from context-formatter.js
console.log(message);
}
};
onSessionStart(mockContext)
.then(() => {
// Test completed quietly
process.exit(0);
})
.catch(error => {
console.error(`${CONSOLE_COLORS.RED}❌ Hook test failed:${CONSOLE_COLORS.RESET} ${error.message}`);
process.exit(1);
});
}
```