memorymaster 3.13.0__tar.gz → 3.15.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {memorymaster-3.13.0/memorymaster.egg-info → memorymaster-3.15.0}/PKG-INFO +26 -28
- {memorymaster-3.13.0 → memorymaster-3.15.0}/README.md +23 -27
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/_storage_lifecycle.py +84 -12
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/_storage_read.py +5 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/_storage_schema.py +2 -1
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/_storage_sources.py +17 -1
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/_storage_write_claims.py +24 -3
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/auto_resolver.py +51 -45
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/claim_verifier.py +0 -1
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/cli.py +53 -4
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/cli_handlers_basic.py +155 -3
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/config.py +103 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/config_templates/hooks/memorymaster-dream-sync.py +2 -1
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/config_templates/hooks/memorymaster-recall.py +3 -1
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/config_templates/hooks/memorymaster-steward-cycle.py +2 -1
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/conflict_resolver.py +113 -2
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/context_optimizer.py +161 -19
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/dashboard.py +391 -1
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/db_merge.py +133 -11
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/dream_bridge.py +12 -5
- memorymaster-3.15.0/memorymaster/jobs/calibration.py +120 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/jobs/compact_summaries.py +6 -2
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/jobs/compactor.py +93 -12
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/jobs/decay.py +62 -1
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/jobs/dedup.py +155 -2
- memorymaster-3.15.0/memorymaster/jobs/entity_graph_export.py +210 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/lifecycle.py +31 -1
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/llm_provider.py +73 -2
- memorymaster-3.15.0/memorymaster/llm_rerank.py +216 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/llm_steward.py +5 -2
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/mcp_server.py +378 -34
- memorymaster-3.15.0/memorymaster/mcp_usage.py +43 -0
- memorymaster-3.15.0/memorymaster/observability.py +183 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/operator.py +10 -10
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/postgres_store.py +62 -32
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/retrieval.py +31 -2
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/scheduler.py +9 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/schema.sql +9 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/schema_postgres.sql +9 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/security.py +7 -2
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/service.py +340 -17
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/setup_hooks.py +1 -1
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/snapshot.py +64 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/steward.py +16 -14
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/storage.py +19 -35
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/vault_linter.py +166 -14
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/vault_query_capture.py +1 -1
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/verbatim_store.py +10 -4
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/wiki_engine.py +238 -22
- memorymaster-3.15.0/memorymaster/wiki_suggest.py +270 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0/memorymaster.egg-info}/PKG-INFO +26 -28
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster.egg-info/SOURCES.txt +46 -1
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster.egg-info/requires.txt +2 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster.egg-info/top_level.txt +1 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/pyproject.toml +10 -2
- memorymaster-3.15.0/tests/bench_longmemeval.py +921 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_auto_resolver.py +10 -18
- memorymaster-3.15.0/tests/test_calibration.py +134 -0
- memorymaster-3.15.0/tests/test_calibration_priors_applied.py +20 -0
- memorymaster-3.15.0/tests/test_cli_dry_run.py +142 -0
- memorymaster-3.15.0/tests/test_compact_summaries_sensitivity.py +69 -0
- memorymaster-3.15.0/tests/test_compactor_artifact_order.py +40 -0
- memorymaster-3.15.0/tests/test_context_optimizer_provider.py +145 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_dashboard.py +96 -1
- memorymaster-3.15.0/tests/test_dashboard_coverage.py +321 -0
- memorymaster-3.15.0/tests/test_dashboard_latency.py +111 -0
- memorymaster-3.15.0/tests/test_dashboard_lineage.py +70 -0
- memorymaster-3.15.0/tests/test_dashboard_review_queue.py +143 -0
- memorymaster-3.15.0/tests/test_db_merge_confidence_conflict.py +71 -0
- memorymaster-3.15.0/tests/test_db_merge_coverage_v2.py +260 -0
- memorymaster-3.15.0/tests/test_decay_coverage.py +212 -0
- memorymaster-3.15.0/tests/test_decay_respects_pinned.py +120 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_dedup.py +9 -0
- memorymaster-3.15.0/tests/test_dedup_cli.py +120 -0
- memorymaster-3.15.0/tests/test_dedup_conflict_disambiguation.py +52 -0
- memorymaster-3.15.0/tests/test_dream_bridge_coverage_v2.py +186 -0
- memorymaster-3.15.0/tests/test_dream_bridge_sensitivity.py +76 -0
- memorymaster-3.15.0/tests/test_entity_graph_export.py +147 -0
- memorymaster-3.15.0/tests/test_federated_query_safety.py +91 -0
- memorymaster-3.15.0/tests/test_lifecycle_supersede_invariant.py +87 -0
- memorymaster-3.15.0/tests/test_llm_provider_key_rotation.py +80 -0
- memorymaster-3.15.0/tests/test_mcp_filter_bypass.py +91 -0
- memorymaster-3.15.0/tests/test_mcp_rate_limit.py +101 -0
- memorymaster-3.15.0/tests/test_mcp_server_validation.py +49 -0
- memorymaster-3.15.0/tests/test_mcp_usage.py +95 -0
- memorymaster-3.15.0/tests/test_meta_decisions.py +125 -0
- memorymaster-3.15.0/tests/test_observability.py +47 -0
- memorymaster-3.15.0/tests/test_resolvers_concurrent_supersede.py +148 -0
- memorymaster-3.15.0/tests/test_retrieval_profile.py +120 -0
- memorymaster-3.15.0/tests/test_sensitivity_filter_t07.py +63 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_snapshot.py +2 -1
- memorymaster-3.15.0/tests/test_snapshot_roundtrip.py +168 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_sqlite_core.py +9 -0
- memorymaster-3.15.0/tests/test_storage_parity.py +287 -0
- memorymaster-3.15.0/tests/test_vault_linter_orphan.py +91 -0
- memorymaster-3.15.0/tests/test_verbatim_store.py +67 -0
- memorymaster-3.15.0/tests/test_verbatim_store_qdrant.py +120 -0
- memorymaster-3.15.0/tests/test_wiki_autopromote.py +101 -0
- memorymaster-3.15.0/tests/test_wiki_engine_idempotency.py +170 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_wiki_freshness.py +1 -1
- memorymaster-3.15.0/tests/test_wiki_suggest.py +124 -0
- memorymaster-3.13.0/scripts/run_longmemeval.py +0 -997
- {memorymaster-3.13.0 → memorymaster-3.15.0}/LICENSE +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/artifacts/bm25-per-field-eval-harness.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/benchmarks/longmemeval_runner.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/benchmarks/longmemeval_vector_runner.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/benchmarks/perf_smoke.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/__init__.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/__main__.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/_storage_shared.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/access_control.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/action_exporters.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/action_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/atlas_claim_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/atlas_contract.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/auto_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/candidate_dedupe.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/claim_edges.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/cli_handlers_curation.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/cli_helpers.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/closets.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/config_templates/claude-md-append.md +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/config_templates/codex-agents-md-append.md +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/config_templates/hooks/memorymaster-auto-ingest.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/config_templates/hooks/memorymaster-classify.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/config_templates/hooks/memorymaster-precompact.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/config_templates/hooks/memorymaster-session-start.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/config_templates/hooks/memorymaster-validate-wiki.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/connectors/__init__.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/connectors/whatsapp.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/context_hook.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/daily_notes.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/embeddings.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/entity_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/entity_graph.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/entity_registry.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/federated_graphify.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/feedback.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/graph_store.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/hook_log.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/jobs/__init__.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/jobs/deterministic.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/jobs/extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/jobs/staleness.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/jobs/validator.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/key_rotator.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/media_processing.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/media_providers.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/metrics_exporter.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/models.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/operator_queue.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/plugins.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/policy.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/qdrant_backend.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/qdrant_recall_fallback.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/qmd_bridge.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/query_classifier.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/query_expansion.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/recall_fusion.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/recall_tokenizer.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/retry.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/review.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/rl_trainer.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/schema.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/scope_utils.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/session_tracker.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/skill_evolver.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/steward_classifier.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/steward_features.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/store_factory.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/transcript_miner.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/turn_schema.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/vault_bases.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/vault_curator.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/vault_exporter.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/vault_log.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/vault_synthesis.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/verbatim_recall.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/webhook.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/wiki_freshness.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/wiki_similarity.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster/wiki_validate.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster.egg-info/dependency_links.txt +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/memorymaster.egg-info/entry_points.txt +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/agg_recall_latency.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/alert_operator_metrics.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/audit_dedupe_precision.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/autoresearch_daemon.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/backfill_entity_extraction.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/backfill_graph_store.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/backfill_stop_hook_citations.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/backtest_steward_classifier.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/build_steward_training_set.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/check_hook_template_drift.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/claude_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/codex_live_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/compaction_edge_cases.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/compaction_trace_report.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/compaction_trace_validate.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/confusion_matrix_eval.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/conversation_importer.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/conversation_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/e2e_operator.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/email_live_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/eval_bm25_sweep.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/eval_classify_f1.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/eval_memorymaster.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/eval_recall_precision_at_5.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/eval_recall_quality.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/eval_steward_pareto.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/eval_verbatim_recall.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/expand_recall_eval.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/generate_drill_signoff.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/git_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/github_live_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/gitnexus_to_claims.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/grid_recall_weights.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/index_claims_to_qdrant.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/ingest_planning_docs.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/jira_live_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/label_prompts_with_judge.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/llm_benchmark.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/measure_dedupe_thresholds.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/merge_scope_variants.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/messages_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/operator_metrics.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/precompute_candidates.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/recurring_incident_drill.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/release_readiness.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/run_codex_autologger.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/run_incident_drill.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/scheduled_ingest.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/setup-hooks.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/slack_live_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/sync_hook_templates.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/tickets_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/train_steward_classifier.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/scripts/webhook_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/setup.cfg +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/conftest.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/integration/test_extract_llm_ollama_live.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_access_control.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_action_exporters.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_action_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_atlas_claim_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_atlas_contract.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_atlas_source_schema.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_auto_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_auto_ingest_hook_citations.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_auto_ingest_hook_schema.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_auto_validate.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_bm25_per_field.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_candidate_dedupe.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_claim_edges.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_claim_links.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_claim_type_ranking.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_classify_hook_f1.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_classify_hook_latency.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_claude_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_cli_json_flag.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_cli_ready.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_cli_review_queue.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_cli_subcommands.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_closets.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_closets_recall_integration.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_compact_summaries.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_compaction_trace.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_config.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_conflict_resolver.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_confusion_matrix_eval.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_connection_retry.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_connectors.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_context_hook.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_context_optimizer.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_conversation_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_deterministic_predicates.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_embeddings_coverage.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_entity_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_entity_extractor_llm.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_entity_graph.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_entity_new_kinds.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_entity_regex_v3.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_entity_registry.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_eval_harness.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_events_schema.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_extract_llm_ollama.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_federated_graphify_mcp.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_feedback.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_fts5_search.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_graph_distance.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_graph_store.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_handler_regressions.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_hook_env_isolation.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_human_id.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_incident_drill_runner.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_integration_workflows.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_key_rotator.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_lifecycle.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_llm_fallback.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_llm_provider_claude_cli.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_llm_steward_coverage.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_llm_steward_key_rotation.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_mcp_helpers.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_media_processing.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_metrics_exporter.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_obsidian_mind_patterns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_operator.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_operator_queue.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_perf_smoke_config.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_plugins.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_policy_coverage.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_policy_mode_env.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_postgres_parity.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_qdrant_backend.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_qmd_bridge.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_query_classifier.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_query_expansion.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_recall_entity_fanout.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_recall_fusion.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_recall_latency.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_recall_precision_at_5.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_recall_tokenizer.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_recall_vector_fallback.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_reliability_hardening.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_review.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_rl_trainer.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_rrf_auto_gate.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_scheduler.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_schema.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_scope_boost.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_scope_utils.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_security_access.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_security_patterns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_sensitivity_filter_adversarial.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_sensitivity_filter_adversarial_v2.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_service_coverage.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_session_tracker.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_staleness.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_stealth_mode.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_steward.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_steward_classifier.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_steward_features.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_steward_features_v3.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_steward_resolution_parity.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_store_factory.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_tenant_isolation.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_turn_schema.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_two_pass_recall.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_v311_fixes.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_v313_e2e.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_v313_run_cycle_dedupe.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_v390_e2e.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_v391_strict_warnings.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_vault_exporter.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_vector_search.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_verbatim_dedup.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_verbatim_recall.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_webhook.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_whatsapp_importer.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_wiki_binding.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_wiki_explored_and_contradictions.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_wiki_similarity_multiscope.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.15.0}/tests/test_wiki_validate_cli.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memorymaster
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.15.0
|
|
4
4
|
Summary: Production-grade memory reliability system for AI coding agents. Lifecycle-managed claims with citations, conflict detection, steward governance, and MCP integration.
|
|
5
5
|
Author: wolverin0
|
|
6
6
|
License: MIT
|
|
@@ -17,6 +17,8 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
|
17
17
|
Requires-Python: >=3.10
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
License-File: LICENSE
|
|
20
|
+
Requires-Dist: requests>=2.31
|
|
21
|
+
Requires-Dist: tenacity>=8.2
|
|
20
22
|
Provides-Extra: postgres
|
|
21
23
|
Requires-Dist: psycopg[binary]>=3.2; extra == "postgres"
|
|
22
24
|
Provides-Extra: security
|
|
@@ -61,29 +63,23 @@ MemoryMaster prevents the #1 problem with agent memory: **drift, stale assumptio
|
|
|
61
63
|
|
|
62
64
|
## Architecture
|
|
63
65
|
|
|
66
|
+
MemoryMaster is layered around MCP/CLI entry points, the `MemoryService` facade, SQLite/Postgres
|
|
67
|
+
storage, optional Qdrant vector search, scheduled jobs, and the Obsidian wiki/vault layer. The
|
|
68
|
+
canonical ingest path is:
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
MCP/CLI -> sensitivity filter -> MemoryService.ingest -> store write -> FTS5 index
|
|
64
72
|
```
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
v v
|
|
71
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
72
|
-
│ MemoryMaster Core │
|
|
73
|
-
│ ┌──────────┐ ┌───────────┐ ┌──────────┐ ┌───────────────┐ │
|
|
74
|
-
│ │ Ingestor │ │ Extractor │ │ Validator │ │ State Engine │ │
|
|
75
|
-
│ │ (events) │->│ (claims) │->│ (probes) │->│ (6-state FSM) │ │
|
|
76
|
-
│ └──────────┘ └───────────┘ └──────────┘ └───────────────┘ │
|
|
77
|
-
│ ┌──────────┐ ┌───────────┐ ┌──────────┐ ┌───────────────┐ │
|
|
78
|
-
│ │ Retrieval│ │ Compactor │ │ Steward │ │ Dashboard │ │
|
|
79
|
-
│ │ (hybrid) │ │ (archive) │ │ (govern) │ │ (HTML+SSE) │ │
|
|
80
|
-
│ └──────────┘ └───────────┘ └──────────┘ └───────────────┘ │
|
|
81
|
-
└────────┬──────────────┬──────────────┬──────────┬───────────────┘
|
|
82
|
-
v v v v
|
|
83
|
-
SQLite/Postgres Qdrant Ollama/CLI Claude Code
|
|
84
|
-
(vectors) (LLM stack) Auto Dream + Vault
|
|
73
|
+
|
|
74
|
+
The query path is:
|
|
75
|
+
|
|
76
|
+
```text
|
|
77
|
+
query_memory -> MemoryService.query -> storage reads + optional Qdrant candidates -> ranked context
|
|
85
78
|
```
|
|
86
79
|
|
|
80
|
+
See [docs/architecture.md](docs/architecture.md) for the current module map, data-flow details,
|
|
81
|
+
recent PR status, and sensitivity-filter invariants.
|
|
82
|
+
|
|
87
83
|
## Key features
|
|
88
84
|
|
|
89
85
|
- **6-state lifecycle**: `candidate` → `confirmed` → `stale` → `superseded` → `conflicted` → `archived`
|
|
@@ -104,18 +100,20 @@ Full feature index lives in [`docs/handbook.md`](docs/handbook.md).
|
|
|
104
100
|
|
|
105
101
|
## Prerequisites
|
|
106
102
|
|
|
107
|
-
**Required**
|
|
103
|
+
**Required (the package won't function without these)**
|
|
108
104
|
|
|
109
105
|
- Python **3.10+** with `pip`
|
|
110
106
|
- Claude Code, Codex, or any MCP-compatible agent
|
|
107
|
+
- **An LLM provider** — pick one: Claude Code OAuth (free if you're a subscriber, set `MEMORYMASTER_LLM_PROVIDER=claude_cli`), a free Gemini API key from [aistudio.google.com](https://aistudio.google.com), OpenAI, Anthropic API, or local Ollama. The steward, auto-ingest, and wiki-absorb cycles all need an LLM — without one, claims pile up as `candidate` and never get validated, deduped, or compiled into the wiki.
|
|
108
|
+
|
|
109
|
+
**Strongly recommended (you'll lose ~80% of the value without these)**
|
|
110
|
+
|
|
111
|
+
- **Node.js 18+** for [graphify](https://github.com/wolverin0/graphify) and [GitNexus](https://github.com/wolverin0/gitnexus) — these are the cached intelligence layers that make MemoryMaster cheap to query. Without them, every "what does this codebase do?" question burns tokens cold-exploring files the graph already mapped. The `intelligence-first` workflow in `CLAUDE.md` assumes both are installed.
|
|
112
|
+
- **Obsidian 1.6+** with the [Bases](https://help.obsidian.md/Plugins/Bases) core plugin — the wiki engine writes plain Markdown so any editor works, but Obsidian's backlinks, graph view, and Bases dashboards are how you actually navigate `wiki-absorb` output. Without Obsidian, the wiki is just a folder of files.
|
|
111
113
|
|
|
112
|
-
**Optional**
|
|
114
|
+
**Optional (nice to have)**
|
|
113
115
|
|
|
114
|
-
- **
|
|
115
|
-
- A free Gemini API key from [aistudio.google.com](https://aistudio.google.com) — powers the auto-ingest hook at ~zero cost
|
|
116
|
-
- **Node.js 18+** for graphify and GitNexus
|
|
117
|
-
- **Obsidian 1.6+** with the Bases core plugin (for visual wiki browsing)
|
|
118
|
-
- **Docker** for Qdrant (SQLite FTS5 is the default and works out of the box)
|
|
116
|
+
- **Docker** for Qdrant — vector retrieval. SQLite FTS5 is the default and works out of the box; add Qdrant when you want semantic recall on top of keyword search.
|
|
119
117
|
|
|
120
118
|
## Quick start
|
|
121
119
|
|
|
@@ -17,29 +17,23 @@ MemoryMaster prevents the #1 problem with agent memory: **drift, stale assumptio
|
|
|
17
17
|
|
|
18
18
|
## Architecture
|
|
19
19
|
|
|
20
|
+
MemoryMaster is layered around MCP/CLI entry points, the `MemoryService` facade, SQLite/Postgres
|
|
21
|
+
storage, optional Qdrant vector search, scheduled jobs, and the Obsidian wiki/vault layer. The
|
|
22
|
+
canonical ingest path is:
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
MCP/CLI -> sensitivity filter -> MemoryService.ingest -> store write -> FTS5 index
|
|
20
26
|
```
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
v v
|
|
27
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
28
|
-
│ MemoryMaster Core │
|
|
29
|
-
│ ┌──────────┐ ┌───────────┐ ┌──────────┐ ┌───────────────┐ │
|
|
30
|
-
│ │ Ingestor │ │ Extractor │ │ Validator │ │ State Engine │ │
|
|
31
|
-
│ │ (events) │->│ (claims) │->│ (probes) │->│ (6-state FSM) │ │
|
|
32
|
-
│ └──────────┘ └───────────┘ └──────────┘ └───────────────┘ │
|
|
33
|
-
│ ┌──────────┐ ┌───────────┐ ┌──────────┐ ┌───────────────┐ │
|
|
34
|
-
│ │ Retrieval│ │ Compactor │ │ Steward │ │ Dashboard │ │
|
|
35
|
-
│ │ (hybrid) │ │ (archive) │ │ (govern) │ │ (HTML+SSE) │ │
|
|
36
|
-
│ └──────────┘ └───────────┘ └──────────┘ └───────────────┘ │
|
|
37
|
-
└────────┬──────────────┬──────────────┬──────────┬───────────────┘
|
|
38
|
-
v v v v
|
|
39
|
-
SQLite/Postgres Qdrant Ollama/CLI Claude Code
|
|
40
|
-
(vectors) (LLM stack) Auto Dream + Vault
|
|
27
|
+
|
|
28
|
+
The query path is:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
query_memory -> MemoryService.query -> storage reads + optional Qdrant candidates -> ranked context
|
|
41
32
|
```
|
|
42
33
|
|
|
34
|
+
See [docs/architecture.md](docs/architecture.md) for the current module map, data-flow details,
|
|
35
|
+
recent PR status, and sensitivity-filter invariants.
|
|
36
|
+
|
|
43
37
|
## Key features
|
|
44
38
|
|
|
45
39
|
- **6-state lifecycle**: `candidate` → `confirmed` → `stale` → `superseded` → `conflicted` → `archived`
|
|
@@ -60,18 +54,20 @@ Full feature index lives in [`docs/handbook.md`](docs/handbook.md).
|
|
|
60
54
|
|
|
61
55
|
## Prerequisites
|
|
62
56
|
|
|
63
|
-
**Required**
|
|
57
|
+
**Required (the package won't function without these)**
|
|
64
58
|
|
|
65
59
|
- Python **3.10+** with `pip`
|
|
66
60
|
- Claude Code, Codex, or any MCP-compatible agent
|
|
61
|
+
- **An LLM provider** — pick one: Claude Code OAuth (free if you're a subscriber, set `MEMORYMASTER_LLM_PROVIDER=claude_cli`), a free Gemini API key from [aistudio.google.com](https://aistudio.google.com), OpenAI, Anthropic API, or local Ollama. The steward, auto-ingest, and wiki-absorb cycles all need an LLM — without one, claims pile up as `candidate` and never get validated, deduped, or compiled into the wiki.
|
|
62
|
+
|
|
63
|
+
**Strongly recommended (you'll lose ~80% of the value without these)**
|
|
64
|
+
|
|
65
|
+
- **Node.js 18+** for [graphify](https://github.com/wolverin0/graphify) and [GitNexus](https://github.com/wolverin0/gitnexus) — these are the cached intelligence layers that make MemoryMaster cheap to query. Without them, every "what does this codebase do?" question burns tokens cold-exploring files the graph already mapped. The `intelligence-first` workflow in `CLAUDE.md` assumes both are installed.
|
|
66
|
+
- **Obsidian 1.6+** with the [Bases](https://help.obsidian.md/Plugins/Bases) core plugin — the wiki engine writes plain Markdown so any editor works, but Obsidian's backlinks, graph view, and Bases dashboards are how you actually navigate `wiki-absorb` output. Without Obsidian, the wiki is just a folder of files.
|
|
67
67
|
|
|
68
|
-
**Optional**
|
|
68
|
+
**Optional (nice to have)**
|
|
69
69
|
|
|
70
|
-
- **
|
|
71
|
-
- A free Gemini API key from [aistudio.google.com](https://aistudio.google.com) — powers the auto-ingest hook at ~zero cost
|
|
72
|
-
- **Node.js 18+** for graphify and GitNexus
|
|
73
|
-
- **Obsidian 1.6+** with the Bases core plugin (for visual wiki browsing)
|
|
74
|
-
- **Docker** for Qdrant (SQLite FTS5 is the default and works out of the box)
|
|
70
|
+
- **Docker** for Qdrant — vector retrieval. SQLite FTS5 is the default and works out of the box; add Qdrant when you want semantic recall on top of keyword search.
|
|
75
71
|
|
|
76
72
|
## Quick start
|
|
77
73
|
|
|
@@ -10,6 +10,7 @@ import json
|
|
|
10
10
|
import logging
|
|
11
11
|
import sqlite3
|
|
12
12
|
from datetime import datetime, timedelta, timezone
|
|
13
|
+
from typing import TYPE_CHECKING, Any
|
|
13
14
|
|
|
14
15
|
from memorymaster.embeddings import EmbeddingProvider, cosine_similarity
|
|
15
16
|
from memorymaster.models import (
|
|
@@ -23,16 +24,37 @@ from memorymaster.models import (
|
|
|
23
24
|
validate_transition_event_type,
|
|
24
25
|
)
|
|
25
26
|
|
|
26
|
-
logger = logging.getLogger(__name__)
|
|
27
|
-
|
|
28
27
|
from memorymaster._storage_shared import (
|
|
29
28
|
EVENT_HASH_ALGO,
|
|
30
29
|
ConcurrentModificationError,
|
|
31
30
|
utc_now,
|
|
32
31
|
)
|
|
33
32
|
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
|
|
34
35
|
|
|
35
36
|
class _LifecycleMixin:
|
|
37
|
+
if TYPE_CHECKING:
|
|
38
|
+
def connect(self) -> sqlite3.Connection: ...
|
|
39
|
+
|
|
40
|
+
def get_claim(self, claim_id: int, include_citations: bool = True) -> Claim | None: ...
|
|
41
|
+
|
|
42
|
+
def _ensure_event_integrity_schema(self, conn: sqlite3.Connection) -> None: ...
|
|
43
|
+
|
|
44
|
+
def _ensure_embeddings_schema(self, conn: sqlite3.Connection) -> None: ...
|
|
45
|
+
|
|
46
|
+
def _insert_event_row(
|
|
47
|
+
self,
|
|
48
|
+
conn: sqlite3.Connection,
|
|
49
|
+
*,
|
|
50
|
+
claim_id: int | None,
|
|
51
|
+
event_type: str,
|
|
52
|
+
from_status: str | None,
|
|
53
|
+
to_status: str | None,
|
|
54
|
+
details: str | None,
|
|
55
|
+
payload_json: str | None,
|
|
56
|
+
created_at: str,
|
|
57
|
+
) -> int: ...
|
|
36
58
|
|
|
37
59
|
def apply_status_transition(
|
|
38
60
|
self,
|
|
@@ -102,14 +124,64 @@ class _LifecycleMixin:
|
|
|
102
124
|
old_claim = self.get_claim(old_claim_id, include_citations=False)
|
|
103
125
|
if old_claim is None:
|
|
104
126
|
return
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
)
|
|
112
|
-
|
|
127
|
+
if old_claim.status == "superseded" or old_claim.replaced_by_claim_id is not None:
|
|
128
|
+
raise ConcurrentModificationError(
|
|
129
|
+
f"Claim {old_claim_id} was already superseded. Reload and retry."
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
now = utc_now()
|
|
133
|
+
with self.connect() as conn:
|
|
134
|
+
target = conn.execute(
|
|
135
|
+
"SELECT supersedes_claim_id FROM claims WHERE id = ?",
|
|
136
|
+
(new_claim_id,),
|
|
137
|
+
).fetchone()
|
|
138
|
+
if target is None:
|
|
139
|
+
raise ValueError(f"Replacement claim {new_claim_id} does not exist.")
|
|
140
|
+
if target["supersedes_claim_id"] not in {None, old_claim_id}:
|
|
141
|
+
raise ConcurrentModificationError(
|
|
142
|
+
f"Claim {new_claim_id} already supersedes another claim. Reload and retry."
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
cur = conn.execute(
|
|
146
|
+
"""
|
|
147
|
+
UPDATE claims
|
|
148
|
+
SET status = 'superseded', updated_at = ?, replaced_by_claim_id = ?,
|
|
149
|
+
version = version + 1, valid_until = COALESCE(?, valid_until)
|
|
150
|
+
WHERE id = ? AND version = ? AND status != 'superseded'
|
|
151
|
+
AND replaced_by_claim_id IS NULL
|
|
152
|
+
""",
|
|
153
|
+
(now, new_claim_id, now, old_claim_id, old_claim.version),
|
|
154
|
+
)
|
|
155
|
+
if cur.rowcount == 0:
|
|
156
|
+
raise ConcurrentModificationError(
|
|
157
|
+
f"Claim {old_claim_id} was modified by another writer. Reload and retry."
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
cur = conn.execute(
|
|
161
|
+
"""
|
|
162
|
+
UPDATE claims
|
|
163
|
+
SET supersedes_claim_id = ?, updated_at = ?
|
|
164
|
+
WHERE id = ? AND (supersedes_claim_id IS NULL OR supersedes_claim_id = ?)
|
|
165
|
+
""",
|
|
166
|
+
(old_claim_id, now, new_claim_id, old_claim_id),
|
|
167
|
+
)
|
|
168
|
+
if cur.rowcount == 0:
|
|
169
|
+
conn.rollback()
|
|
170
|
+
raise ConcurrentModificationError(
|
|
171
|
+
f"Claim {new_claim_id} was modified by another writer. Reload and retry."
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
self._insert_event_row(
|
|
175
|
+
conn,
|
|
176
|
+
claim_id=old_claim.id,
|
|
177
|
+
event_type="supersession",
|
|
178
|
+
from_status=old_claim.status,
|
|
179
|
+
to_status="superseded",
|
|
180
|
+
details=reason,
|
|
181
|
+
payload_json=json.dumps({"replaced_by_claim_id": new_claim_id}),
|
|
182
|
+
created_at=now,
|
|
183
|
+
)
|
|
184
|
+
conn.commit()
|
|
113
185
|
|
|
114
186
|
|
|
115
187
|
def delete_old_events(self, retain_days: int) -> int:
|
|
@@ -117,8 +189,8 @@ class _LifecycleMixin:
|
|
|
117
189
|
return 0
|
|
118
190
|
|
|
119
191
|
|
|
120
|
-
def reconcile_integrity(self, *, fix: bool = False, limit: int = 500) -> dict[str,
|
|
121
|
-
report: dict[str,
|
|
192
|
+
def reconcile_integrity(self, *, fix: bool = False, limit: int = 500) -> dict[str, Any]:
|
|
193
|
+
report: dict[str, Any] = {
|
|
122
194
|
"checked_at": utc_now(),
|
|
123
195
|
"fix_mode": bool(fix),
|
|
124
196
|
"issues": {},
|
|
@@ -9,6 +9,7 @@ from __future__ import annotations
|
|
|
9
9
|
import logging
|
|
10
10
|
import sqlite3
|
|
11
11
|
from datetime import datetime, timedelta, timezone
|
|
12
|
+
from typing import TYPE_CHECKING
|
|
12
13
|
|
|
13
14
|
from memorymaster.models import (
|
|
14
15
|
Citation,
|
|
@@ -22,6 +23,10 @@ logger = logging.getLogger(__name__)
|
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class _ReadMixin:
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
def connect(self) -> sqlite3.Connection: ...
|
|
28
|
+
|
|
29
|
+
def init_db(self) -> None: ...
|
|
25
30
|
|
|
26
31
|
def _check_idempotency(self, conn: sqlite3.Connection, idempotency_key: str | None) -> Claim | None:
|
|
27
32
|
"""Check if a claim with this idempotency key already exists. Returns existing claim or None."""
|
|
@@ -8,7 +8,7 @@ from __future__ import annotations
|
|
|
8
8
|
|
|
9
9
|
import json
|
|
10
10
|
import sqlite3
|
|
11
|
-
from typing import Any
|
|
11
|
+
from typing import TYPE_CHECKING, Any
|
|
12
12
|
|
|
13
13
|
from memorymaster._storage_shared import utc_now
|
|
14
14
|
from memorymaster.models import (
|
|
@@ -51,6 +51,22 @@ def _bounded_confidence(confidence: float | None) -> float | None:
|
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
class _SourceItemsMixin:
|
|
54
|
+
if TYPE_CHECKING:
|
|
55
|
+
def connect(self) -> sqlite3.Connection: ...
|
|
56
|
+
|
|
57
|
+
def _insert_event_row(
|
|
58
|
+
self,
|
|
59
|
+
conn: sqlite3.Connection,
|
|
60
|
+
*,
|
|
61
|
+
claim_id: int | None,
|
|
62
|
+
event_type: str,
|
|
63
|
+
from_status: str | None,
|
|
64
|
+
to_status: str | None,
|
|
65
|
+
details: str | None,
|
|
66
|
+
payload_json: str | None,
|
|
67
|
+
created_at: str,
|
|
68
|
+
) -> int: ...
|
|
69
|
+
|
|
54
70
|
def upsert_external_source(
|
|
55
71
|
self,
|
|
56
72
|
*,
|
|
@@ -9,21 +9,42 @@ from __future__ import annotations
|
|
|
9
9
|
import json
|
|
10
10
|
import logging
|
|
11
11
|
import sqlite3
|
|
12
|
+
from typing import TYPE_CHECKING
|
|
12
13
|
|
|
13
14
|
from memorymaster.models import (
|
|
14
15
|
CitationInput,
|
|
15
16
|
Claim,
|
|
16
17
|
validate_event_payload,
|
|
17
18
|
)
|
|
18
|
-
|
|
19
|
-
logger = logging.getLogger(__name__)
|
|
20
|
-
|
|
21
19
|
from memorymaster._storage_shared import (
|
|
22
20
|
utc_now,
|
|
23
21
|
)
|
|
24
22
|
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
25
|
|
|
26
26
|
class _WriteClaimsMixin:
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
def connect(self) -> sqlite3.Connection: ...
|
|
29
|
+
|
|
30
|
+
def _check_idempotency(self, conn: sqlite3.Connection, idempotency_key: str | None) -> Claim | None: ...
|
|
31
|
+
|
|
32
|
+
def get_claim(self, claim_id: int, include_citations: bool = True) -> Claim | None: ...
|
|
33
|
+
|
|
34
|
+
def _allocate_human_id(self, conn: sqlite3.Connection, subject: str | None, text: str, claim_id: int) -> str: ...
|
|
35
|
+
|
|
36
|
+
def _insert_event_row(
|
|
37
|
+
self,
|
|
38
|
+
conn: sqlite3.Connection,
|
|
39
|
+
*,
|
|
40
|
+
claim_id: int | None,
|
|
41
|
+
event_type: str,
|
|
42
|
+
from_status: str | None,
|
|
43
|
+
to_status: str | None,
|
|
44
|
+
details: str | None,
|
|
45
|
+
payload_json: str | None,
|
|
46
|
+
created_at: str,
|
|
47
|
+
) -> int: ...
|
|
27
48
|
|
|
28
49
|
def create_claim(
|
|
29
50
|
self,
|
|
@@ -3,27 +3,25 @@
|
|
|
3
3
|
When two claims contradict (same subject/predicate, different object_value),
|
|
4
4
|
asks an LLM to evaluate which one has stronger evidence and should be kept.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
Provider routing goes through `memorymaster.llm_provider.call_llm`, which
|
|
7
|
+
honors `MEMORYMASTER_LLM_PROVIDER` (claude_cli / google / openai / anthropic
|
|
8
|
+
/ ollama) instead of the previous hardcoded Ollama-only path. The loser
|
|
9
|
+
gets superseded, not deleted — preserving full audit trail.
|
|
8
10
|
"""
|
|
9
11
|
|
|
10
12
|
from __future__ import annotations
|
|
11
13
|
|
|
12
14
|
import json
|
|
13
15
|
import logging
|
|
14
|
-
import os
|
|
15
|
-
import urllib.error
|
|
16
|
-
import urllib.request
|
|
17
16
|
from typing import Any
|
|
18
17
|
|
|
18
|
+
from memorymaster._storage_shared import ConcurrentModificationError
|
|
19
19
|
from memorymaster.lifecycle import transition_claim
|
|
20
|
+
from memorymaster.llm_provider import call_llm
|
|
20
21
|
from memorymaster.models import Claim
|
|
21
22
|
|
|
22
23
|
logger = logging.getLogger(__name__)
|
|
23
24
|
|
|
24
|
-
DEFAULT_OLLAMA_URL = "http://localhost:11434"
|
|
25
|
-
DEFAULT_MODEL = "deepseek-coder-v2:16b"
|
|
26
|
-
|
|
27
25
|
RESOLUTION_PROMPT = """You are a memory quality evaluator. Two claims contradict each other.
|
|
28
26
|
Decide which one should be KEPT based on:
|
|
29
27
|
1. Recency (newer information is usually more accurate)
|
|
@@ -47,49 +45,34 @@ Return JSON only: {{"winner": "A" or "B", "reason": "brief explanation"}}"""
|
|
|
47
45
|
|
|
48
46
|
|
|
49
47
|
def _llm_evaluate(prompt: str, model: str = "", base_url: str = "") -> dict:
|
|
50
|
-
"""
|
|
48
|
+
"""Ask the configured LLM to pick the winner and parse its JSON response.
|
|
51
49
|
|
|
52
|
-
Returns empty dict {} if LLM returns invalid JSON or
|
|
50
|
+
Returns empty dict {} if the LLM returns invalid JSON or the call fails.
|
|
51
|
+
The `model` and `base_url` kwargs are kept for backwards compatibility but
|
|
52
|
+
are no longer consulted — provider routing is centralized in llm_provider.
|
|
53
53
|
"""
|
|
54
|
-
url = (base_url or os.environ.get("OLLAMA_URL") or DEFAULT_OLLAMA_URL).rstrip("/")
|
|
55
|
-
mdl = model or os.environ.get("RESOLVER_LLM_MODEL") or DEFAULT_MODEL
|
|
56
|
-
|
|
57
|
-
body = json.dumps({
|
|
58
|
-
"model": mdl,
|
|
59
|
-
"messages": [{"role": "user", "content": prompt}],
|
|
60
|
-
"stream": False,
|
|
61
|
-
"options": {"temperature": 0.1, "num_predict": 200},
|
|
62
|
-
}).encode()
|
|
63
|
-
|
|
64
|
-
req = urllib.request.Request(
|
|
65
|
-
f"{url}/api/chat",
|
|
66
|
-
data=body,
|
|
67
|
-
headers={"Content-Type": "application/json"},
|
|
68
|
-
method="POST",
|
|
69
|
-
)
|
|
70
54
|
try:
|
|
71
|
-
|
|
72
|
-
result = json.loads(resp.read())
|
|
73
|
-
raw = result.get("message", {}).get("content", "")
|
|
74
|
-
# Parse JSON from response
|
|
75
|
-
text = raw.strip()
|
|
76
|
-
if text.startswith("```"):
|
|
77
|
-
lines = text.split("\n")
|
|
78
|
-
lines = [line for line in lines if not line.strip().startswith("```")]
|
|
79
|
-
text = "\n".join(lines)
|
|
80
|
-
try:
|
|
81
|
-
parsed = json.loads(text)
|
|
82
|
-
if not isinstance(parsed, dict):
|
|
83
|
-
logger.warning("LLM returned non-dict JSON: %s", type(parsed))
|
|
84
|
-
return {}
|
|
85
|
-
return parsed
|
|
86
|
-
except json.JSONDecodeError as exc:
|
|
87
|
-
logger.warning("LLM returned invalid JSON: %s (text: %s)", exc, text[:100])
|
|
88
|
-
return {}
|
|
55
|
+
raw = call_llm(prompt, "")
|
|
89
56
|
except Exception as exc:
|
|
90
57
|
logger.warning("LLM conflict evaluation failed: %s", exc)
|
|
91
58
|
return {}
|
|
92
59
|
|
|
60
|
+
text = (raw or "").strip()
|
|
61
|
+
if text.startswith("```"):
|
|
62
|
+
lines = [line for line in text.split("\n") if not line.strip().startswith("```")]
|
|
63
|
+
text = "\n".join(lines)
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
parsed = json.loads(text)
|
|
67
|
+
except json.JSONDecodeError as exc:
|
|
68
|
+
logger.warning("LLM returned invalid JSON: %s (text: %s)", exc, text[:100])
|
|
69
|
+
return {}
|
|
70
|
+
|
|
71
|
+
if not isinstance(parsed, dict):
|
|
72
|
+
logger.warning("LLM returned non-dict JSON: %s", type(parsed))
|
|
73
|
+
return {}
|
|
74
|
+
return parsed
|
|
75
|
+
|
|
93
76
|
|
|
94
77
|
def _cite_summary(claim: Claim) -> str:
|
|
95
78
|
"""Summarize citations for LLM prompt."""
|
|
@@ -132,7 +115,7 @@ def resolve_conflict_pair(
|
|
|
132
115
|
loser = claim_b if winner_letter == "A" else claim_a
|
|
133
116
|
|
|
134
117
|
try:
|
|
135
|
-
transition_claim(
|
|
118
|
+
updated = transition_claim(
|
|
136
119
|
store,
|
|
137
120
|
claim_id=loser.id,
|
|
138
121
|
to_status="superseded",
|
|
@@ -140,12 +123,35 @@ def resolve_conflict_pair(
|
|
|
140
123
|
event_type="validator",
|
|
141
124
|
replaced_by_claim_id=winner.id,
|
|
142
125
|
)
|
|
126
|
+
current_replacement_id = getattr(updated, "replaced_by_claim_id", None)
|
|
127
|
+
if current_replacement_id != winner.id:
|
|
128
|
+
return {
|
|
129
|
+
"resolved": False,
|
|
130
|
+
"reason": "lost_race",
|
|
131
|
+
"winner_id": winner.id,
|
|
132
|
+
"loser_id": loser.id,
|
|
133
|
+
"current_replacement_id": current_replacement_id,
|
|
134
|
+
}
|
|
135
|
+
if hasattr(store, "set_supersedes"):
|
|
136
|
+
store.set_supersedes(winner.id, loser.id)
|
|
143
137
|
return {
|
|
144
138
|
"resolved": True,
|
|
145
139
|
"winner_id": winner.id,
|
|
146
140
|
"loser_id": loser.id,
|
|
147
141
|
"reason": reason,
|
|
148
142
|
}
|
|
143
|
+
except ConcurrentModificationError as exc:
|
|
144
|
+
current = store.get_claim(loser.id, include_citations=False)
|
|
145
|
+
if current is not None and current.status == "superseded":
|
|
146
|
+
return {
|
|
147
|
+
"resolved": False,
|
|
148
|
+
"reason": "lost_race",
|
|
149
|
+
"winner_id": winner.id,
|
|
150
|
+
"loser_id": loser.id,
|
|
151
|
+
"current_replacement_id": current.replaced_by_claim_id,
|
|
152
|
+
}
|
|
153
|
+
logger.warning("Failed to resolve conflict %d vs %d: %s", claim_a.id, claim_b.id, exc)
|
|
154
|
+
return {"resolved": False, "reason": str(exc)}
|
|
149
155
|
except Exception as exc:
|
|
150
156
|
logger.warning("Failed to resolve conflict %d vs %d: %s", claim_a.id, claim_b.id, exc)
|
|
151
157
|
return {"resolved": False, "reason": str(exc)}
|