memorymaster 3.3.1__tar.gz → 3.4.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.3.1/memorymaster.egg-info → memorymaster-3.4.0}/PKG-INFO +161 -15
- {memorymaster-3.3.1 → memorymaster-3.4.0}/README.md +160 -14
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/__init__.py +1 -1
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/_storage_read.py +2 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/_storage_schema.py +13 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/cli.py +6 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/cli_handlers_curation.py +68 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/context_hook.py +5 -1
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/models.py +1 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/postgres_store.py +10 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/schema.sql +1 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/schema_postgres.sql +5 -1
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/storage.py +1 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/wiki_engine.py +27 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0/memorymaster.egg-info}/PKG-INFO +161 -15
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster.egg-info/SOURCES.txt +3 -1
- {memorymaster-3.3.1 → memorymaster-3.4.0}/pyproject.toml +1 -1
- memorymaster-3.4.0/scripts/llm_benchmark.py +264 -0
- memorymaster-3.4.0/tests/test_wiki_binding.py +182 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/LICENSE +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/benchmarks/longmemeval_runner.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/benchmarks/longmemeval_vector_runner.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/benchmarks/perf_smoke.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/__main__.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/_storage_lifecycle.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/_storage_shared.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/_storage_write_claims.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/access_control.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/auto_extractor.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/auto_resolver.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/claim_verifier.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/cli_handlers_basic.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/cli_helpers.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/config.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/config_templates/claude-md-append.md +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/config_templates/codex-agents-md-append.md +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/config_templates/hooks/memorymaster-auto-ingest.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/config_templates/hooks/memorymaster-classify.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/config_templates/hooks/memorymaster-precompact.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/config_templates/hooks/memorymaster-recall.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/config_templates/hooks/memorymaster-session-start.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/config_templates/hooks/memorymaster-steward-cycle.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/config_templates/hooks/memorymaster-validate-wiki.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/conflict_resolver.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/context_optimizer.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/daily_notes.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/dashboard.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/db_merge.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/dream_bridge.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/embeddings.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/entity_graph.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/entity_registry.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/feedback.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/jobs/__init__.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/jobs/compact_summaries.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/jobs/compactor.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/jobs/decay.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/jobs/dedup.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/jobs/deterministic.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/jobs/extractor.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/jobs/staleness.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/jobs/validator.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/lifecycle.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/llm_provider.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/llm_steward.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/mcp_server.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/metrics_exporter.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/operator.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/operator_queue.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/plugins.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/policy.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/qdrant_backend.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/qmd_bridge.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/query_classifier.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/retrieval.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/retry.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/review.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/rl_trainer.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/scheduler.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/schema.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/security.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/service.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/session_tracker.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/setup_hooks.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/skill_evolver.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/snapshot.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/steward.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/store_factory.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/transcript_miner.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/turn_schema.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/vault_bases.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/vault_curator.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/vault_exporter.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/vault_linter.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/vault_log.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/vault_query_capture.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/vault_synthesis.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/verbatim_store.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster/webhook.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster.egg-info/dependency_links.txt +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster.egg-info/entry_points.txt +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster.egg-info/requires.txt +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/memorymaster.egg-info/top_level.txt +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/alert_operator_metrics.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/autoresearch_daemon.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/claude_to_turns.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/codex_live_to_turns.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/compaction_edge_cases.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/compaction_trace_report.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/compaction_trace_validate.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/confusion_matrix_eval.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/conversation_importer.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/conversation_to_turns.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/e2e_operator.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/email_live_to_turns.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/eval_memorymaster.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/generate_drill_signoff.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/git_to_turns.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/github_live_to_turns.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/gitnexus_to_claims.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/ingest_planning_docs.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/jira_live_to_turns.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/messages_to_turns.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/operator_metrics.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/recurring_incident_drill.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/release_readiness.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/run_codex_autologger.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/run_incident_drill.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/scheduled_ingest.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/setup-hooks.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/slack_live_to_turns.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/tickets_to_turns.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/scripts/webhook_to_turns.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/setup.cfg +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/conftest.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_access_control.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_auto_extractor.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_auto_resolver.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_auto_validate.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_claim_links.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_claude_to_turns.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_cli_json_flag.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_cli_ready.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_cli_review_queue.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_cli_subcommands.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_compact_summaries.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_compaction_trace.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_config.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_conflict_resolver.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_confusion_matrix_eval.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_connection_retry.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_connectors.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_context_hook.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_context_optimizer.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_conversation_to_turns.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_dashboard.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_dedup.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_deterministic_predicates.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_embeddings_coverage.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_entity_graph.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_events_schema.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_feedback.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_fts5_search.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_handler_regressions.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_human_id.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_incident_drill_runner.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_integration_workflows.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_lifecycle.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_llm_steward_coverage.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_llm_steward_key_rotation.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_mcp_helpers.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_metrics_exporter.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_obsidian_mind_patterns.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_operator.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_operator_queue.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_perf_smoke_config.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_plugins.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_policy_coverage.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_postgres_parity.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_qdrant_backend.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_qmd_bridge.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_query_classifier.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_reliability_hardening.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_review.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_rl_trainer.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_scheduler.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_schema.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_security_access.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_security_patterns.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_service_coverage.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_session_tracker.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_snapshot.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_sqlite_core.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_staleness.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_stealth_mode.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_steward.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_steward_resolution_parity.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_store_factory.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_tenant_isolation.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_turn_schema.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_vault_exporter.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_vector_search.py +0 -0
- {memorymaster-3.3.1 → memorymaster-3.4.0}/tests/test_webhook.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memorymaster
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.4.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
|
|
@@ -42,7 +42,7 @@ Lifecycle-managed claims with citations, conflict detection, steward governance,
|
|
|
42
42
|
|
|
43
43
|
[](LICENSE)
|
|
44
44
|
[](https://www.python.org/downloads/)
|
|
45
|
-
[]()
|
|
46
46
|
[]()
|
|
47
47
|
[]()
|
|
48
48
|
|
|
@@ -55,7 +55,7 @@ MemoryMaster gives AI coding agents **persistent, verifiable memory** with a ful
|
|
|
55
55
|
| Metric | Count |
|
|
56
56
|
|--------|-------|
|
|
57
57
|
| Source modules | 35+ (20,000+ lines) |
|
|
58
|
-
| Tests |
|
|
58
|
+
| Tests | 1029 across 68 test modules |
|
|
59
59
|
| MCP tools | 22 |
|
|
60
60
|
| CLI commands | 64 |
|
|
61
61
|
| Import connectors | 10+ (Git, Slack, Jira, email, GitHub, conversations) |
|
|
@@ -131,7 +131,79 @@ MemoryMaster gives AI coding agents **persistent, verifiable memory** with a ful
|
|
|
131
131
|
| **Obsidian Bases** | Auto-generated `.base` dashboards (all-claims, gotchas, decisions, recent, needs-review) regenerated on every `wiki-absorb` |
|
|
132
132
|
| **7-Hook Stack** | Recall + Classify (UserPromptSubmit), Validate-Wiki (PostToolUse), Session-Start (SessionStart), Auto-Ingest (Stop), PreCompact — full memory lifecycle without manual intervention |
|
|
133
133
|
|
|
134
|
-
##
|
|
134
|
+
## Prerequisites
|
|
135
|
+
|
|
136
|
+
**Required**
|
|
137
|
+
- Python **3.10+** with `pip`
|
|
138
|
+
- Claude Code **or** Codex **or** any MCP-compatible agent (for the hooks + MCP integration)
|
|
139
|
+
|
|
140
|
+
**Optional but recommended**
|
|
141
|
+
- A free Gemini API key from [aistudio.google.com](https://aistudio.google.com) — powers the auto-ingest hook at ~zero cost. Fallbacks: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or a local Ollama.
|
|
142
|
+
- **Node.js 18+** — only if you want graphify (architecture maps) or GitNexus (code impact analysis)
|
|
143
|
+
- **Obsidian 1.6+** with the **Bases** core plugin — only if you want to browse the wiki visually
|
|
144
|
+
- **Docker** — only if you want Qdrant for hybrid vector search (SQLite FTS5 is the default and works out of the box)
|
|
145
|
+
|
|
146
|
+
## Install via Agent (One-Prompt) ⚡
|
|
147
|
+
|
|
148
|
+
**The fastest way to install MemoryMaster end-to-end is to let an AI agent do it.** Open Claude Code, Codex, Cursor, or any agent with shell access in the project directory you want to instrument, and paste the prompt below. The agent handles pip install, MCP wiring, all 7 hooks, steward cron, LLM provider selection, and verification — you only approve steps and provide an API key when asked.
|
|
149
|
+
|
|
150
|
+
<details>
|
|
151
|
+
<summary><b>📋 Click to copy the one-prompt install</b></summary>
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
Install MemoryMaster end-to-end in this directory. Execute each step and verify it before moving to the next. Stop and ask me if any step needs a secret, credential, or destructive action.
|
|
155
|
+
|
|
156
|
+
Step 1 — Prerequisites
|
|
157
|
+
• Run `python --version` and confirm 3.10+. If lower, stop and ask me to upgrade.
|
|
158
|
+
• Run `python -m pip --version` to confirm pip is available.
|
|
159
|
+
|
|
160
|
+
Step 2 — Install the package
|
|
161
|
+
• `pip install "memorymaster[mcp,security]"`
|
|
162
|
+
• Confirm `python -c "import memorymaster; print(memorymaster.__version__)"` reports 3.3.1 or higher.
|
|
163
|
+
|
|
164
|
+
Step 3 — Initialize the project DB
|
|
165
|
+
• `memorymaster --db memorymaster.db init-db`
|
|
166
|
+
• Confirm the file exists and is non-empty.
|
|
167
|
+
|
|
168
|
+
Step 4 — Run the interactive setup
|
|
169
|
+
• `memorymaster-setup`
|
|
170
|
+
• This installs 7 Claude Code hooks (recall, classify, validate-wiki, session-start, auto-ingest, precompact, steward-cron), wires the MCP server into ~/.claude.json and ~/.codex/, schedules the steward cron (every 6h), and appends a MemoryMaster section to CLAUDE.md / AGENTS.md in the current project.
|
|
171
|
+
|
|
172
|
+
Step 5 — LLM provider for the auto-ingest hook
|
|
173
|
+
• If any of GEMINI_API_KEY / ANTHROPIC_API_KEY / OPENAI_API_KEY is already set, report which one and continue.
|
|
174
|
+
• Otherwise, tell me the cheapest option is a free Gemini Flash Lite key from aistudio.google.com and stop until I paste one. Never invent or reuse keys.
|
|
175
|
+
|
|
176
|
+
Step 6 — Verify the MCP server
|
|
177
|
+
• Tell me to fully restart Claude Code / Codex so the new MCP config loads, then wait for me to confirm.
|
|
178
|
+
• After restart, call mcp__memorymaster__query_memory with text "install smoke test". Expect an empty result set (not an error).
|
|
179
|
+
• Call mcp__memorymaster__list_claims with limit 5. Expect an empty or short list.
|
|
180
|
+
|
|
181
|
+
Step 7 — Optional: graphify (architecture map, saves ~70x tokens on codebase exploration)
|
|
182
|
+
• `npm install -g graphify`
|
|
183
|
+
• `graphify claude install` — installs the global Claude hook
|
|
184
|
+
• `graphify hook install` — per-project post-commit hook
|
|
185
|
+
• `graphify analyze` — index this project (first run may take a few minutes)
|
|
186
|
+
|
|
187
|
+
Step 8 — Optional: GitNexus (symbol-level impact analysis before edits)
|
|
188
|
+
• `npx gitnexus analyze` in this project
|
|
189
|
+
|
|
190
|
+
Step 9 — Report
|
|
191
|
+
Print a table with:
|
|
192
|
+
• Component → status (✓ installed / — skipped / ✗ failed)
|
|
193
|
+
• Env vars still required (if any)
|
|
194
|
+
• 3 smoke-test commands I can run myself
|
|
195
|
+
• Absolute paths to: memorymaster.db, modified ~/.claude.json, modified CLAUDE.md
|
|
196
|
+
|
|
197
|
+
Hard constraints:
|
|
198
|
+
• Do not create new accounts. Do not set credentials for me.
|
|
199
|
+
• Do not edit files outside: this project, ~/.claude/, ~/.codex/, ~/.memorymaster/.
|
|
200
|
+
• If any step fails, report the exact error and stop. Do not retry silently.
|
|
201
|
+
• Do not run `pip install --upgrade pip` or touch system Python.
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
</details>
|
|
205
|
+
|
|
206
|
+
## Quick Start (Manual)
|
|
135
207
|
|
|
136
208
|
```bash
|
|
137
209
|
# Install
|
|
@@ -616,16 +688,19 @@ python -m memorymaster --db memorymaster.db wiki-absorb --output obsidian-vault
|
|
|
616
688
|
- **Python 3.10+** with stdlib `sqlite3` (everything is stdlib — no extra deps)
|
|
617
689
|
- **Obsidian 1.6+** with **Bases core plugin enabled** (for `.base` dashboards). The plugin ships with Obsidian — just enable it under Settings → Core plugins.
|
|
618
690
|
|
|
619
|
-
###
|
|
691
|
+
### Recommended Companion Stack
|
|
620
692
|
|
|
621
|
-
|
|
693
|
+
MemoryMaster is the memory layer, but it's designed to work alongside a small set of tools that each specialise in one layer of agent intelligence. The **Intelligence-First Rule** — check the cheapest cached layer before exploring raw files — is the reason this stack saves 70× tokens on typical architectural questions.
|
|
622
694
|
|
|
623
|
-
|
|
|
624
|
-
|
|
625
|
-
| **
|
|
626
|
-
| **
|
|
627
|
-
|
|
|
628
|
-
| **
|
|
695
|
+
| Priority | Tool | What it adds | How to install |
|
|
696
|
+
|----------|------|--------------|----------------|
|
|
697
|
+
| 1 | **graphify** | Pre-computed architecture map (god nodes, communities, surprising connections) in `graphify-out/GRAPH_REPORT.md`. The cheapest layer — answers architectural questions without reading a single source file. | `npm install -g graphify` → `graphify claude install` → `graphify hook install` → `graphify analyze` |
|
|
698
|
+
| 2 | **memorymaster** ← you are here | 22 MCP tools (`ingest_claim`, `query_memory`, `run_cycle`, `find_related_claims`, etc.), 7 hooks, wiki, steward | `memorymaster-setup` (interactive; or `python scripts/setup-hooks.py` from clone) |
|
|
699
|
+
| 3 | **GitNexus** | Symbol-level impact analysis — "what breaks if I change function X" via a pre-built call graph | `npx gitnexus analyze`. See [GitNexus Integration](#gitnexus-integration-code-intelligence). |
|
|
700
|
+
| 4 | **Serena** | LSP-powered symbol-level read/edit — read or rewrite one function without opening the whole file | Global MCP config, see [oraios/serena](https://github.com/oraios/serena) |
|
|
701
|
+
| 5 | **context7** | Live library docs — never guess an API signature | Already a first-party Claude Code MCP; nothing to install |
|
|
702
|
+
| opt | **Obsidian CLI** | Vault-aware search from the terminal | `npm install -g obsidian-cli` (requires Obsidian 1.12+) |
|
|
703
|
+
| opt | **Qdrant** | External vector search backend for semantic recall (SQLite FTS5 is the default) | `docker run -p 6333:6333 qdrant/qdrant` |
|
|
629
704
|
|
|
630
705
|
### Installation
|
|
631
706
|
|
|
@@ -642,11 +717,40 @@ python scripts/setup-hooks.py # 3-line shim calling memorymaster.setup_hooks:
|
|
|
642
717
|
|
|
643
718
|
# Either way, the installer copies hooks from memorymaster/config_templates/hooks/
|
|
644
719
|
# to ~/.claude/hooks/ and registers them in ~/.claude/settings.json automatically.
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
### Verify Installation
|
|
645
723
|
|
|
646
|
-
|
|
647
|
-
|
|
724
|
+
After install (either path — pip or agent-driven), run these three commands to confirm everything is wired:
|
|
725
|
+
|
|
726
|
+
```bash
|
|
727
|
+
# 1. Package + version
|
|
728
|
+
python -c "import memorymaster; print('memorymaster', memorymaster.__version__)"
|
|
729
|
+
# expect: memorymaster 3.3.1 (or higher)
|
|
730
|
+
|
|
731
|
+
# 2. DB + CLI
|
|
732
|
+
python -m memorymaster --db memorymaster.db query "install smoke test"
|
|
733
|
+
# expect: empty result set, no traceback
|
|
734
|
+
|
|
735
|
+
# 3. MCP server reachable from an agent
|
|
736
|
+
# In Claude Code or Codex (after restarting the client so MCP reloads):
|
|
737
|
+
# mcp__memorymaster__list_claims(limit=5)
|
|
738
|
+
# expect: empty list or a short list of pre-existing claims, no error
|
|
648
739
|
```
|
|
649
740
|
|
|
741
|
+
If all three pass, the hooks are in `~/.claude/hooks/`, the MCP server is registered in `~/.claude.json`, and the steward cron is scheduled. The next message you send in that session will trigger the recall hook, and the first time Claude stops, the auto-ingest hook will capture learnings.
|
|
742
|
+
|
|
743
|
+
### Troubleshooting
|
|
744
|
+
|
|
745
|
+
| Symptom | Cause | Fix |
|
|
746
|
+
|---------|-------|-----|
|
|
747
|
+
| MCP tools don't appear in agent | Client didn't reload config | Fully quit and reopen Claude Code / Codex — stdio MCP servers only load at startup |
|
|
748
|
+
| Claims land under `project:<name>:<hash>` scope | Running MCP is pre-v3.3.1 | Restart the agent so the new `_project_scope()` loads. See [New in v3.3](#new-in-v33--entity-registry--typed-relationships--scope-fix). |
|
|
749
|
+
| Auto-ingest hook silent, no claims growing | No LLM provider env var set | Set `GEMINI_API_KEY` (free) or `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` |
|
|
750
|
+
| `wiki-absorb` says "no claims to absorb" | Scope mismatch between cwd and claims | `memorymaster --db memorymaster.db query "test"` — check `scope` column on results; then re-run absorb with `--scope project:<name>` |
|
|
751
|
+
| Steward cron not running | Windows doesn't have cron | `memorymaster-setup` installs a Task Scheduler entry on Windows, a `launchd` plist on macOS, and a crontab line on Linux — check your platform's scheduler UI |
|
|
752
|
+
| `ruff check` fails after install | You're on the dev path and haven't pinned ruff | `pip install -e ".[dev]"` — dev extras include pinned lint tools |
|
|
753
|
+
|
|
650
754
|
### Tests
|
|
651
755
|
|
|
652
756
|
32 E2E tests in `tests/test_obsidian_mind_patterns.py` validate all 5 components:
|
|
@@ -656,6 +760,48 @@ python -m pytest tests/test_obsidian_mind_patterns.py -v
|
|
|
656
760
|
# 32 passed
|
|
657
761
|
```
|
|
658
762
|
|
|
763
|
+
## New in v3.3 — Entity Registry + Typed Relationships + Scope Fix
|
|
764
|
+
|
|
765
|
+
v3.3 adds three GBrain-inspired patterns and ships a critical data-layer fix surfaced by a 24h audit.
|
|
766
|
+
|
|
767
|
+
### Entity Registry
|
|
768
|
+
|
|
769
|
+
`memorymaster/entity_registry.py` introduces canonical entities with alias resolution. When you ingest a claim about `qdrant`, `Qdrant`, or `QDRANT vector DB`, they all resolve to the same entity via `normalize_alias()`. New tables:
|
|
770
|
+
|
|
771
|
+
| Table | Purpose |
|
|
772
|
+
|-------|---------|
|
|
773
|
+
| `entities` | Canonical names with `entity_type`, `description`, `aliases_count` |
|
|
774
|
+
| `entity_aliases` | Many-to-one alias → entity mapping, normalized |
|
|
775
|
+
|
|
776
|
+
`service.ingest()` now auto-assigns `entity_id` on every claim. A one-time backfill mapped 684 existing subjects into 312 entities in ~23 ms. Use `mcp__memorymaster__entity_stats` to see the current graph, or `find_related_claims` to walk relationships through the entity.
|
|
777
|
+
|
|
778
|
+
### RESOLVER.md — MECE Decision Tree
|
|
779
|
+
|
|
780
|
+
`obsidian-vault/wiki/RESOLVER.md` is an auto-generated decision tree that tells the wiki engine *which* article a new claim belongs to. 10 canonical types (decision, gotcha, constraint, architecture, environment, reference, bug-root-cause, fact, process, glossary) with disambiguation rules and scope routing. It's **M**utually **E**xclusive, **C**ollectively **E**xhaustive — no claim falls through the cracks, no claim lands in two articles.
|
|
781
|
+
|
|
782
|
+
### Typed Relationships (5 → 14)
|
|
783
|
+
|
|
784
|
+
`CLAIM_LINK_TYPES` grew from 5 generic (`relates_to`, `supersedes`, `derived_from`, `contradicts`, `supports`) to 14. New domain-specific link types enable graph traversal that actually answers questions:
|
|
785
|
+
|
|
786
|
+
```
|
|
787
|
+
implements configures depends_on deployed_on owned_by
|
|
788
|
+
tested_by documents blocks enables
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
New `traverse_relationships()` BFS method on the storage read layer: filter by `link_types`, `max_depth`, and `direction` (outgoing/incoming/both). Schema migration preserved existing links via `rename → create → copy → drop`.
|
|
792
|
+
|
|
793
|
+
### Scope Fix + claim_type Normalization (v3.3.1)
|
|
794
|
+
|
|
795
|
+
A 24-hour audit surfaced three data-quality bugs, all fixed in v3.3.1:
|
|
796
|
+
|
|
797
|
+
| Bug | Impact | Fix |
|
|
798
|
+
|-----|--------|-----|
|
|
799
|
+
| `_project_scope()` appended a `sha1(workspace)[:8]` suffix unconditionally | 341 claims fragmented across 6 scopes for the same project | Scope is now canonical `project:<slug>` by default. Set `MEMORYMASTER_SCOPE_DISAMBIGUATE=1` only if you genuinely have two projects with the same directory name. |
|
|
800
|
+
| Classify hook emits ALL-CAPS labels (`DECISION`, `GOTCHA`) that flowed straight into `claim_type` | 30 claims with uppercase types didn't match lowercase queries | `service.ingest()` now lowercases `claim_type` before write. |
|
|
801
|
+
| Auto-resolver for `conflicted` claims skipped orphan conflicts (no active sibling) | 6 orphan conflicts accumulated indefinitely | Manual cleanup: orphans are marked `superseded` with `replaced_by_claim_id` pointing to the confirmed sibling. |
|
|
802
|
+
|
|
803
|
+
Migration was applied in-place on existing databases. The v3.3.1 release notes include the full SQL. **After upgrading, restart Claude Code / Codex so the running MCP server picks up the new `_project_scope()` — otherwise same-session ingests still land under the old hashed scope.**
|
|
804
|
+
|
|
659
805
|
## Security
|
|
660
806
|
|
|
661
807
|
- **Auto-redaction**: JWT, GitHub tokens, Bearer, AWS keys, SSH keys, and custom patterns scrubbed at ingest
|
|
@@ -704,7 +850,7 @@ Key config groups:
|
|
|
704
850
|
# Install with all dev dependencies
|
|
705
851
|
pip install -e ".[dev,mcp,security,embeddings,qdrant]"
|
|
706
852
|
|
|
707
|
-
# Run tests (
|
|
853
|
+
# Run tests (1029 tests)
|
|
708
854
|
pytest tests/ -q
|
|
709
855
|
|
|
710
856
|
# Lint and format
|
|
@@ -6,7 +6,7 @@ Lifecycle-managed claims with citations, conflict detection, steward governance,
|
|
|
6
6
|
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
[](https://www.python.org/downloads/)
|
|
9
|
-
[]()
|
|
10
10
|
[]()
|
|
11
11
|
[]()
|
|
12
12
|
|
|
@@ -19,7 +19,7 @@ MemoryMaster gives AI coding agents **persistent, verifiable memory** with a ful
|
|
|
19
19
|
| Metric | Count |
|
|
20
20
|
|--------|-------|
|
|
21
21
|
| Source modules | 35+ (20,000+ lines) |
|
|
22
|
-
| Tests |
|
|
22
|
+
| Tests | 1029 across 68 test modules |
|
|
23
23
|
| MCP tools | 22 |
|
|
24
24
|
| CLI commands | 64 |
|
|
25
25
|
| Import connectors | 10+ (Git, Slack, Jira, email, GitHub, conversations) |
|
|
@@ -95,7 +95,79 @@ MemoryMaster gives AI coding agents **persistent, verifiable memory** with a ful
|
|
|
95
95
|
| **Obsidian Bases** | Auto-generated `.base` dashboards (all-claims, gotchas, decisions, recent, needs-review) regenerated on every `wiki-absorb` |
|
|
96
96
|
| **7-Hook Stack** | Recall + Classify (UserPromptSubmit), Validate-Wiki (PostToolUse), Session-Start (SessionStart), Auto-Ingest (Stop), PreCompact — full memory lifecycle without manual intervention |
|
|
97
97
|
|
|
98
|
-
##
|
|
98
|
+
## Prerequisites
|
|
99
|
+
|
|
100
|
+
**Required**
|
|
101
|
+
- Python **3.10+** with `pip`
|
|
102
|
+
- Claude Code **or** Codex **or** any MCP-compatible agent (for the hooks + MCP integration)
|
|
103
|
+
|
|
104
|
+
**Optional but recommended**
|
|
105
|
+
- A free Gemini API key from [aistudio.google.com](https://aistudio.google.com) — powers the auto-ingest hook at ~zero cost. Fallbacks: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or a local Ollama.
|
|
106
|
+
- **Node.js 18+** — only if you want graphify (architecture maps) or GitNexus (code impact analysis)
|
|
107
|
+
- **Obsidian 1.6+** with the **Bases** core plugin — only if you want to browse the wiki visually
|
|
108
|
+
- **Docker** — only if you want Qdrant for hybrid vector search (SQLite FTS5 is the default and works out of the box)
|
|
109
|
+
|
|
110
|
+
## Install via Agent (One-Prompt) ⚡
|
|
111
|
+
|
|
112
|
+
**The fastest way to install MemoryMaster end-to-end is to let an AI agent do it.** Open Claude Code, Codex, Cursor, or any agent with shell access in the project directory you want to instrument, and paste the prompt below. The agent handles pip install, MCP wiring, all 7 hooks, steward cron, LLM provider selection, and verification — you only approve steps and provide an API key when asked.
|
|
113
|
+
|
|
114
|
+
<details>
|
|
115
|
+
<summary><b>📋 Click to copy the one-prompt install</b></summary>
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
Install MemoryMaster end-to-end in this directory. Execute each step and verify it before moving to the next. Stop and ask me if any step needs a secret, credential, or destructive action.
|
|
119
|
+
|
|
120
|
+
Step 1 — Prerequisites
|
|
121
|
+
• Run `python --version` and confirm 3.10+. If lower, stop and ask me to upgrade.
|
|
122
|
+
• Run `python -m pip --version` to confirm pip is available.
|
|
123
|
+
|
|
124
|
+
Step 2 — Install the package
|
|
125
|
+
• `pip install "memorymaster[mcp,security]"`
|
|
126
|
+
• Confirm `python -c "import memorymaster; print(memorymaster.__version__)"` reports 3.3.1 or higher.
|
|
127
|
+
|
|
128
|
+
Step 3 — Initialize the project DB
|
|
129
|
+
• `memorymaster --db memorymaster.db init-db`
|
|
130
|
+
• Confirm the file exists and is non-empty.
|
|
131
|
+
|
|
132
|
+
Step 4 — Run the interactive setup
|
|
133
|
+
• `memorymaster-setup`
|
|
134
|
+
• This installs 7 Claude Code hooks (recall, classify, validate-wiki, session-start, auto-ingest, precompact, steward-cron), wires the MCP server into ~/.claude.json and ~/.codex/, schedules the steward cron (every 6h), and appends a MemoryMaster section to CLAUDE.md / AGENTS.md in the current project.
|
|
135
|
+
|
|
136
|
+
Step 5 — LLM provider for the auto-ingest hook
|
|
137
|
+
• If any of GEMINI_API_KEY / ANTHROPIC_API_KEY / OPENAI_API_KEY is already set, report which one and continue.
|
|
138
|
+
• Otherwise, tell me the cheapest option is a free Gemini Flash Lite key from aistudio.google.com and stop until I paste one. Never invent or reuse keys.
|
|
139
|
+
|
|
140
|
+
Step 6 — Verify the MCP server
|
|
141
|
+
• Tell me to fully restart Claude Code / Codex so the new MCP config loads, then wait for me to confirm.
|
|
142
|
+
• After restart, call mcp__memorymaster__query_memory with text "install smoke test". Expect an empty result set (not an error).
|
|
143
|
+
• Call mcp__memorymaster__list_claims with limit 5. Expect an empty or short list.
|
|
144
|
+
|
|
145
|
+
Step 7 — Optional: graphify (architecture map, saves ~70x tokens on codebase exploration)
|
|
146
|
+
• `npm install -g graphify`
|
|
147
|
+
• `graphify claude install` — installs the global Claude hook
|
|
148
|
+
• `graphify hook install` — per-project post-commit hook
|
|
149
|
+
• `graphify analyze` — index this project (first run may take a few minutes)
|
|
150
|
+
|
|
151
|
+
Step 8 — Optional: GitNexus (symbol-level impact analysis before edits)
|
|
152
|
+
• `npx gitnexus analyze` in this project
|
|
153
|
+
|
|
154
|
+
Step 9 — Report
|
|
155
|
+
Print a table with:
|
|
156
|
+
• Component → status (✓ installed / — skipped / ✗ failed)
|
|
157
|
+
• Env vars still required (if any)
|
|
158
|
+
• 3 smoke-test commands I can run myself
|
|
159
|
+
• Absolute paths to: memorymaster.db, modified ~/.claude.json, modified CLAUDE.md
|
|
160
|
+
|
|
161
|
+
Hard constraints:
|
|
162
|
+
• Do not create new accounts. Do not set credentials for me.
|
|
163
|
+
• Do not edit files outside: this project, ~/.claude/, ~/.codex/, ~/.memorymaster/.
|
|
164
|
+
• If any step fails, report the exact error and stop. Do not retry silently.
|
|
165
|
+
• Do not run `pip install --upgrade pip` or touch system Python.
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
</details>
|
|
169
|
+
|
|
170
|
+
## Quick Start (Manual)
|
|
99
171
|
|
|
100
172
|
```bash
|
|
101
173
|
# Install
|
|
@@ -580,16 +652,19 @@ python -m memorymaster --db memorymaster.db wiki-absorb --output obsidian-vault
|
|
|
580
652
|
- **Python 3.10+** with stdlib `sqlite3` (everything is stdlib — no extra deps)
|
|
581
653
|
- **Obsidian 1.6+** with **Bases core plugin enabled** (for `.base` dashboards). The plugin ships with Obsidian — just enable it under Settings → Core plugins.
|
|
582
654
|
|
|
583
|
-
###
|
|
655
|
+
### Recommended Companion Stack
|
|
584
656
|
|
|
585
|
-
|
|
657
|
+
MemoryMaster is the memory layer, but it's designed to work alongside a small set of tools that each specialise in one layer of agent intelligence. The **Intelligence-First Rule** — check the cheapest cached layer before exploring raw files — is the reason this stack saves 70× tokens on typical architectural questions.
|
|
586
658
|
|
|
587
|
-
|
|
|
588
|
-
|
|
589
|
-
| **
|
|
590
|
-
| **
|
|
591
|
-
|
|
|
592
|
-
| **
|
|
659
|
+
| Priority | Tool | What it adds | How to install |
|
|
660
|
+
|----------|------|--------------|----------------|
|
|
661
|
+
| 1 | **graphify** | Pre-computed architecture map (god nodes, communities, surprising connections) in `graphify-out/GRAPH_REPORT.md`. The cheapest layer — answers architectural questions without reading a single source file. | `npm install -g graphify` → `graphify claude install` → `graphify hook install` → `graphify analyze` |
|
|
662
|
+
| 2 | **memorymaster** ← you are here | 22 MCP tools (`ingest_claim`, `query_memory`, `run_cycle`, `find_related_claims`, etc.), 7 hooks, wiki, steward | `memorymaster-setup` (interactive; or `python scripts/setup-hooks.py` from clone) |
|
|
663
|
+
| 3 | **GitNexus** | Symbol-level impact analysis — "what breaks if I change function X" via a pre-built call graph | `npx gitnexus analyze`. See [GitNexus Integration](#gitnexus-integration-code-intelligence). |
|
|
664
|
+
| 4 | **Serena** | LSP-powered symbol-level read/edit — read or rewrite one function without opening the whole file | Global MCP config, see [oraios/serena](https://github.com/oraios/serena) |
|
|
665
|
+
| 5 | **context7** | Live library docs — never guess an API signature | Already a first-party Claude Code MCP; nothing to install |
|
|
666
|
+
| opt | **Obsidian CLI** | Vault-aware search from the terminal | `npm install -g obsidian-cli` (requires Obsidian 1.12+) |
|
|
667
|
+
| opt | **Qdrant** | External vector search backend for semantic recall (SQLite FTS5 is the default) | `docker run -p 6333:6333 qdrant/qdrant` |
|
|
593
668
|
|
|
594
669
|
### Installation
|
|
595
670
|
|
|
@@ -606,11 +681,40 @@ python scripts/setup-hooks.py # 3-line shim calling memorymaster.setup_hooks:
|
|
|
606
681
|
|
|
607
682
|
# Either way, the installer copies hooks from memorymaster/config_templates/hooks/
|
|
608
683
|
# to ~/.claude/hooks/ and registers them in ~/.claude/settings.json automatically.
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
### Verify Installation
|
|
609
687
|
|
|
610
|
-
|
|
611
|
-
|
|
688
|
+
After install (either path — pip or agent-driven), run these three commands to confirm everything is wired:
|
|
689
|
+
|
|
690
|
+
```bash
|
|
691
|
+
# 1. Package + version
|
|
692
|
+
python -c "import memorymaster; print('memorymaster', memorymaster.__version__)"
|
|
693
|
+
# expect: memorymaster 3.3.1 (or higher)
|
|
694
|
+
|
|
695
|
+
# 2. DB + CLI
|
|
696
|
+
python -m memorymaster --db memorymaster.db query "install smoke test"
|
|
697
|
+
# expect: empty result set, no traceback
|
|
698
|
+
|
|
699
|
+
# 3. MCP server reachable from an agent
|
|
700
|
+
# In Claude Code or Codex (after restarting the client so MCP reloads):
|
|
701
|
+
# mcp__memorymaster__list_claims(limit=5)
|
|
702
|
+
# expect: empty list or a short list of pre-existing claims, no error
|
|
612
703
|
```
|
|
613
704
|
|
|
705
|
+
If all three pass, the hooks are in `~/.claude/hooks/`, the MCP server is registered in `~/.claude.json`, and the steward cron is scheduled. The next message you send in that session will trigger the recall hook, and the first time Claude stops, the auto-ingest hook will capture learnings.
|
|
706
|
+
|
|
707
|
+
### Troubleshooting
|
|
708
|
+
|
|
709
|
+
| Symptom | Cause | Fix |
|
|
710
|
+
|---------|-------|-----|
|
|
711
|
+
| MCP tools don't appear in agent | Client didn't reload config | Fully quit and reopen Claude Code / Codex — stdio MCP servers only load at startup |
|
|
712
|
+
| Claims land under `project:<name>:<hash>` scope | Running MCP is pre-v3.3.1 | Restart the agent so the new `_project_scope()` loads. See [New in v3.3](#new-in-v33--entity-registry--typed-relationships--scope-fix). |
|
|
713
|
+
| Auto-ingest hook silent, no claims growing | No LLM provider env var set | Set `GEMINI_API_KEY` (free) or `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` |
|
|
714
|
+
| `wiki-absorb` says "no claims to absorb" | Scope mismatch between cwd and claims | `memorymaster --db memorymaster.db query "test"` — check `scope` column on results; then re-run absorb with `--scope project:<name>` |
|
|
715
|
+
| Steward cron not running | Windows doesn't have cron | `memorymaster-setup` installs a Task Scheduler entry on Windows, a `launchd` plist on macOS, and a crontab line on Linux — check your platform's scheduler UI |
|
|
716
|
+
| `ruff check` fails after install | You're on the dev path and haven't pinned ruff | `pip install -e ".[dev]"` — dev extras include pinned lint tools |
|
|
717
|
+
|
|
614
718
|
### Tests
|
|
615
719
|
|
|
616
720
|
32 E2E tests in `tests/test_obsidian_mind_patterns.py` validate all 5 components:
|
|
@@ -620,6 +724,48 @@ python -m pytest tests/test_obsidian_mind_patterns.py -v
|
|
|
620
724
|
# 32 passed
|
|
621
725
|
```
|
|
622
726
|
|
|
727
|
+
## New in v3.3 — Entity Registry + Typed Relationships + Scope Fix
|
|
728
|
+
|
|
729
|
+
v3.3 adds three GBrain-inspired patterns and ships a critical data-layer fix surfaced by a 24h audit.
|
|
730
|
+
|
|
731
|
+
### Entity Registry
|
|
732
|
+
|
|
733
|
+
`memorymaster/entity_registry.py` introduces canonical entities with alias resolution. When you ingest a claim about `qdrant`, `Qdrant`, or `QDRANT vector DB`, they all resolve to the same entity via `normalize_alias()`. New tables:
|
|
734
|
+
|
|
735
|
+
| Table | Purpose |
|
|
736
|
+
|-------|---------|
|
|
737
|
+
| `entities` | Canonical names with `entity_type`, `description`, `aliases_count` |
|
|
738
|
+
| `entity_aliases` | Many-to-one alias → entity mapping, normalized |
|
|
739
|
+
|
|
740
|
+
`service.ingest()` now auto-assigns `entity_id` on every claim. A one-time backfill mapped 684 existing subjects into 312 entities in ~23 ms. Use `mcp__memorymaster__entity_stats` to see the current graph, or `find_related_claims` to walk relationships through the entity.
|
|
741
|
+
|
|
742
|
+
### RESOLVER.md — MECE Decision Tree
|
|
743
|
+
|
|
744
|
+
`obsidian-vault/wiki/RESOLVER.md` is an auto-generated decision tree that tells the wiki engine *which* article a new claim belongs to. 10 canonical types (decision, gotcha, constraint, architecture, environment, reference, bug-root-cause, fact, process, glossary) with disambiguation rules and scope routing. It's **M**utually **E**xclusive, **C**ollectively **E**xhaustive — no claim falls through the cracks, no claim lands in two articles.
|
|
745
|
+
|
|
746
|
+
### Typed Relationships (5 → 14)
|
|
747
|
+
|
|
748
|
+
`CLAIM_LINK_TYPES` grew from 5 generic (`relates_to`, `supersedes`, `derived_from`, `contradicts`, `supports`) to 14. New domain-specific link types enable graph traversal that actually answers questions:
|
|
749
|
+
|
|
750
|
+
```
|
|
751
|
+
implements configures depends_on deployed_on owned_by
|
|
752
|
+
tested_by documents blocks enables
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
New `traverse_relationships()` BFS method on the storage read layer: filter by `link_types`, `max_depth`, and `direction` (outgoing/incoming/both). Schema migration preserved existing links via `rename → create → copy → drop`.
|
|
756
|
+
|
|
757
|
+
### Scope Fix + claim_type Normalization (v3.3.1)
|
|
758
|
+
|
|
759
|
+
A 24-hour audit surfaced three data-quality bugs, all fixed in v3.3.1:
|
|
760
|
+
|
|
761
|
+
| Bug | Impact | Fix |
|
|
762
|
+
|-----|--------|-----|
|
|
763
|
+
| `_project_scope()` appended a `sha1(workspace)[:8]` suffix unconditionally | 341 claims fragmented across 6 scopes for the same project | Scope is now canonical `project:<slug>` by default. Set `MEMORYMASTER_SCOPE_DISAMBIGUATE=1` only if you genuinely have two projects with the same directory name. |
|
|
764
|
+
| Classify hook emits ALL-CAPS labels (`DECISION`, `GOTCHA`) that flowed straight into `claim_type` | 30 claims with uppercase types didn't match lowercase queries | `service.ingest()` now lowercases `claim_type` before write. |
|
|
765
|
+
| Auto-resolver for `conflicted` claims skipped orphan conflicts (no active sibling) | 6 orphan conflicts accumulated indefinitely | Manual cleanup: orphans are marked `superseded` with `replaced_by_claim_id` pointing to the confirmed sibling. |
|
|
766
|
+
|
|
767
|
+
Migration was applied in-place on existing databases. The v3.3.1 release notes include the full SQL. **After upgrading, restart Claude Code / Codex so the running MCP server picks up the new `_project_scope()` — otherwise same-session ingests still land under the old hashed scope.**
|
|
768
|
+
|
|
623
769
|
## Security
|
|
624
770
|
|
|
625
771
|
- **Auto-redaction**: JWT, GitHub tokens, Bearer, AWS keys, SSH keys, and custom patterns scrubbed at ingest
|
|
@@ -668,7 +814,7 @@ Key config groups:
|
|
|
668
814
|
# Install with all dev dependencies
|
|
669
815
|
pip install -e ".[dev,mcp,security,embeddings,qdrant]"
|
|
670
816
|
|
|
671
|
-
# Run tests (
|
|
817
|
+
# Run tests (1029 tests)
|
|
672
818
|
pytest tests/ -q
|
|
673
819
|
|
|
674
820
|
# Lint and format
|
|
@@ -426,6 +426,7 @@ class _ReadMixin:
|
|
|
426
426
|
access_count = int(row["access_count"]) if "access_count" in keys else 0
|
|
427
427
|
last_accessed_val = row["last_accessed"] if "last_accessed" in keys else None
|
|
428
428
|
version = int(row["version"]) if "version" in keys and row["version"] is not None else 1
|
|
429
|
+
wiki_article = row["wiki_article"] if "wiki_article" in keys else None
|
|
429
430
|
return Claim(
|
|
430
431
|
id=int(row["id"]),
|
|
431
432
|
text=str(row["text"]),
|
|
@@ -457,6 +458,7 @@ class _ReadMixin:
|
|
|
457
458
|
source_agent=row["source_agent"] if "source_agent" in keys else None,
|
|
458
459
|
visibility=row["visibility"] if "visibility" in keys else "public",
|
|
459
460
|
version=version,
|
|
461
|
+
wiki_article=wiki_article,
|
|
460
462
|
)
|
|
461
463
|
|
|
462
464
|
|
|
@@ -472,6 +472,19 @@ class _SchemaMixin:
|
|
|
472
472
|
conn.execute("CREATE INDEX IF NOT EXISTS idx_claims_tier ON claims(tier)")
|
|
473
473
|
|
|
474
474
|
|
|
475
|
+
@staticmethod
|
|
476
|
+
def _ensure_binding_columns(conn: sqlite3.Connection) -> None:
|
|
477
|
+
"""Add wiki_article column for claim↔wiki bidirectional binding (v3.4)."""
|
|
478
|
+
try:
|
|
479
|
+
conn.execute("ALTER TABLE claims ADD COLUMN wiki_article TEXT")
|
|
480
|
+
except sqlite3.OperationalError as exc:
|
|
481
|
+
if "duplicate column name" not in str(exc).lower():
|
|
482
|
+
raise
|
|
483
|
+
conn.execute(
|
|
484
|
+
"CREATE INDEX IF NOT EXISTS idx_claims_wiki_article ON claims(wiki_article)"
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
|
|
475
488
|
@staticmethod
|
|
476
489
|
def _canonical_payload(payload_json: str | None) -> str:
|
|
477
490
|
if payload_json is None:
|
|
@@ -292,6 +292,12 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
292
292
|
wiki_breakdown.add_argument("--output", default="obsidian-vault", help="Wiki directory")
|
|
293
293
|
wiki_breakdown.add_argument("--scope", default="", help="Scope filter")
|
|
294
294
|
|
|
295
|
+
wiki_backfill = sub.add_parser(
|
|
296
|
+
"wiki-backfill-bindings",
|
|
297
|
+
help="Backfill claims.wiki_article from existing wiki article frontmatter (v3.4)",
|
|
298
|
+
)
|
|
299
|
+
wiki_backfill.add_argument("--output", default="obsidian-vault", help="Wiki directory to scan")
|
|
300
|
+
|
|
295
301
|
mine_cmd = sub.add_parser("mine-transcript", help="Parse Claude Code transcripts into claims")
|
|
296
302
|
mine_cmd.add_argument("--input", required=True, help="JSONL transcript file or directory")
|
|
297
303
|
mine_cmd.add_argument("--scope", default="project", help="Scope for ingested claims")
|
|
@@ -136,6 +136,73 @@ def _handle_wiki_absorb(args: argparse.Namespace, service, parser: argparse.Argu
|
|
|
136
136
|
return 0
|
|
137
137
|
|
|
138
138
|
|
|
139
|
+
def _handle_wiki_backfill_bindings(
|
|
140
|
+
args: argparse.Namespace, service, parser: argparse.ArgumentParser, effective_db: str
|
|
141
|
+
) -> int:
|
|
142
|
+
"""Backfill claims.wiki_article from existing wiki article frontmatter.
|
|
143
|
+
|
|
144
|
+
Scans every ``<wiki_dir>/**/*.md`` for a ``claims: [...]`` frontmatter line and
|
|
145
|
+
stamps each listed claim with the file's slug. One-shot v3.4 migration for DBs
|
|
146
|
+
that were absorbed before the binding feature existed.
|
|
147
|
+
"""
|
|
148
|
+
import re
|
|
149
|
+
import sqlite3
|
|
150
|
+
from pathlib import Path
|
|
151
|
+
|
|
152
|
+
wiki_dir = Path(args.output)
|
|
153
|
+
if not wiki_dir.exists():
|
|
154
|
+
print(f"Wiki dir not found: {wiki_dir}")
|
|
155
|
+
return 1
|
|
156
|
+
|
|
157
|
+
t0 = time.perf_counter()
|
|
158
|
+
scanned = 0
|
|
159
|
+
updated = 0
|
|
160
|
+
|
|
161
|
+
conn = sqlite3.connect(effective_db)
|
|
162
|
+
try:
|
|
163
|
+
cols = [r[1] for r in conn.execute("PRAGMA table_info(claims)").fetchall()]
|
|
164
|
+
if "wiki_article" not in cols:
|
|
165
|
+
print("claims.wiki_article column missing — run `init-db` first.")
|
|
166
|
+
return 1
|
|
167
|
+
|
|
168
|
+
claim_line = re.compile(r"^claims:\s*(\[[^\]]*\])", re.MULTILINE)
|
|
169
|
+
for md in wiki_dir.rglob("*.md"):
|
|
170
|
+
scanned += 1
|
|
171
|
+
try:
|
|
172
|
+
head = md.read_text(encoding="utf-8", errors="replace")[:2000]
|
|
173
|
+
except OSError:
|
|
174
|
+
continue
|
|
175
|
+
if not head.startswith("---"):
|
|
176
|
+
continue
|
|
177
|
+
m = claim_line.search(head)
|
|
178
|
+
if not m:
|
|
179
|
+
continue
|
|
180
|
+
try:
|
|
181
|
+
ids = [int(x.strip()) for x in m.group(1).strip("[]").split(",") if x.strip()]
|
|
182
|
+
except ValueError:
|
|
183
|
+
continue
|
|
184
|
+
if not ids:
|
|
185
|
+
continue
|
|
186
|
+
slug = md.stem
|
|
187
|
+
placeholders = ",".join("?" * len(ids))
|
|
188
|
+
cur = conn.execute(
|
|
189
|
+
f"UPDATE claims SET wiki_article = ? WHERE id IN ({placeholders}) AND (wiki_article IS NULL OR wiki_article != ?)",
|
|
190
|
+
(slug, *ids, slug),
|
|
191
|
+
)
|
|
192
|
+
updated += cur.rowcount
|
|
193
|
+
conn.commit()
|
|
194
|
+
finally:
|
|
195
|
+
conn.close()
|
|
196
|
+
|
|
197
|
+
elapsed_ms = (time.perf_counter() - t0) * 1000
|
|
198
|
+
result = {"wiki_dir": str(wiki_dir), "articles_scanned": scanned, "claims_updated": updated}
|
|
199
|
+
if args.json_output:
|
|
200
|
+
print(_json_envelope(result, query_ms=elapsed_ms))
|
|
201
|
+
else:
|
|
202
|
+
print(f"Backfill: scanned {scanned} articles, updated {updated} claims ({elapsed_ms:.0f}ms)")
|
|
203
|
+
return 0
|
|
204
|
+
|
|
205
|
+
|
|
139
206
|
def _handle_bases_generate(args: argparse.Namespace, service, parser: argparse.ArgumentParser, effective_db: str) -> int:
|
|
140
207
|
from memorymaster.vault_bases import generate_bases
|
|
141
208
|
t0 = time.perf_counter()
|
|
@@ -531,6 +598,7 @@ COMMAND_HANDLERS: dict[str, object] = {
|
|
|
531
598
|
"wiki-absorb": _handle_wiki_absorb,
|
|
532
599
|
"wiki-cleanup": _handle_wiki_cleanup,
|
|
533
600
|
"wiki-breakdown": _handle_wiki_breakdown,
|
|
601
|
+
"wiki-backfill-bindings": _handle_wiki_backfill_bindings,
|
|
534
602
|
"bases-generate": _handle_bases_generate,
|
|
535
603
|
"mine-transcript": _handle_mine_transcript,
|
|
536
604
|
"verify-claims": _handle_verify_claims,
|
|
@@ -123,7 +123,11 @@ def recall(
|
|
|
123
123
|
if not hasattr(claim, "text"):
|
|
124
124
|
continue
|
|
125
125
|
text = claim.text[:300]
|
|
126
|
-
|
|
126
|
+
wiki_slug = getattr(claim, "wiki_article", None)
|
|
127
|
+
if wiki_slug:
|
|
128
|
+
chunk = f"- {text} (compiled in [[{wiki_slug}]])"
|
|
129
|
+
else:
|
|
130
|
+
chunk = f"- {text}"
|
|
127
131
|
chunk_tokens = len(chunk) // chars_per_token
|
|
128
132
|
if tokens_used + chunk_tokens > budget:
|
|
129
133
|
break
|