memorymaster 3.13.0__tar.gz → 3.14.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.14.0}/PKG-INFO +24 -28
- {memorymaster-3.13.0 → memorymaster-3.14.0}/README.md +23 -27
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/_storage_lifecycle.py +60 -10
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/auto_resolver.py +51 -45
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/claim_verifier.py +0 -1
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/cli.py +53 -4
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/cli_handlers_basic.py +155 -3
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/config.py +76 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/config_templates/hooks/memorymaster-dream-sync.py +2 -1
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/config_templates/hooks/memorymaster-recall.py +3 -1
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/config_templates/hooks/memorymaster-steward-cycle.py +2 -1
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/conflict_resolver.py +113 -2
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/context_optimizer.py +161 -19
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/dashboard.py +391 -1
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/db_merge.py +133 -11
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/dream_bridge.py +12 -5
- memorymaster-3.14.0/memorymaster/jobs/calibration.py +120 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/jobs/compact_summaries.py +6 -2
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/jobs/compactor.py +93 -12
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/jobs/decay.py +62 -1
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/jobs/dedup.py +155 -2
- memorymaster-3.14.0/memorymaster/jobs/entity_graph_export.py +210 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/lifecycle.py +31 -1
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/llm_provider.py +73 -2
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/mcp_server.py +378 -34
- memorymaster-3.14.0/memorymaster/mcp_usage.py +43 -0
- memorymaster-3.14.0/memorymaster/observability.py +183 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/postgres_store.py +16 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/schema.sql +9 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/schema_postgres.sql +9 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/security.py +7 -2
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/service.py +311 -7
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/setup_hooks.py +1 -1
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/snapshot.py +64 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/steward.py +16 -14
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/storage.py +0 -27
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/vault_linter.py +164 -13
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/vault_query_capture.py +1 -1
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/verbatim_store.py +10 -4
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/wiki_engine.py +238 -22
- memorymaster-3.14.0/memorymaster/wiki_suggest.py +270 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0/memorymaster.egg-info}/PKG-INFO +24 -28
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster.egg-info/SOURCES.txt +44 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/pyproject.toml +1 -1
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_auto_resolver.py +10 -18
- memorymaster-3.14.0/tests/test_calibration.py +134 -0
- memorymaster-3.14.0/tests/test_calibration_priors_applied.py +20 -0
- memorymaster-3.14.0/tests/test_cli_dry_run.py +142 -0
- memorymaster-3.14.0/tests/test_compact_summaries_sensitivity.py +69 -0
- memorymaster-3.14.0/tests/test_compactor_artifact_order.py +40 -0
- memorymaster-3.14.0/tests/test_context_optimizer_provider.py +145 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_dashboard.py +96 -1
- memorymaster-3.14.0/tests/test_dashboard_coverage.py +321 -0
- memorymaster-3.14.0/tests/test_dashboard_latency.py +111 -0
- memorymaster-3.14.0/tests/test_dashboard_lineage.py +70 -0
- memorymaster-3.14.0/tests/test_dashboard_review_queue.py +143 -0
- memorymaster-3.14.0/tests/test_db_merge_confidence_conflict.py +71 -0
- memorymaster-3.14.0/tests/test_db_merge_coverage_v2.py +260 -0
- memorymaster-3.14.0/tests/test_decay_coverage.py +212 -0
- memorymaster-3.14.0/tests/test_decay_respects_pinned.py +120 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_dedup.py +9 -0
- memorymaster-3.14.0/tests/test_dedup_cli.py +120 -0
- memorymaster-3.14.0/tests/test_dedup_conflict_disambiguation.py +52 -0
- memorymaster-3.14.0/tests/test_dream_bridge_coverage_v2.py +186 -0
- memorymaster-3.14.0/tests/test_dream_bridge_sensitivity.py +76 -0
- memorymaster-3.14.0/tests/test_entity_graph_export.py +147 -0
- memorymaster-3.14.0/tests/test_federated_query_safety.py +91 -0
- memorymaster-3.14.0/tests/test_lifecycle_supersede_invariant.py +87 -0
- memorymaster-3.14.0/tests/test_llm_provider_key_rotation.py +80 -0
- memorymaster-3.14.0/tests/test_mcp_filter_bypass.py +91 -0
- memorymaster-3.14.0/tests/test_mcp_rate_limit.py +101 -0
- memorymaster-3.14.0/tests/test_mcp_server_validation.py +49 -0
- memorymaster-3.14.0/tests/test_mcp_usage.py +95 -0
- memorymaster-3.14.0/tests/test_meta_decisions.py +125 -0
- memorymaster-3.14.0/tests/test_observability.py +47 -0
- memorymaster-3.14.0/tests/test_resolvers_concurrent_supersede.py +148 -0
- memorymaster-3.14.0/tests/test_retrieval_profile.py +120 -0
- memorymaster-3.14.0/tests/test_sensitivity_filter_t07.py +63 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_snapshot.py +2 -1
- memorymaster-3.14.0/tests/test_snapshot_roundtrip.py +168 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_sqlite_core.py +9 -0
- memorymaster-3.14.0/tests/test_storage_parity.py +67 -0
- memorymaster-3.14.0/tests/test_vault_linter_orphan.py +91 -0
- memorymaster-3.14.0/tests/test_verbatim_store.py +67 -0
- memorymaster-3.14.0/tests/test_verbatim_store_qdrant.py +120 -0
- memorymaster-3.14.0/tests/test_wiki_autopromote.py +101 -0
- memorymaster-3.14.0/tests/test_wiki_engine_idempotency.py +170 -0
- memorymaster-3.14.0/tests/test_wiki_suggest.py +124 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/LICENSE +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/artifacts/bm25-per-field-eval-harness.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/benchmarks/longmemeval_runner.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/benchmarks/longmemeval_vector_runner.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/benchmarks/perf_smoke.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/__init__.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/__main__.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/_storage_read.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/_storage_schema.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/_storage_shared.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/_storage_sources.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/_storage_write_claims.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/access_control.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/action_exporters.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/action_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/atlas_claim_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/atlas_contract.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/auto_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/candidate_dedupe.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/claim_edges.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/cli_handlers_curation.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/cli_helpers.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/closets.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/config_templates/claude-md-append.md +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/config_templates/codex-agents-md-append.md +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/config_templates/hooks/memorymaster-auto-ingest.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/config_templates/hooks/memorymaster-classify.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/config_templates/hooks/memorymaster-precompact.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/config_templates/hooks/memorymaster-session-start.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/config_templates/hooks/memorymaster-validate-wiki.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/connectors/__init__.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/connectors/whatsapp.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/context_hook.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/daily_notes.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/embeddings.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/entity_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/entity_graph.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/entity_registry.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/federated_graphify.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/feedback.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/graph_store.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/hook_log.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/jobs/__init__.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/jobs/deterministic.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/jobs/extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/jobs/staleness.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/jobs/validator.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/key_rotator.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/llm_steward.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/media_processing.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/media_providers.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/metrics_exporter.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/models.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/operator.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/operator_queue.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/plugins.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/policy.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/qdrant_backend.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/qdrant_recall_fallback.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/qmd_bridge.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/query_classifier.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/query_expansion.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/recall_fusion.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/recall_tokenizer.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/retrieval.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/retry.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/review.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/rl_trainer.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/scheduler.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/schema.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/scope_utils.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/session_tracker.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/skill_evolver.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/steward_classifier.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/steward_features.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/store_factory.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/transcript_miner.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/turn_schema.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/vault_bases.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/vault_curator.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/vault_exporter.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/vault_log.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/vault_synthesis.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/verbatim_recall.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/webhook.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/wiki_freshness.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/wiki_similarity.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster/wiki_validate.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster.egg-info/dependency_links.txt +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster.egg-info/entry_points.txt +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster.egg-info/requires.txt +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/memorymaster.egg-info/top_level.txt +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/agg_recall_latency.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/alert_operator_metrics.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/audit_dedupe_precision.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/autoresearch_daemon.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/backfill_entity_extraction.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/backfill_graph_store.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/backfill_stop_hook_citations.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/backtest_steward_classifier.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/build_steward_training_set.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/check_hook_template_drift.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/claude_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/codex_live_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/compaction_edge_cases.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/compaction_trace_report.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/compaction_trace_validate.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/confusion_matrix_eval.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/conversation_importer.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/conversation_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/e2e_operator.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/email_live_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/eval_bm25_sweep.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/eval_classify_f1.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/eval_memorymaster.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/eval_recall_precision_at_5.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/eval_recall_quality.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/eval_steward_pareto.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/eval_verbatim_recall.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/expand_recall_eval.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/generate_drill_signoff.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/git_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/github_live_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/gitnexus_to_claims.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/grid_recall_weights.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/index_claims_to_qdrant.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/ingest_planning_docs.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/jira_live_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/label_prompts_with_judge.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/llm_benchmark.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/measure_dedupe_thresholds.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/merge_scope_variants.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/messages_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/operator_metrics.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/precompute_candidates.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/recurring_incident_drill.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/release_readiness.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/run_codex_autologger.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/run_incident_drill.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/run_longmemeval.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/scheduled_ingest.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/setup-hooks.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/slack_live_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/sync_hook_templates.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/tickets_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/train_steward_classifier.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/scripts/webhook_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/setup.cfg +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/conftest.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/integration/test_extract_llm_ollama_live.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_access_control.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_action_exporters.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_action_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_atlas_claim_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_atlas_contract.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_atlas_source_schema.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_auto_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_auto_ingest_hook_citations.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_auto_ingest_hook_schema.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_auto_validate.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_bm25_per_field.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_candidate_dedupe.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_claim_edges.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_claim_links.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_claim_type_ranking.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_classify_hook_f1.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_classify_hook_latency.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_claude_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_cli_json_flag.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_cli_ready.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_cli_review_queue.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_cli_subcommands.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_closets.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_closets_recall_integration.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_compact_summaries.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_compaction_trace.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_config.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_conflict_resolver.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_confusion_matrix_eval.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_connection_retry.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_connectors.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_context_hook.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_context_optimizer.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_conversation_to_turns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_deterministic_predicates.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_embeddings_coverage.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_entity_extractor.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_entity_extractor_llm.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_entity_graph.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_entity_new_kinds.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_entity_regex_v3.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_entity_registry.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_eval_harness.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_events_schema.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_extract_llm_ollama.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_federated_graphify_mcp.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_feedback.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_fts5_search.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_graph_distance.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_graph_store.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_handler_regressions.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_hook_env_isolation.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_human_id.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_incident_drill_runner.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_integration_workflows.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_key_rotator.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_lifecycle.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_llm_fallback.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_llm_provider_claude_cli.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_llm_steward_coverage.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_llm_steward_key_rotation.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_mcp_helpers.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_media_processing.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_metrics_exporter.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_obsidian_mind_patterns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_operator.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_operator_queue.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_perf_smoke_config.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_plugins.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_policy_coverage.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_policy_mode_env.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_postgres_parity.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_qdrant_backend.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_qmd_bridge.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_query_classifier.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_query_expansion.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_recall_entity_fanout.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_recall_fusion.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_recall_latency.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_recall_precision_at_5.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_recall_tokenizer.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_recall_vector_fallback.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_reliability_hardening.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_review.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_rl_trainer.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_rrf_auto_gate.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_scheduler.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_schema.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_scope_boost.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_scope_utils.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_security_access.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_security_patterns.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_sensitivity_filter_adversarial.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_sensitivity_filter_adversarial_v2.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_service_coverage.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_session_tracker.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_staleness.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_stealth_mode.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_steward.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_steward_classifier.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_steward_features.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_steward_features_v3.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_steward_resolution_parity.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_store_factory.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_tenant_isolation.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_turn_schema.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_two_pass_recall.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_v311_fixes.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_v313_e2e.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_v313_run_cycle_dedupe.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_v390_e2e.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_v391_strict_warnings.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_vault_exporter.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_vector_search.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_verbatim_dedup.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_verbatim_recall.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_webhook.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_whatsapp_importer.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_wiki_binding.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_wiki_explored_and_contradictions.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_wiki_freshness.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.0}/tests/test_wiki_similarity_multiscope.py +0 -0
- {memorymaster-3.13.0 → memorymaster-3.14.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.14.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
|
|
@@ -61,29 +61,23 @@ MemoryMaster prevents the #1 problem with agent memory: **drift, stale assumptio
|
|
|
61
61
|
|
|
62
62
|
## Architecture
|
|
63
63
|
|
|
64
|
+
MemoryMaster is layered around MCP/CLI entry points, the `MemoryService` facade, SQLite/Postgres
|
|
65
|
+
storage, optional Qdrant vector search, scheduled jobs, and the Obsidian wiki/vault layer. The
|
|
66
|
+
canonical ingest path is:
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
MCP/CLI -> sensitivity filter -> MemoryService.ingest -> store write -> FTS5 index
|
|
64
70
|
```
|
|
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
|
|
71
|
+
|
|
72
|
+
The query path is:
|
|
73
|
+
|
|
74
|
+
```text
|
|
75
|
+
query_memory -> MemoryService.query -> storage reads + optional Qdrant candidates -> ranked context
|
|
85
76
|
```
|
|
86
77
|
|
|
78
|
+
See [docs/architecture.md](docs/architecture.md) for the current module map, data-flow details,
|
|
79
|
+
recent PR status, and sensitivity-filter invariants.
|
|
80
|
+
|
|
87
81
|
## Key features
|
|
88
82
|
|
|
89
83
|
- **6-state lifecycle**: `candidate` → `confirmed` → `stale` → `superseded` → `conflicted` → `archived`
|
|
@@ -104,18 +98,20 @@ Full feature index lives in [`docs/handbook.md`](docs/handbook.md).
|
|
|
104
98
|
|
|
105
99
|
## Prerequisites
|
|
106
100
|
|
|
107
|
-
**Required**
|
|
101
|
+
**Required (the package won't function without these)**
|
|
108
102
|
|
|
109
103
|
- Python **3.10+** with `pip`
|
|
110
104
|
- Claude Code, Codex, or any MCP-compatible agent
|
|
105
|
+
- **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.
|
|
106
|
+
|
|
107
|
+
**Strongly recommended (you'll lose ~80% of the value without these)**
|
|
108
|
+
|
|
109
|
+
- **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.
|
|
110
|
+
- **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
111
|
|
|
112
|
-
**Optional**
|
|
112
|
+
**Optional (nice to have)**
|
|
113
113
|
|
|
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)
|
|
114
|
+
- **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
115
|
|
|
120
116
|
## Quick start
|
|
121
117
|
|
|
@@ -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
|
|
|
@@ -23,14 +23,14 @@ from memorymaster.models import (
|
|
|
23
23
|
validate_transition_event_type,
|
|
24
24
|
)
|
|
25
25
|
|
|
26
|
-
logger = logging.getLogger(__name__)
|
|
27
|
-
|
|
28
26
|
from memorymaster._storage_shared import (
|
|
29
27
|
EVENT_HASH_ALGO,
|
|
30
28
|
ConcurrentModificationError,
|
|
31
29
|
utc_now,
|
|
32
30
|
)
|
|
33
31
|
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
34
|
|
|
35
35
|
class _LifecycleMixin:
|
|
36
36
|
|
|
@@ -102,14 +102,64 @@ class _LifecycleMixin:
|
|
|
102
102
|
old_claim = self.get_claim(old_claim_id, include_citations=False)
|
|
103
103
|
if old_claim is None:
|
|
104
104
|
return
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
)
|
|
112
|
-
|
|
105
|
+
if old_claim.status == "superseded" or old_claim.replaced_by_claim_id is not None:
|
|
106
|
+
raise ConcurrentModificationError(
|
|
107
|
+
f"Claim {old_claim_id} was already superseded. Reload and retry."
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
now = utc_now()
|
|
111
|
+
with self.connect() as conn:
|
|
112
|
+
target = conn.execute(
|
|
113
|
+
"SELECT supersedes_claim_id FROM claims WHERE id = ?",
|
|
114
|
+
(new_claim_id,),
|
|
115
|
+
).fetchone()
|
|
116
|
+
if target is None:
|
|
117
|
+
raise ValueError(f"Replacement claim {new_claim_id} does not exist.")
|
|
118
|
+
if target["supersedes_claim_id"] not in {None, old_claim_id}:
|
|
119
|
+
raise ConcurrentModificationError(
|
|
120
|
+
f"Claim {new_claim_id} already supersedes another claim. Reload and retry."
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
cur = conn.execute(
|
|
124
|
+
"""
|
|
125
|
+
UPDATE claims
|
|
126
|
+
SET status = 'superseded', updated_at = ?, replaced_by_claim_id = ?,
|
|
127
|
+
version = version + 1, valid_until = COALESCE(?, valid_until)
|
|
128
|
+
WHERE id = ? AND version = ? AND status != 'superseded'
|
|
129
|
+
AND replaced_by_claim_id IS NULL
|
|
130
|
+
""",
|
|
131
|
+
(now, new_claim_id, now, old_claim_id, old_claim.version),
|
|
132
|
+
)
|
|
133
|
+
if cur.rowcount == 0:
|
|
134
|
+
raise ConcurrentModificationError(
|
|
135
|
+
f"Claim {old_claim_id} was modified by another writer. Reload and retry."
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
cur = conn.execute(
|
|
139
|
+
"""
|
|
140
|
+
UPDATE claims
|
|
141
|
+
SET supersedes_claim_id = ?, updated_at = ?
|
|
142
|
+
WHERE id = ? AND (supersedes_claim_id IS NULL OR supersedes_claim_id = ?)
|
|
143
|
+
""",
|
|
144
|
+
(old_claim_id, now, new_claim_id, old_claim_id),
|
|
145
|
+
)
|
|
146
|
+
if cur.rowcount == 0:
|
|
147
|
+
conn.rollback()
|
|
148
|
+
raise ConcurrentModificationError(
|
|
149
|
+
f"Claim {new_claim_id} was modified by another writer. Reload and retry."
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
self._insert_event_row(
|
|
153
|
+
conn,
|
|
154
|
+
claim_id=old_claim.id,
|
|
155
|
+
event_type="supersession",
|
|
156
|
+
from_status=old_claim.status,
|
|
157
|
+
to_status="superseded",
|
|
158
|
+
details=reason,
|
|
159
|
+
payload_json=json.dumps({"replaced_by_claim_id": new_claim_id}),
|
|
160
|
+
created_at=now,
|
|
161
|
+
)
|
|
162
|
+
conn.commit()
|
|
113
163
|
|
|
114
164
|
|
|
115
165
|
def delete_old_events(self, retain_days: int) -> int:
|
|
@@ -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)}
|
|
@@ -13,13 +13,29 @@ from memorymaster.cli_helpers import ( # noqa: F401 — re-export for backward
|
|
|
13
13
|
parse_citation,
|
|
14
14
|
parse_scope_allowlist,
|
|
15
15
|
)
|
|
16
|
-
from memorymaster.context_optimizer import OUTPUT_FORMATS
|
|
16
|
+
from memorymaster.context_optimizer import OUTPUT_FORMATS, PROVIDERS
|
|
17
17
|
from memorymaster.models import CLAIM_LINK_TYPES, CLAIM_STATUSES, VOLATILITY_LEVELS
|
|
18
18
|
from memorymaster.retrieval import RETRIEVAL_MODES
|
|
19
|
-
from memorymaster.service import MemoryService
|
|
19
|
+
from memorymaster.service import RETRIEVAL_PROFILES, MemoryService
|
|
20
20
|
|
|
21
21
|
# Import dispatch table — this also triggers the late dispatch additions for daily/dream/ghost
|
|
22
22
|
from memorymaster.cli_handlers_curation import COMMAND_HANDLERS
|
|
23
|
+
from memorymaster.cli_handlers_basic import (
|
|
24
|
+
_handle_decay,
|
|
25
|
+
_handle_entity_graph_export,
|
|
26
|
+
_handle_recompute_confidence_priors,
|
|
27
|
+
_handle_wiki_suggest_links,
|
|
28
|
+
handle_mcp_usage_report,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
COMMAND_HANDLERS["entity-graph-export"] = _handle_entity_graph_export
|
|
33
|
+
COMMAND_HANDLERS["recompute-confidence-priors"] = _handle_recompute_confidence_priors
|
|
34
|
+
COMMAND_HANDLERS["wiki-suggest-links"] = _handle_wiki_suggest_links
|
|
35
|
+
COMMAND_HANDLERS["decay"] = _handle_decay
|
|
36
|
+
COMMAND_HANDLERS["mcp-usage-report"] = (
|
|
37
|
+
lambda args, service, parser, effective_db: handle_mcp_usage_report(args, effective_db)
|
|
38
|
+
)
|
|
23
39
|
|
|
24
40
|
|
|
25
41
|
def build_parser() -> argparse.ArgumentParser:
|
|
@@ -147,6 +163,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
147
163
|
query.add_argument("--exclude-conflicted", action="store_true", help="Only return confirmed/stale")
|
|
148
164
|
query.add_argument("--include-candidates", action="store_true", help="Also search candidate (unverified) claims")
|
|
149
165
|
query.add_argument("--retrieval-mode", choices=list(RETRIEVAL_MODES), default="legacy", help="Retrieval mode (legacy SQL ordering or hybrid lexical/confidence/freshness ranking)")
|
|
166
|
+
query.add_argument("--profile", choices=list(RETRIEVAL_PROFILES), default=None, help="Per-query hybrid retrieval profile")
|
|
150
167
|
query.add_argument("--allow-sensitive", action="store_true", help="Include claims that look sensitive (default excludes them)")
|
|
151
168
|
query.add_argument("--scope-allowlist", default="", help="Comma-separated scopes to include (e.g. project,team_x)")
|
|
152
169
|
query.add_argument("--as-of", default="", help="Temporal query: show claims valid at this ISO timestamp")
|
|
@@ -156,11 +173,13 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
156
173
|
context.add_argument("text", help="Query text describing what context is needed")
|
|
157
174
|
context.add_argument("--budget", type=int, default=4000, help="Maximum token budget (default: 4000)")
|
|
158
175
|
context.add_argument("--format", dest="output_format", choices=list(OUTPUT_FORMATS), default="text", help="Output format: text (human-readable), xml (system prompt), json (structured)")
|
|
176
|
+
context.add_argument("--provider", choices=list(PROVIDERS), default=None, help="Provider-aware packing strategy")
|
|
159
177
|
context.add_argument("--limit", type=int, default=100, help="Max candidate claims to rank")
|
|
160
178
|
context.add_argument("--exclude-stale", action="store_true", help="Exclude stale claims")
|
|
161
179
|
context.add_argument("--exclude-conflicted", action="store_true", help="Exclude conflicted claims")
|
|
162
180
|
context.add_argument("--include-candidates", action="store_true", help="Include candidate (unverified) claims")
|
|
163
181
|
context.add_argument("--retrieval-mode", choices=list(RETRIEVAL_MODES), default="hybrid", help="Retrieval mode (default: hybrid)")
|
|
182
|
+
context.add_argument("--profile", choices=list(RETRIEVAL_PROFILES), default=None, help="Per-query hybrid retrieval profile")
|
|
164
183
|
context.add_argument("--allow-sensitive", action="store_true", help="Include sensitive claims")
|
|
165
184
|
context.add_argument("--scope-allowlist", default="", help="Comma-separated scopes to include")
|
|
166
185
|
|
|
@@ -180,6 +199,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
180
199
|
compact = sub.add_parser("compact", help="Archive stale/superseded/conflicted claims and trim old events")
|
|
181
200
|
compact.add_argument("--retain-days", type=int, default=30, help="Days before archiving stale/superseded/conflicted claims")
|
|
182
201
|
compact.add_argument("--event-retain-days", type=int, default=60, help="Days to retain event history")
|
|
202
|
+
compact.add_argument("--dry-run", action="store_true", help="Preview compaction without archiving claims, deleting events, or writing artifacts")
|
|
183
203
|
|
|
184
204
|
compact_sum = sub.add_parser("compact-summaries", help="Summarize groups of archived claims into higher-level summary claims using LLM")
|
|
185
205
|
compact_sum.add_argument("--provider", default="gemini", choices=["gemini", "openai", "anthropic", "ollama", "custom"], help="LLM provider (default: gemini)")
|
|
@@ -197,10 +217,24 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
197
217
|
dedup = sub.add_parser("dedup", help="Detect and merge duplicate claims using embedding similarity")
|
|
198
218
|
dedup.add_argument("--threshold", type=float, default=0.92, help="Cosine similarity threshold for duplicate detection (default: 0.92)")
|
|
199
219
|
dedup.add_argument("--min-text-overlap", type=float, default=0.3, help="Minimum word-level Jaccard overlap as secondary gate (default: 0.3)")
|
|
220
|
+
dedup.add_argument("--limit", type=int, default=None, help="Maximum claims to scan, oldest first")
|
|
221
|
+
dedup.add_argument("--scope", default=None, help="Only scan claims with this exact scope")
|
|
200
222
|
dedup.add_argument("--dry-run", action="store_true", help="Preview duplicates without archiving")
|
|
201
223
|
|
|
224
|
+
decay_cmd = sub.add_parser("decay", help="Apply confidence decay and mark low-confidence claims stale")
|
|
225
|
+
decay_cmd.add_argument("--limit", type=int, default=200, help="Maximum confirmed claims to process")
|
|
226
|
+
decay_cmd.add_argument("--stale-threshold", type=float, default=None, help="Confidence threshold below which claims become stale")
|
|
227
|
+
decay_cmd.add_argument("--dry-run", action="store_true", help="Preview confidence decay and stale transitions without writing")
|
|
228
|
+
|
|
202
229
|
sub.add_parser("recompute-tiers", help="Recompute memory tiers (core/working/peripheral) for all claims")
|
|
203
230
|
|
|
231
|
+
confidence_priors = sub.add_parser(
|
|
232
|
+
"recompute-confidence-priors",
|
|
233
|
+
help="Write recommended initial-confidence priors from recent validator events",
|
|
234
|
+
)
|
|
235
|
+
confidence_priors.add_argument("--window-days", type=int, default=90, help="Number of recent event days to read")
|
|
236
|
+
confidence_priors.add_argument("--output", required=True, help="JSON report path to write")
|
|
237
|
+
|
|
204
238
|
list_claims = sub.add_parser("list-claims", help="List claims")
|
|
205
239
|
list_claims.add_argument("--status", choices=list(CLAIM_STATUSES), help="Filter by claim status")
|
|
206
240
|
list_claims.add_argument("--limit", type=int, default=50, help="Maximum rows")
|
|
@@ -221,6 +255,10 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
221
255
|
export_metrics.add_argument("--out-prom", default="artifacts/metrics/metrics.prom", help="Output path for Prometheus text metrics")
|
|
222
256
|
export_metrics.add_argument("--out-json", default="artifacts/metrics/metrics_snapshot.json", help="Output path for structured metrics JSON snapshot")
|
|
223
257
|
|
|
258
|
+
mcp_usage = sub.add_parser("mcp-usage-report", help="Export MCP tool usage for a time window")
|
|
259
|
+
mcp_usage.add_argument("--since", default="7d", help="Window start: 7d, 30d, 1d, or ISO date")
|
|
260
|
+
mcp_usage.add_argument("--format", default="csv", help="Output format (default: csv)")
|
|
261
|
+
|
|
224
262
|
review_queue = sub.add_parser("review-queue", help="Build conflict/stale review queue")
|
|
225
263
|
review_queue.add_argument("--limit", type=int, default=100, help="Maximum claims scanned for queue")
|
|
226
264
|
review_queue.add_argument("--exclude-stale", action="store_true", help="Exclude stale claims from queue")
|
|
@@ -390,6 +428,12 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
390
428
|
wiki_freshness.add_argument("--below", type=float, default=None, help="Only show articles with freshness_score below this threshold (0-1)")
|
|
391
429
|
wiki_freshness.add_argument("--threshold-days", type=int, default=None, help="Only show articles older than N days since last absorb (alias for --below)")
|
|
392
430
|
|
|
431
|
+
wiki_suggest = sub.add_parser("wiki-suggest-links", help="Suggest wiki article links from paragraph entities")
|
|
432
|
+
wiki_suggest.add_argument("--text", required=True, help="Current paragraph text")
|
|
433
|
+
wiki_suggest.add_argument("--wiki-root", default="obsidian-vault/wiki", help="Wiki root to scan for article slugs")
|
|
434
|
+
wiki_suggest.add_argument("--limit", type=int, default=10, help="Maximum suggestions")
|
|
435
|
+
wiki_suggest.add_argument("--hops", type=int, default=2, help="Maximum entity graph hops")
|
|
436
|
+
|
|
393
437
|
mine_cmd = sub.add_parser("mine-transcript", help="Parse Claude Code transcripts into claims")
|
|
394
438
|
mine_cmd.add_argument("--input", required=True, help="JSONL transcript file or directory")
|
|
395
439
|
mine_cmd.add_argument("--scope", default="project", help="Scope for ingested claims")
|
|
@@ -405,6 +449,11 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
405
449
|
|
|
406
450
|
sub.add_parser("entity-stats", help="Show entity graph statistics")
|
|
407
451
|
|
|
452
|
+
entity_graph_export = sub.add_parser("entity-graph-export", help="Export entity graph relationships as DOT or GraphML")
|
|
453
|
+
entity_graph_export.add_argument("--format", choices=["dot", "graphml"], required=True, help="Graph output format")
|
|
454
|
+
entity_graph_export.add_argument("--output", required=True, help="Output file path")
|
|
455
|
+
entity_graph_export.add_argument("--scope", default=None, help="Only export graph data linked to this claim scope")
|
|
456
|
+
|
|
408
457
|
sub.add_parser("feedback-stats", help="Show feedback tracking and quality score statistics")
|
|
409
458
|
|
|
410
459
|
sub.add_parser("quality-scores", help="Recompute quality scores for all claims")
|
|
@@ -487,7 +536,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
487
536
|
entity_aliases_cmd.add_argument("entity_id", type=int, help="Entity ID")
|
|
488
537
|
entity_aliases_cmd.add_argument("--add", default="", help="Add this alias to the entity")
|
|
489
538
|
|
|
490
|
-
|
|
539
|
+
sub.add_parser("entity-backfill", help="Backfill entity_id on claims with subject but no entity")
|
|
491
540
|
|
|
492
541
|
return parser
|
|
493
542
|
|
|
@@ -499,7 +548,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
499
548
|
effective_db = _resolve_db_path(args)
|
|
500
549
|
|
|
501
550
|
# Commands that don't need MemoryService run first; service is lazy-created once for all others.
|
|
502
|
-
_NO_SERVICE_COMMANDS = {"stealth-status", "export-metrics", "wiki-freshness"}
|
|
551
|
+
_NO_SERVICE_COMMANDS = {"stealth-status", "export-metrics", "wiki-freshness", "mcp-usage-report"}
|
|
503
552
|
|
|
504
553
|
try:
|
|
505
554
|
handler = COMMAND_HANDLERS.get(args.command)
|