luminary-memory 0.2.4__tar.gz → 0.2.6__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.
Files changed (132) hide show
  1. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/.github/workflows/publish.yml +3 -3
  2. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/CHANGELOG.md +28 -0
  3. luminary_memory-0.2.6/CONTRIBUTING.md +81 -0
  4. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/PKG-INFO +6 -4
  5. luminary_memory-0.2.6/PLAN-v0.2.5.md +120 -0
  6. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/README.md +5 -3
  7. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/ROADMAP.md +5 -5
  8. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/docs/api.md +1 -1
  9. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/docs/architecture.md +6 -2
  10. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/docs/cli.md +33 -1
  11. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/docs/hermes-integration.md +2 -0
  12. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/docs/index.md +2 -0
  13. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/docs/lifecycle.md +16 -1
  14. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/docs/quickstart.md +39 -0
  15. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/hermes/SKILL.md +5 -1
  16. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/pyproject.toml +1 -1
  17. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/__init__.py +1 -1
  18. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/api.py +18 -10
  19. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/backends/pgvector.py +20 -3
  20. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/backends/sqlite.py +4 -0
  21. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/cli.py +12 -2
  22. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/config.py +9 -0
  23. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/hermes/config_schema.py +2 -0
  24. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/hermes/provider.py +4 -0
  25. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/ingest/llm.py +12 -6
  26. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/lifecycle/cleanup.py +4 -0
  27. luminary_memory-0.2.6/src/luminary_memory/lifecycle/consolidate.py +87 -0
  28. luminary_memory-0.2.6/src/luminary_memory/lifecycle/importance.py +68 -0
  29. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/lifecycle/prune.py +4 -0
  30. luminary_memory-0.2.6/src/luminary_memory/lifecycle/runner.py +52 -0
  31. luminary_memory-0.2.6/src/luminary_memory/recall/dedup.py +50 -0
  32. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_api_extended.py +21 -0
  33. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_cli.py +11 -1
  34. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_dedup_jaccard.py +47 -0
  35. luminary_memory-0.2.6/tests/test_importance.py +145 -0
  36. luminary_memory-0.2.6/tests/test_lifecycle.py +189 -0
  37. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/website/index.html +1 -1
  38. luminary_memory-0.2.4/CONTRIBUTING.md +0 -45
  39. luminary_memory-0.2.4/src/luminary_memory/lifecycle/consolidate.py +0 -47
  40. luminary_memory-0.2.4/src/luminary_memory/lifecycle/runner.py +0 -26
  41. luminary_memory-0.2.4/src/luminary_memory/recall/dedup.py +0 -30
  42. luminary_memory-0.2.4/tests/test_lifecycle.py +0 -92
  43. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  44. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  45. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  46. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/.github/workflows/ci.yml +0 -0
  47. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/.github/workflows/pages.yml +0 -0
  48. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/.gitignore +0 -0
  49. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/CODE_OF_CONDUCT.md +0 -0
  50. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/LICENSE +0 -0
  51. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/PLAN-v0.2.0.md +0 -0
  52. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/PLAN-v0.2.1.md +0 -0
  53. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/PLAN-v0.2.4.md +0 -0
  54. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/PLAN.md +0 -0
  55. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/SECURITY.md +0 -0
  56. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/benchmarks/README.md +0 -0
  57. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/benchmarks/RESULTS.md +0 -0
  58. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/benchmarks/__init__.py +0 -0
  59. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/benchmarks/hermes_provider_bench.py +0 -0
  60. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/benchmarks/metrics.py +0 -0
  61. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/benchmarks/run_benchmarks.py +0 -0
  62. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/benchmarks/synthetic.py +0 -0
  63. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/docs/backends.md +0 -0
  64. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/docs/recall.md +0 -0
  65. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/hermes/README.md +0 -0
  66. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/hermes/hooks/luminary-activity/HOOK.yaml +0 -0
  67. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/hermes/hooks/luminary-activity/README.md +0 -0
  68. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/hermes/hooks/luminary-activity/handler.py +0 -0
  69. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/hermes/install.sh +0 -0
  70. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/backends/__init__.py +0 -0
  71. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/backends/base.py +0 -0
  72. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/budget.py +0 -0
  73. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/embeddings/__init__.py +0 -0
  74. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/embeddings/fastembed.py +0 -0
  75. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/export.py +0 -0
  76. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/hermes/__init__.py +0 -0
  77. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/hermes/config.py +0 -0
  78. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/hermes/plugin.yaml +0 -0
  79. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/ingest/__init__.py +0 -0
  80. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/ingest/whitelist.py +0 -0
  81. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/lifecycle/__init__.py +0 -0
  82. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/recall/__init__.py +0 -0
  83. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/recall/fusion.py +0 -0
  84. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/recall/graph.py +0 -0
  85. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/recall/keyword.py +0 -0
  86. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/recall/planner.py +0 -0
  87. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/recall/semantic.py +0 -0
  88. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/recall/snippets.py +0 -0
  89. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/recall/temporal.py +0 -0
  90. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/schema.py +0 -0
  91. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/src/luminary_memory/types.py +0 -0
  92. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/__init__.py +0 -0
  93. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/conftest.py +0 -0
  94. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/hermes/test_backup_paths.py +0 -0
  95. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/hermes/test_config.py +0 -0
  96. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/hermes/test_entrypoint.py +0 -0
  97. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/hermes/test_hooks.py +0 -0
  98. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/hermes/test_lifecycle.py +0 -0
  99. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/hermes/test_provider_import.py +0 -0
  100. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/hermes/test_recall.py +0 -0
  101. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/hermes/test_session_boundaries.py +0 -0
  102. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/hermes/test_sync_turn.py +0 -0
  103. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/hermes/test_system_prompt.py +0 -0
  104. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/hermes/test_tools.py +0 -0
  105. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/hermes_stubs/agent/memory_provider.py +0 -0
  106. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_api.py +0 -0
  107. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_backend_pgvector.py +0 -0
  108. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_backend_sqlite.py +0 -0
  109. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_budget.py +0 -0
  110. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_embeddings.py +0 -0
  111. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_fusion_rrf.py +0 -0
  112. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_ingest_llm.py +0 -0
  113. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_ingest_whitelist.py +0 -0
  114. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_recall_graph.py +0 -0
  115. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_recall_keyword.py +0 -0
  116. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_recall_orchestrator.py +0 -0
  117. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_recall_semantic.py +0 -0
  118. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_recall_temporal.py +0 -0
  119. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_schema.py +0 -0
  120. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_t10_export.py +0 -0
  121. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_t11_limit_zero.py +0 -0
  122. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_t1_hnsw.py +0 -0
  123. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_t3_planner.py +0 -0
  124. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_t4_batch.py +0 -0
  125. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_t5_enricher.py +0 -0
  126. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_t6_tag_scoped.py +0 -0
  127. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_t7_updated_at.py +0 -0
  128. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_t8_snippets.py +0 -0
  129. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/tests/test_t9_cli_json.py +0 -0
  130. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/website/.nojekyll +0 -0
  131. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/website/css/luminary.css +0 -0
  132. {luminary_memory-0.2.4 → luminary_memory-0.2.6}/website/js/luminary.js +0 -0
@@ -35,9 +35,9 @@ jobs:
35
35
  ls -lh skill_asset/luminary-memory-skill.zip
36
36
  - name: Publish to PyPI (trusted publishing / OIDC)
37
37
  uses: pypa/gh-action-pypi-publish@release/v1
38
- # Requires one-time setup on PyPI: configure this repo as a trusted
39
- # publisher for project luminary-memory (https://pypi.org/manage/account/publishing/).
40
- # Fallback: python -m build && twine upload dist/*
38
+ # Trusted Publisher only — no API token. Configured at
39
+ # https://pypi.org/manage/account/publishing/. Never fall back to twine:
40
+ # an API token upload alongside Trusted Publishing triggers a PyPI alert.
41
41
  - name: Attach skill asset to GitHub Release
42
42
  uses: softprops/action-gh-release@v2
43
43
  with:
@@ -2,6 +2,34 @@
2
2
 
3
3
  All notable changes to this project are documented in this file. The format follows [Keep a Changelog](https://keepachangelog.com/), and the project adheres to [Semantic Versioning](https://semver.org/).
4
4
 
5
+ ## [0.2.6] - 2026-08-18
6
+
7
+ ### Polish & hardening
8
+
9
+ - **Lifecycle logging** — `cleanup`, `consolidate` (mode + merged count), `prune`, and `run_lifecycle` (result + duration) now log their activity; `estimate_importance` logs via the runner.
10
+ - **SQLite batch errors logged** — `add_many` failures log the exception before rollback/re-raise (was silent).
11
+ - **CLI recall JSON richer** — each memory now includes `source`, `created_at`, and `importance`.
12
+ - **Env var warnings** — invalid `LUMINARY_*` int/float values warn instead of silently falling back.
13
+ - **Dashboard schema 20 fields** — `consolidate_semantic` (Semantic consolidation) and `importance_auto` (Auto importance estimation) added to the Hermes provider config.
14
+ - **`recall(limit=0)` truly unlimited** — passes `None` to backends instead of a 10k magic cap.
15
+ - **Dedup capped window** — `dedup_jaccard(max_pairs=500)` keeps recall O(n·k) instead of O(n²) on large result sets.
16
+ - **`import_memories` error logging** — failures log the path before re-raise.
17
+ - **pgvector JSON columns safe** — `metadata`/`tags` parse via a `_json_load` helper (corrupt data falls back instead of crashing); HNSW index failure now logged.
18
+ - **Prefetch thread join** — `queue_prefetch` joins any in-flight worker before spawning a new one (no thread leak / stale-cache overwrite).
19
+ - **Degenerate embedding guard** — semantic consolidation falls back to Jaccard when embeddings are all-equal (no false merges of unrelated memories).
20
+ - **`CONTRIBUTING.md`** — new Testing section (Postgres/pgvector setup, coverage ≥ 90%) pointing at [issue #1](https://github.com/alertxsto/luminary-memory/issues/1) (add Postgres to CI).
21
+
22
+ ## [0.2.5] - 2026-08-18
23
+
24
+ ### Added
25
+
26
+ - **Semantic consolidation** — `consolidate(semantic=True)` merges memories by embedding-cosine similarity (default `LUMINARY_CONSOLIDATE_SEMANTIC=true`), catching paraphrases that token-overlap misses; falls back to Jaccard when embeddings are missing. CLI: `luminary-memory lifecycle --semantic/--no-semantic`.
27
+ - **Auto importance estimation** — `lifecycle/importance.py:estimate_importance()` scores each memory from access (`log1p`), recency (24h decay), and graph centrality; applied on ingest and re-estimated before every prune (`LUMINARY_IMPORTANCE_AUTO=true`). Pruning and the health score's importance dimension now use live values.
28
+
29
+ ### Changed
30
+
31
+ - `run_lifecycle()` now also re-estimates importances (returns `reestimated` count).
32
+
5
33
  ## [0.2.4] - 2026-08-18
6
34
 
7
35
  ### Added
@@ -0,0 +1,81 @@
1
+ # Contributing
2
+
3
+ Thanks for helping build luminary-memory.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ git clone <repo> && cd luminary-memory
9
+ pip install -e ".[dev]"
10
+ ```
11
+
12
+ ## Development workflow
13
+
14
+ 1. Create a branch: `git checkout -b feat/your-change`.
15
+ 2. Write a failing test first (`tests/`).
16
+ 3. Implement the minimal change.
17
+ 4. Run the checks:
18
+
19
+ ```bash
20
+ python -m pytest
21
+ python -m ruff check src tests
22
+ ```
23
+
24
+ 5. Commit with a conventional message.
25
+
26
+ ## Commit conventions
27
+
28
+ - `feat:` — new feature
29
+ - `fix:` — bug fix
30
+ - `docs:` — documentation only
31
+ - `improve:` — refactor or enhancement without behavior change
32
+ - `chore:` — build/tooling
33
+
34
+ ## Coding standards
35
+
36
+ - Python 3.11+, type-hinted.
37
+ - `ruff` clean, `pytest` green.
38
+ - TDD where feasible — test first, then implement.
39
+ - Keep the public API (`MemoryClient`) stable; add rather than break.
40
+
41
+ ## Pull requests
42
+
43
+ - One logical change per PR.
44
+ - Link the issue if applicable.
45
+ - CI must pass before merge.
46
+
47
+ ## Testing
48
+
49
+ Run the full suite (SQLite + unit tests) locally:
50
+
51
+ ```bash
52
+ python -m pytest # ~200+ tests, green without any external service
53
+ python -m ruff check src tests
54
+ ```
55
+
56
+ Coverage (must stay ≥ 90%):
57
+
58
+ ```bash
59
+ python -m pytest --cov=luminary_memory --cov-report=term
60
+ ```
61
+
62
+ ### Postgres / pgvector integration tests
63
+
64
+ `tests/test_backend_pgvector.py` contains real-Postgres round-trips that are
65
+ **skipped unless `LUMINARY_PG_DSN` is set** — CI currently does not provide
66
+ Postgres, so the pgvector path is the least-covered module (59%). If you're
67
+ working on the pgvector backend, run them locally with:
68
+
69
+ ```bash
70
+ # spin up a throwaway Postgres with the pgvector extension
71
+ docker run -d --name luminary-pg -p 5432:5432 \
72
+ -e POSTGRES_USER=luminary -e POSTGRES_PASSWORD=luminary -e POSTGRES_DB=luminary \
73
+ pgvector/pgvector:pg16
74
+
75
+ # point the tests at it
76
+ export LUMINARY_PG_DSN=postgresql://luminary:luminary@localhost:5432/luminary
77
+ python -m pytest tests/test_backend_pgvector.py -v
78
+ ```
79
+
80
+ See [issue #1](https://github.com/alertxsto/luminary-memory/issues/1) for
81
+ adding a Postgres service to CI so these tests run automatically.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: luminary-memory
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Summary: A lightweight, self-hosted memory layer for AI agents
5
5
  Project-URL: Homepage, https://github.com/alertxsto/luminary-memory
6
6
  Project-URL: Repository, https://github.com/alertxsto/luminary-memory
@@ -40,8 +40,8 @@ Description-Content-Type: text/markdown
40
40
  [![Python](https://img.shields.io/pypi/pyversions/luminary-memory?color=8ab4e8)](https://pypi.org/project/luminary-memory)
41
41
  [![License](https://img.shields.io/github/license/alertxsto/luminary-memory?color=8ab4e8)](LICENSE)
42
42
  [![CI](https://img.shields.io/github/actions/workflow/status/alertxsto/luminary-memory/ci.yml?color=8ab4e8&label=CI)](https://github.com/alertxsto/luminary-memory/actions)
43
- [![Tests](https://img.shields.io/badge/tests-168%20passing-8ab4e8)](https://github.com/alertxsto/luminary-memory/actions)
44
- [![Coverage](https://img.shields.io/badge/coverage-85%25-8ab4e8)](https://github.com/alertxsto/luminary-memory)
43
+ [![Tests](https://img.shields.io/badge/tests-190%2B%20passing-8ab4e8)](https://github.com/alertxsto/luminary-memory/actions)
44
+ [![Coverage](https://img.shields.io/badge/coverage-90%25-8ab4e8)](https://github.com/alertxsto/luminary-memory)
45
45
  [![Stars](https://img.shields.io/github/stars/alertxsto/luminary-memory?color=8ab4e8)](https://github.com/alertxsto/luminary-memory)
46
46
 
47
47
  **Self-hosted · Private · Budget-aware · Self-maintaining**
@@ -132,6 +132,8 @@ Every setting has a `LUMINARY_*` env var or a `Settings` object.
132
132
  | `ttl_default_seconds` | `LUMINARY_TTL_DEFAULT_SECONDS` | `null` |
133
133
  | `prune_min_importance` | `LUMINARY_PRUNE_MIN_IMPORTANCE` | `0.2` |
134
134
  | `consolidate_jaccard_threshold` | `LUMINARY_CONSOLIDATE_JACCARD_THRESHOLD` | `0.9` |
135
+ | `consolidate_semantic` | `LUMINARY_CONSOLIDATE_SEMANTIC` | `true` |
136
+ | `importance_auto` | `LUMINARY_IMPORTANCE_AUTO` | `true` |
135
137
 
136
138
  See [hermes/SKILL.md](hermes/SKILL.md) for the full provider config table (18 settings).
137
139
 
@@ -166,7 +168,7 @@ Built-in lifecycle keeps the store lean. LLM maintenance (optional) keeps it acc
166
168
  | [Lifecycle](docs/lifecycle.md) | Cleanup, consolidation, pruning, LLM maintenance |
167
169
  | [Backends](docs/backends.md) | SQLite vs pgvector |
168
170
  | [Hermes integration](docs/hermes-integration.md) | Provider, config, installer |
169
- | [Roadmap](ROADMAP.md) | v0.2.3 → v1.0.0 |
171
+ | [Roadmap](ROADMAP.md) | v0.2.6 → v1.0.0 |
170
172
  | [Benchmarks](benchmarks/RESULTS.md) | 230 ms recall @ 5k, 0 LLM tokens |
171
173
 
172
174
  ---
@@ -0,0 +1,120 @@
1
+ # PLAN v0.2.5 — Semantic Consolidation + Auto Importance
2
+
3
+ **Version:** 0.2.5 · **Milestone:** Smarter self-maintenance (roadmap v0.3.0 items #4 + #5)
4
+ **Goal:** Replace token-overlap consolidation with semantic (embedding) merging, and auto-estimate memory importance so pruning and health scores reflect real value.
5
+
6
+ ---
7
+
8
+ ## Background (verified from code)
9
+
10
+ - `lifecycle/consolidate.py` uses **Jaccard token overlap only** (`recall/dedup.py:jaccard_similarity`). Two memories with the same meaning but different wording ("deploy target is staging" vs "deploy target is production cluster") are **not** merged → semantic duplicates accumulate.
11
+ - `lifecycle/prune.py` uses **static `m.importance`** (default `0.2`), never estimated from behavior → pruning is blunt.
12
+ - `MemoryClient` has `self.engine.embed()` (fastembed) available — can compute embeddings for consolidation without new deps.
13
+ - `types.py:Memory` has `importance`, `access_count`, `created_at`, `last_accessed_at`, `metadata`.
14
+
15
+ ---
16
+
17
+ ## Phase 1 — Semantic Consolidation (T1–T4)
18
+
19
+ ### T1 — cosine helper in `recall/dedup.py`
20
+
21
+ Add `cosine_similarity(a: list[float], b: list[float]) -> float` (pure math, no deps). Reuse in consolidation; keep `jaccard_similarity` for dedup.
22
+
23
+ - Test: identical vectors → 1.0; orthogonal → 0.0; empty → 0.0; negative → clamped.
24
+
25
+ ### T2 — semantic merge in `lifecycle/consolidate.py`
26
+
27
+ Extend `consolidate(backend, threshold=0.9, semantic=True)`:
28
+
29
+ - `semantic=True` (default): cluster by `cosine_similarity(embedding_a, embedding_b) >= semantic_threshold` (default 0.85), **falling back to Jaccard** when embeddings are missing (legacy rows, pgvector without vectors).
30
+ - `semantic=False`: current Jaccard behavior (back-compat).
31
+ - Keep existing merge logic (longest content as master, sum access, union tags).
32
+
33
+ - Tests: two memories same meaning different words → merged (embedding similarity high); two unrelated → kept; missing embeddings → falls back to Jaccard; `semantic=False` → Jaccard only.
34
+
35
+ ### T3 — CLI flag
36
+
37
+ `luminary-memory lifecycle --semantic/--no-semantic` (default semantic on). Wire through `run_lifecycle()` → `consolidate(semantic=...)`.
38
+
39
+ - Test: CLI flag parse + passes through.
40
+
41
+ ### T4 — runner integration
42
+
43
+ `lifecycle/runner.py:run_lifecycle()` passes `semantic` from settings (`LUMINARY_CONSOLIDATE_SEMANTIC`, default `true`). New env var documented.
44
+
45
+ - Test: runner respects env var.
46
+
47
+ ---
48
+
49
+ ## Phase 2 — Auto Importance Estimation (T5–T8)
50
+
51
+ ### T5 — estimator module `lifecycle/importance.py`
52
+
53
+ ```python
54
+ def estimate_importance(
55
+ memory, now=None,
56
+ half_life_hours: float = 24.0, # recency decay
57
+ access_weight: float = 0.4,
58
+ recency_weight: float = 0.3,
59
+ centrality_weight: float = 0.3,
60
+ ) -> float:
61
+ ```
62
+
63
+ `importance = access_norm * access_weight + recency_norm * recency_weight + centrality_norm * centrality_weight`
64
+
65
+ - `access_norm` — `log1p(access_count) / log1p(max_access_in_store)`.
66
+ - `recency_norm` — `exp(-age_hours / half_life_hours)` (same decay shape as temporal recall).
67
+ - `centrality_norm` — graph degree / max degree (relations count; 0 when no graph table).
68
+ - Clamp 0.0–1.0.
69
+
70
+ - Tests: new memory → low importance; accessed many times → high; recent → high; old+never-accessed → low; clamp bounds.
71
+
72
+ ### T6 — call estimator on ingest + lifecycle
73
+
74
+ - `api.py:ingest()` — after insert, if importance not explicitly set, `estimate_importance(memory)` and persist (needs backend update — cheap, one row).
75
+ - `run_lifecycle()` — re-estimate all importances before prune so pruning reflects current value.
76
+ - Guard: only when `LUMINARY_IMPORTANCE_AUTO` (default `true`).
77
+
78
+ - Tests: ingest sets importance > 0; lifecycle re-estimates (old memory importance drops); disabled flag keeps static.
79
+
80
+ ### T7 — prune uses estimated importance (already does, but now fed live values)
81
+
82
+ No structural change — prune already reads `m.importance`. Add test proving a low-importance memory gets pruned after re-estimation.
83
+
84
+ ### T8 — health score uses importance dimension (already reads it)
85
+
86
+ `health_score()` `importance` dimension already uses `m.importance >= prune_min`. With auto-estimation the dimension becomes meaningful. Add test: fresh store → importance high → score contribution healthy.
87
+
88
+ ---
89
+
90
+ ## Phase 3 — Docs + Release (T9–T10)
91
+
92
+ ### T9 — Documentation sweep (REQUIRED before release — user rule)
93
+
94
+ - `docs/lifecycle.md` — semantic consolidation section + importance auto-estimation + new env vars.
95
+ - `docs/recall.md` — note cosine in consolidation (dedup still Jaccard).
96
+ - `docs/architecture.md` — update lifecycle pipeline (importance estimation step).
97
+ - `docs/cli.md` — `lifecycle --semantic/--no-semantic`.
98
+ - `README.md` — badges if tests/coverage change; roadmap line v0.2.5.
99
+ - `CHANGELOG.md` — 0.2.5 entry.
100
+ - `ROADMAP.md` — header v0.2.5, tick items #4 (importance) + #5 (consolidation v2).
101
+ - Website badge → v0.2.5.
102
+ - Grep for stale versions across all docs before release.
103
+
104
+ ### T10 — Release v0.2.5
105
+
106
+ - Bump `pyproject.toml` + `__init__.py` → 0.2.5.
107
+ - `pytest -q` green, `ruff check` clean, coverage ≥ 90% (DoD).
108
+ - Tag `v0.2.5` → push → GitHub release (Trusted Publisher auto-publishes PyPI).
109
+ - Verify PyPI version + website redeploy.
110
+
111
+ ---
112
+
113
+ ## Definition of Done
114
+
115
+ - [ ] Consolidation merges semantic near-duplicates (verified with same-meaning-different-words test)
116
+ - [ ] Importance auto-estimated on ingest + lifecycle (verified with behavior tests)
117
+ - [ ] Coverage ≥ 90%, ruff clean, all tests green
118
+ - [ ] CLI `--semantic/--no-semantic` works
119
+ - [ ] Docs sweep complete & versions consistent (user rule)
120
+ - [ ] v0.2.5 released via Trusted Publisher (no twine)
@@ -6,8 +6,8 @@
6
6
  [![Python](https://img.shields.io/pypi/pyversions/luminary-memory?color=8ab4e8)](https://pypi.org/project/luminary-memory)
7
7
  [![License](https://img.shields.io/github/license/alertxsto/luminary-memory?color=8ab4e8)](LICENSE)
8
8
  [![CI](https://img.shields.io/github/actions/workflow/status/alertxsto/luminary-memory/ci.yml?color=8ab4e8&label=CI)](https://github.com/alertxsto/luminary-memory/actions)
9
- [![Tests](https://img.shields.io/badge/tests-168%20passing-8ab4e8)](https://github.com/alertxsto/luminary-memory/actions)
10
- [![Coverage](https://img.shields.io/badge/coverage-85%25-8ab4e8)](https://github.com/alertxsto/luminary-memory)
9
+ [![Tests](https://img.shields.io/badge/tests-190%2B%20passing-8ab4e8)](https://github.com/alertxsto/luminary-memory/actions)
10
+ [![Coverage](https://img.shields.io/badge/coverage-90%25-8ab4e8)](https://github.com/alertxsto/luminary-memory)
11
11
  [![Stars](https://img.shields.io/github/stars/alertxsto/luminary-memory?color=8ab4e8)](https://github.com/alertxsto/luminary-memory)
12
12
 
13
13
  **Self-hosted · Private · Budget-aware · Self-maintaining**
@@ -98,6 +98,8 @@ Every setting has a `LUMINARY_*` env var or a `Settings` object.
98
98
  | `ttl_default_seconds` | `LUMINARY_TTL_DEFAULT_SECONDS` | `null` |
99
99
  | `prune_min_importance` | `LUMINARY_PRUNE_MIN_IMPORTANCE` | `0.2` |
100
100
  | `consolidate_jaccard_threshold` | `LUMINARY_CONSOLIDATE_JACCARD_THRESHOLD` | `0.9` |
101
+ | `consolidate_semantic` | `LUMINARY_CONSOLIDATE_SEMANTIC` | `true` |
102
+ | `importance_auto` | `LUMINARY_IMPORTANCE_AUTO` | `true` |
101
103
 
102
104
  See [hermes/SKILL.md](hermes/SKILL.md) for the full provider config table (18 settings).
103
105
 
@@ -132,7 +134,7 @@ Built-in lifecycle keeps the store lean. LLM maintenance (optional) keeps it acc
132
134
  | [Lifecycle](docs/lifecycle.md) | Cleanup, consolidation, pruning, LLM maintenance |
133
135
  | [Backends](docs/backends.md) | SQLite vs pgvector |
134
136
  | [Hermes integration](docs/hermes-integration.md) | Provider, config, installer |
135
- | [Roadmap](ROADMAP.md) | v0.2.3 → v1.0.0 |
137
+ | [Roadmap](ROADMAP.md) | v0.2.6 → v1.0.0 |
136
138
  | [Benchmarks](benchmarks/RESULTS.md) | 230 ms recall @ 5k, 0 LLM tokens |
137
139
 
138
140
  ---
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **Tagline:** A lightweight, self-hosted memory layer for AI agents.
4
4
 
5
- **Current release:** v0.1.1 (bugfix) · **Tests:** 97 passing · **Coverage:** 91% · **License:** Apache-2.0
5
+ **Current release:** v0.2.6 (polish & hardening) · **Tests:** 200+ passing · **Coverage:** 90% · **License:** Apache-2.0
6
6
 
7
7
  ---
8
8
 
@@ -33,7 +33,7 @@ Every AI agent deserves durable memory that lives on its own infrastructure. Lum
33
33
  | Packaging (PyPI, GitHub release, tags) | ✅ v0.1.1 |
34
34
  | Website (landing page) | ✅ v0.1.1 |
35
35
  | Hermes integration skill | ✅ v0.1.1 |
36
- | Test coverage | ✅ 91% total (pgvector 82%) |
36
+ | Test coverage | ✅ 90% total |
37
37
 
38
38
  ---
39
39
 
@@ -102,10 +102,10 @@ Post-MVP audit hardening.
102
102
  **Goal:** Smarter memory — structure, insight, and visualization.
103
103
 
104
104
  - [ ] Knowledge graph visualization (entity relations browser)
105
- - [ ] Memory health score (duplicate rate, staleness, importance distribution)
105
+ - [x] Memory health score (duplicate rate, staleness, importance distribution) — v0.2.4
106
106
  - [ ] Multi-user scoping (`user_id` per memory, per-user recall)
107
- - [ ] Memory importance auto-estimation (recency + access + semantic centrality)
108
- - [ ] Consolidation v2: semantic-aware merging (not just Jaccard token overlap)
107
+ - [x] Memory importance auto-estimation (recency + access + semantic centrality) — v0.2.5
108
+ - [x] Consolidation v2: semantic-aware merging (not just Jaccard token overlap) — v0.2.5
109
109
 
110
110
  ---
111
111
 
@@ -14,7 +14,7 @@ pdoc --output-dir docs/api --docformat markdown src/luminary_memory
14
14
 
15
15
  ## Quick surface
16
16
 
17
- - `MemoryClient` — `ingest`, `ingest_batch`, `recall` (tags + snippets + planner), `search`, `get`/`update`/`delete`, `list`, `export`/`import_memories`, `run_lifecycle`, `run_maintenance` (LLM curation), `stats`, `close`.
17
+ - `MemoryClient` — `ingest`, `ingest_batch`, `recall` (tags + snippets + planner), `search`, `get`/`update`/`delete`, `list`, `export`/`import_memories`, `run_lifecycle`, `run_maintenance` (LLM curation), `health_score` (store health report), `stats`, `close`.
18
18
  - `Settings` — `LUMINARY_*` env vars, `as_dict()`.
19
19
  - `Memory`, `RecallResult` — `types.py`.
20
20
  - Subpackages `backends/`, `embeddings/`, `ingest/`, `recall/`, `lifecycle/`, `export`.
@@ -42,5 +42,9 @@ See [backends.md](backends.md).
42
42
  Three maintenance passes, orchestrated by `run_lifecycle()`:
43
43
 
44
44
  - **cleanup** — remove TTL-expired memories.
45
- - **consolidate** — merge near-duplicates (Jaccard ≥ threshold).
46
- - **prune** — drop low-importance or least-recently-used memories.
45
+ - **consolidate** — merge near-duplicates (Jaccard or embedding-cosine, semantic by default).
46
+ - **prune** — drop low-importance or least-recently-used memories (importance auto-estimated from access, recency, centrality).
47
+
48
+ Optional **LLM maintenance** (`run_maintenance()`, or provider `auto_maintain`)
49
+ reviews the whole store and keeps/updates/deletes facts semantically.
50
+ `health_score()` reports store quality (0-100) across five dimensions.
@@ -46,9 +46,30 @@ Most recent first.
46
46
 
47
47
  ```bash
48
48
  luminary-memory lifecycle
49
+ luminary-memory lifecycle --no-semantic # Jaccard-only consolidation
49
50
  ```
50
51
 
51
- Runs cleanup + consolidate + prune, prints counts.
52
+ Runs cleanup + consolidate + prune (plus importance re-estimation), prints
53
+ counts. `--semantic/--no-semantic` toggles embedding-cosine consolidation
54
+ (default: semantic on).
55
+
56
+ ### export
57
+
58
+ ```bash
59
+ luminary-memory export --path backup.json
60
+ luminary-memory export --path backup.json --no-embeddings
61
+ ```
62
+
63
+ Exports all memories to a JSON file (backup/migration). `--no-embeddings`
64
+ skips embedding vectors to keep the file small.
65
+
66
+ ### import
67
+
68
+ ```bash
69
+ luminary-memory import --path backup.json
70
+ ```
71
+
72
+ Imports memories from a JSON export (recomputes embeddings when absent).
52
73
 
53
74
  ### stats
54
75
 
@@ -58,6 +79,17 @@ luminary-memory stats
58
79
 
59
80
  Prints store statistics as JSON.
60
81
 
82
+ ### health
83
+
84
+ ```bash
85
+ luminary-memory health
86
+ luminary-memory health --json
87
+ ```
88
+
89
+ Prints a 0-100 store health score with a per-dimension breakdown (duplicate
90
+ rate, staleness, importance, graph density, size) and actionable
91
+ recommendations. `--json` emits the raw report.
92
+
61
93
  ## Exit codes
62
94
 
63
95
  - `0` — success.
@@ -96,6 +96,8 @@ cp hermes/SKILL.md ~/.hermes/skills/luminary-memory/SKILL.md
96
96
  1. **Ingest on tool call** — after learning a durable fact (preference, environment detail), call `client.ingest(...)`.
97
97
  2. **Recall into the system prompt** — before answering, call `client.recall(query)` and inject the top memories as context.
98
98
  3. **Lifecycle via cron** — schedule `luminary-memory lifecycle` to keep the store clean.
99
+ 4. **Monitor health** — `luminary-memory health` (or `client.health_score()`) reports store quality; run it in a cron to catch drift.
100
+ 5. **LLM curation (optional)** — with `ingest_llm` + `auto_maintain`, turns are curated and stale facts pruned automatically.
99
101
 
100
102
  ## Example
101
103
 
@@ -12,6 +12,8 @@ A lightweight, self-hosted memory layer for AI agents.
12
12
 
13
13
  - Four retrieval strategies fused into one ranked recall (semantic, keyword, temporal, graph).
14
14
  - **First-class Hermes Agent memory provider** — auto-recall every turn, auto-save every session, zero LLM tokens per turn (`memory.provider: luminary`).
15
+ - **LLM memory curation** — optional `ingest_llm` drops chit-chat and stores factual summaries; `auto_maintain` prunes stale/duplicate facts at session end.
16
+ - **Health score** — `health_score()` / `luminary-memory health` reports store quality (0-100) with recommendations.
15
17
  - SQLite out of the box, optional pgvector for scale.
16
18
  - Local CPU embeddings via ONNX — no GPU, no cloud.
17
19
  - Configurable token budget so memory never overflows the agent's context.
@@ -11,7 +11,22 @@ Removes memories whose `ttl_seconds` has elapsed.
11
11
 
12
12
  ### consolidate — merge near-duplicates
13
13
 
14
- Clusters memories by Jaccard similarity (`LUMINARY_CONSOLIDATE_JACCARD_THRESHOLD`, default 0.9) and merges each cluster into a single memory — keeping the longest content, summing access counts, and unioning tags.
14
+ Clusters memories by Jaccard similarity (`LUMINARY_CONSOLIDATE_JACCARD_THRESHOLD`, default 0.9) **or embedding-cosine similarity** (`LUMINARY_CONSOLIDATE_SEMANTIC`, default `true`) and merges each cluster into a single memory — keeping the longest content, summing access counts, and unioning tags. Semantic mode (default) merges paraphrases that token overlap would miss; it falls back to Jaccard when embeddings are missing. Disable with `LUMINARY_CONSOLIDATE_SEMANTIC=false` or `luminary-memory lifecycle --no-semantic`.
15
+
16
+ ### importance — auto-estimation
17
+
18
+ On ingest and before each prune, each memory's importance is estimated from behavior:
19
+
20
+ ```
21
+ importance = access_norm × 0.4 + recency_norm × 0.3 + centrality_norm × 0.3
22
+ ```
23
+
24
+ - `access_norm` — `log1p(access_count)` normalized to the store's max.
25
+ - `recency_norm` — `exp(-age_hours / 24h)` (fresh memories score higher).
26
+ - `centrality_norm` — graph relation degree normalized (0 when no graph).
27
+
28
+ Disable with `LUMINARY_IMPORTANCE_AUTO=false`. Pruning and the health score's
29
+ importance dimension both use these live values.
15
30
 
16
31
  ### prune — drop low-value memories
17
32
 
@@ -31,6 +31,9 @@ for memory, score in zip(result.memories, result.scores):
31
31
  # 3. maintain the store
32
32
  client.run_lifecycle()
33
33
 
34
+ # 4. check store health (0-100 score + recommendations)
35
+ print(client.health_score())
36
+
34
37
  client.close()
35
38
  ```
36
39
 
@@ -40,8 +43,44 @@ client.close()
40
43
  luminary-memory add "The deploy target is the staging cluster" --tags deploy
41
44
  luminary-memory recall "where do we deploy?" --json
42
45
  luminary-memory stats
46
+ luminary-memory health
47
+ ```
48
+
49
+ ## Backup & restore
50
+
51
+ ```bash
52
+ luminary-memory export --path backup.json
53
+ luminary-memory import --path backup.json
54
+ ```
55
+
56
+ `export` writes all memories to a JSON file (migration/backup); `import`
57
+ restores them (recomputing embeddings when absent).
58
+
59
+ ## Optional: LLM memory curation
60
+
61
+ By default every ingest is stored verbatim (zero LLM cost). To have an LLM
62
+ evaluate each turn — dropping chit-chat and storing concise factual summaries
63
+ instead of raw transcripts — enable `ingest_llm` and `auto_maintain`:
64
+
65
+ ```bash
66
+ pip install "luminary-memory[hermes]"
43
67
  ```
44
68
 
69
+ ```json
70
+ // ~/.hermes/luminary/config.json (Hermes provider)
71
+ {
72
+ "ingest_llm": true,
73
+ "auto_maintain": true,
74
+ "llm_base_url": "https://api.commandcode.ai/provider/v1",
75
+ "llm_model": "deepseek/deepseek-v4-flash",
76
+ "llm_api_key": "your-key"
77
+ }
78
+ ```
79
+
80
+ Any OpenAI-compatible endpoint works. `auto_maintain` reviews the store at
81
+ session end — keeping current facts, updating changed ones, deleting stale or
82
+ duplicate memories.
83
+
45
84
  ## Configuration
46
85
 
47
86
  All settings accept a `LUMINARY_*` env var:
@@ -86,11 +86,15 @@ client.run_lifecycle()
86
86
 
87
87
  # LLM review: keep current facts, update changed ones, delete stale/duplicates
88
88
  client.run_maintenance() # requires an LLM enricher (ingest_llm)
89
+
90
+ # health check: 0-100 score with per-dimension breakdown + recommendations
91
+ report = client.health_score()
89
92
  ```
90
93
 
91
94
  In the Hermes provider, `auto_maintain: true` (plus `ingest_llm: true`) runs
92
95
  `run_maintenance()` automatically at every session end — no manual trigger
93
- needed. Results are logged to `~/.hermes/luminary/luminary.log`.
96
+ needed. Results are logged to `~/.hermes/luminary/luminary.log`. CLI:
97
+ `luminary-memory health` (human bar) or `--json`.
94
98
 
95
99
  ## Configuration — Tweaks
96
100
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "luminary-memory"
7
- version = "0.2.4"
7
+ version = "0.2.6"
8
8
  description = "A lightweight, self-hosted memory layer for AI agents"
9
9
  readme = "README.md"
10
10
  license = { text = "Apache-2.0" }
@@ -1,4 +1,4 @@
1
1
  from luminary_memory.api import MemoryClient
2
2
 
3
- __version__ = "0.2.4"
3
+ __version__ = "0.2.6"
4
4
  __all__ = ["MemoryClient", "__version__"]
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import logging
3
4
  from datetime import UTC
4
5
  from typing import TYPE_CHECKING
5
6
 
@@ -11,18 +12,16 @@ from luminary_memory.ingest.llm import LLMEnricher, NoopEnricher
11
12
  from luminary_memory.ingest.whitelist import WhitelistFilter
12
13
  from luminary_memory.types import Memory, RecallResult
13
14
 
15
+ logger = logging.getLogger(__name__)
14
16
 
15
- def _try_index_graph(backend, memory: Memory) -> None:
16
- import logging
17
17
 
18
+ def _try_index_graph(backend, memory: Memory) -> None:
18
19
  from luminary_memory.recall.graph import index_memory_entities
19
20
 
20
21
  try:
21
22
  index_memory_entities(backend, memory)
22
23
  except Exception: # noqa: BLE001 -- graph indexing is best-effort; never abort ingest
23
- logging.getLogger(__name__).warning(
24
- "graph indexing failed for memory %s (non-fatal)", memory.id
25
- )
24
+ logger.warning("graph indexing failed for memory %s (non-fatal)", memory.id)
26
25
 
27
26
  if TYPE_CHECKING:
28
27
  from luminary_memory.backends.base import MemoryBackend
@@ -77,6 +76,10 @@ class MemoryClient:
77
76
  ttl_seconds=self.settings.ttl_default_seconds,
78
77
  embedding=self.engine.embed(content),
79
78
  )
79
+ if self.settings.importance_auto:
80
+ from luminary_memory.lifecycle.importance import estimate_importance
81
+
82
+ m.importance = estimate_importance(m)
80
83
  mid = self.backend.add(m)
81
84
  m.id = mid
82
85
  _try_index_graph(self.backend, m)
@@ -250,10 +253,10 @@ class MemoryClient:
250
253
  def count(self) -> int:
251
254
  return self.backend.count()
252
255
 
253
- def run_lifecycle(self) -> dict[str, int]:
256
+ def run_lifecycle(self, semantic: bool | None = None) -> dict[str, int]:
254
257
  from luminary_memory.lifecycle.runner import run_lifecycle
255
258
 
256
- return run_lifecycle(self.backend, self.settings)
259
+ return run_lifecycle(self.backend, self.settings, semantic=semantic)
257
260
 
258
261
  def health_score(self) -> dict:
259
262
  """Store health report: overall 0-100 plus per-dimension breakdown.
@@ -419,7 +422,11 @@ class MemoryClient:
419
422
  """Import memories from *path* (recomputes embeddings when absent)."""
420
423
  from luminary_memory.export import import_memories
421
424
 
422
- return import_memories(self.backend, path, engine=self.engine)
425
+ try:
426
+ return import_memories(self.backend, path, engine=self.engine)
427
+ except Exception:
428
+ logger.exception("import_memories failed for %s", path)
429
+ raise
423
430
 
424
431
  def close(self) -> None:
425
432
  self.backend.close()
@@ -435,7 +442,7 @@ class MemoryClient:
435
442
  if n_limit < 0:
436
443
  raise ValueError("limit must be >= 0 (0 means unlimited)")
437
444
  if n_limit == 0:
438
- n_limit = 10_000 # unlimited — large enough for any realistic store
445
+ n_limit = None # unlimited — backends treat None as "no limit"
439
446
  from luminary_memory.recall.dedup import dedup_jaccard
440
447
  from luminary_memory.recall.fusion import reciprocal_rank_fusion
441
448
  from luminary_memory.recall.graph import graph_recall
@@ -450,6 +457,7 @@ class MemoryClient:
450
457
  planner_threshold = float(getattr(self.settings, "query_planner_keyword_threshold", 0.9))
451
458
 
452
459
  eff = n_limit
460
+ temporal_limit = (eff * 2) if eff is not None else None
453
461
  enabled = None
454
462
 
455
463
  strategies: list[list[tuple]] = []
@@ -457,7 +465,7 @@ class MemoryClient:
457
465
  strat_fns = [
458
466
  ("semantic", lambda: semantic_recall(self.backend, self.engine, query, limit=eff)),
459
467
  ("keyword", lambda: keyword_recall(self.backend, query, limit=eff)),
460
- ("temporal", lambda: temporal_recall(self.backend, limit=eff * 2)),
468
+ ("temporal", lambda: temporal_recall(self.backend, limit=temporal_limit)),
461
469
  ("graph", lambda: graph_recall(self.backend, query, limit=eff)),
462
470
  ]
463
471