luminary-memory 0.2.2__tar.gz → 0.2.4__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.2 → luminary_memory-0.2.4}/CHANGELOG.md +24 -1
  2. luminary_memory-0.2.4/PKG-INFO +176 -0
  3. luminary_memory-0.2.4/PLAN-v0.2.4.md +128 -0
  4. luminary_memory-0.2.4/README.md +142 -0
  5. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/docs/api.md +1 -1
  6. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/docs/hermes-integration.md +1 -0
  7. luminary_memory-0.2.4/docs/lifecycle.md +108 -0
  8. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/hermes/README.md +19 -0
  9. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/hermes/SKILL.md +17 -0
  10. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/hermes/hooks/luminary-activity/handler.py +45 -18
  11. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/hermes/install.sh +21 -15
  12. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/pyproject.toml +1 -1
  13. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/__init__.py +1 -1
  14. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/api.py +155 -0
  15. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/cli.py +26 -0
  16. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/hermes/config.py +1 -0
  17. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/hermes/config_schema.py +2 -1
  18. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/hermes/provider.py +7 -1
  19. luminary_memory-0.2.4/src/luminary_memory/ingest/llm.py +202 -0
  20. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/hermes/test_config.py +26 -0
  21. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/hermes/test_hooks.py +28 -0
  22. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/hermes/test_lifecycle.py +33 -0
  23. luminary_memory-0.2.4/tests/hermes/test_session_boundaries.py +128 -0
  24. luminary_memory-0.2.4/tests/hermes/test_sync_turn.py +137 -0
  25. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/hermes/test_tools.py +34 -0
  26. luminary_memory-0.2.4/tests/test_api.py +184 -0
  27. luminary_memory-0.2.4/tests/test_api_extended.py +371 -0
  28. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_cli.py +49 -0
  29. luminary_memory-0.2.4/tests/test_ingest_llm.py +177 -0
  30. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/website/index.html +24 -14
  31. luminary_memory-0.2.2/PKG-INFO +0 -271
  32. luminary_memory-0.2.2/README.md +0 -237
  33. luminary_memory-0.2.2/docs/lifecycle.md +0 -31
  34. luminary_memory-0.2.2/src/luminary_memory/ingest/llm.py +0 -149
  35. luminary_memory-0.2.2/tests/hermes/test_session_boundaries.py +0 -67
  36. luminary_memory-0.2.2/tests/hermes/test_sync_turn.py +0 -73
  37. luminary_memory-0.2.2/tests/test_api.py +0 -68
  38. luminary_memory-0.2.2/tests/test_api_extended.py +0 -83
  39. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  40. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  41. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  42. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/.github/workflows/ci.yml +0 -0
  43. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/.github/workflows/pages.yml +0 -0
  44. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/.github/workflows/publish.yml +0 -0
  45. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/.gitignore +0 -0
  46. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/CODE_OF_CONDUCT.md +0 -0
  47. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/CONTRIBUTING.md +0 -0
  48. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/LICENSE +0 -0
  49. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/PLAN-v0.2.0.md +0 -0
  50. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/PLAN-v0.2.1.md +0 -0
  51. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/PLAN.md +0 -0
  52. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/ROADMAP.md +0 -0
  53. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/SECURITY.md +0 -0
  54. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/benchmarks/README.md +0 -0
  55. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/benchmarks/RESULTS.md +0 -0
  56. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/benchmarks/__init__.py +0 -0
  57. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/benchmarks/hermes_provider_bench.py +0 -0
  58. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/benchmarks/metrics.py +0 -0
  59. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/benchmarks/run_benchmarks.py +0 -0
  60. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/benchmarks/synthetic.py +0 -0
  61. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/docs/architecture.md +0 -0
  62. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/docs/backends.md +0 -0
  63. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/docs/cli.md +0 -0
  64. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/docs/index.md +0 -0
  65. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/docs/quickstart.md +0 -0
  66. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/docs/recall.md +0 -0
  67. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/hermes/hooks/luminary-activity/HOOK.yaml +0 -0
  68. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/hermes/hooks/luminary-activity/README.md +0 -0
  69. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/backends/__init__.py +0 -0
  70. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/backends/base.py +0 -0
  71. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/backends/pgvector.py +0 -0
  72. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/backends/sqlite.py +0 -0
  73. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/budget.py +0 -0
  74. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/config.py +0 -0
  75. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/embeddings/__init__.py +0 -0
  76. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/embeddings/fastembed.py +0 -0
  77. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/export.py +0 -0
  78. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/hermes/__init__.py +0 -0
  79. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/hermes/plugin.yaml +0 -0
  80. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/ingest/__init__.py +0 -0
  81. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/ingest/whitelist.py +0 -0
  82. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/lifecycle/__init__.py +0 -0
  83. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/lifecycle/cleanup.py +0 -0
  84. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/lifecycle/consolidate.py +0 -0
  85. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/lifecycle/prune.py +0 -0
  86. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/lifecycle/runner.py +0 -0
  87. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/recall/__init__.py +0 -0
  88. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/recall/dedup.py +0 -0
  89. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/recall/fusion.py +0 -0
  90. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/recall/graph.py +0 -0
  91. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/recall/keyword.py +0 -0
  92. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/recall/planner.py +0 -0
  93. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/recall/semantic.py +0 -0
  94. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/recall/snippets.py +0 -0
  95. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/recall/temporal.py +0 -0
  96. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/schema.py +0 -0
  97. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/src/luminary_memory/types.py +0 -0
  98. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/__init__.py +0 -0
  99. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/conftest.py +0 -0
  100. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/hermes/test_backup_paths.py +0 -0
  101. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/hermes/test_entrypoint.py +0 -0
  102. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/hermes/test_provider_import.py +0 -0
  103. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/hermes/test_recall.py +0 -0
  104. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/hermes/test_system_prompt.py +0 -0
  105. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/hermes_stubs/agent/memory_provider.py +0 -0
  106. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_backend_pgvector.py +0 -0
  107. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_backend_sqlite.py +0 -0
  108. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_budget.py +0 -0
  109. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_dedup_jaccard.py +0 -0
  110. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_embeddings.py +0 -0
  111. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_fusion_rrf.py +0 -0
  112. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_ingest_whitelist.py +0 -0
  113. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_lifecycle.py +0 -0
  114. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_recall_graph.py +0 -0
  115. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_recall_keyword.py +0 -0
  116. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_recall_orchestrator.py +0 -0
  117. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_recall_semantic.py +0 -0
  118. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_recall_temporal.py +0 -0
  119. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_schema.py +0 -0
  120. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_t10_export.py +0 -0
  121. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_t11_limit_zero.py +0 -0
  122. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_t1_hnsw.py +0 -0
  123. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_t3_planner.py +0 -0
  124. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_t4_batch.py +0 -0
  125. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_t5_enricher.py +0 -0
  126. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_t6_tag_scoped.py +0 -0
  127. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_t7_updated_at.py +0 -0
  128. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_t8_snippets.py +0 -0
  129. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/tests/test_t9_cli_json.py +0 -0
  130. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/website/.nojekyll +0 -0
  131. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/website/css/luminary.css +0 -0
  132. {luminary_memory-0.2.2 → luminary_memory-0.2.4}/website/js/luminary.js +0 -0
@@ -2,6 +2,28 @@
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.4] - 2026-08-18
6
+
7
+ ### Added
8
+
9
+ - **`MemoryClient.health_score()`** — store health report (0-100) across five dimensions: duplicate rate, staleness, importance, graph density, and size — plus actionable recommendations. Empty store scores 100.
10
+ - **`luminary-memory health` CLI** — human-readable bar + `--json` output.
11
+ - **Test coverage raised 82% → 90%** (roadmap DoD): config_schema standalone shim, enricher `_call_llm`/`review_memories` paths, maintenance CRUD edges, provider lifecycle/maintenance/shutdown, CLI whitelist/limit errors, recall strategy failure fallbacks.
12
+
13
+ ### Fixed
14
+
15
+ - **`run_maintenance` bad-response detection** — `data.get("actions") or []` masked non-list responses as "no actions"; now correctly reports `{"error": "bad LLM response"}`.
16
+
17
+ ## [0.2.3] - 2026-08-18
18
+
19
+ ### Added
20
+
21
+ - **Hermes dashboard config schema** — exposes 18 luminary settings (mode, backend, recall limit, token budget, auto-recall/retain, **LLM memory curation**, **auto-maintain**, LLM endpoint, indicators) in the Hermes dashboard Provider panel. `auto_maintain` added; `ingest_llm` label corrected to "LLM memory curation".
22
+
23
+ ### Changed
24
+
25
+ - **Balanced LLM curation** — the enricher now rejects work/task logs and meta-talk about the memory system itself, while still keeping durable facts (not over-strict). Verified: work logs → `worth_saving: false`; facts → stored.
26
+
5
27
  ## [0.2.2] - 2026-08-18
6
28
 
7
29
  ### Added
@@ -10,7 +32,8 @@ All notable changes to this project are documented in this file. The format foll
10
32
  - `worth_saving` — chit-chat, greetings, and trivial turns are **dropped** instead of polluting the store.
11
33
  - `summary` — kept turns are stored as concise factual summaries (e.g. `"Deploy target is the staging cluster."`) instead of raw `User: ... / Assistant: ...` transcripts.
12
34
  - `entities` / `tags` — attached for richer recall.
13
- - **Transparency log** — provider writes `$HERMES_HOME/luminary/luminary.log` recording initialize/recall/retain/errors.
35
+ - **LLM store maintenance** — `MemoryClient.run_maintenance()` + provider `auto_maintain` (session-end): the LLM reviews the store and **deletes obsolete/contradicted/duplicate facts**, **updates changed ones**, and **keeps** current ones (verified: stale deploy target auto-removed).
36
+ - **Transparency log** — provider writes `$HERMES_HOME/luminary/luminary.log` recording initialize/recall/retain/maintenance/errors.
14
37
  - **`OpenAICompatibleEnricher` User-Agent header** — required by some OpenAI-compatible gateways (e.g. Command Code 403s without it).
15
38
 
16
39
  ### Fixed
@@ -0,0 +1,176 @@
1
+ Metadata-Version: 2.5
2
+ Name: luminary-memory
3
+ Version: 0.2.4
4
+ Summary: A lightweight, self-hosted memory layer for AI agents
5
+ Project-URL: Homepage, https://github.com/alertxsto/luminary-memory
6
+ Project-URL: Repository, https://github.com/alertxsto/luminary-memory
7
+ Project-URL: Documentation, https://github.com/alertxsto/luminary-memory#readme
8
+ Author: Dwiky Candra
9
+ License: Apache-2.0
10
+ License-File: LICENSE
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: Apache Software License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
+ Classifier: Topic :: Software Development :: Libraries
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: fastembed>=0.4.0
21
+ Requires-Dist: numpy>=1.26
22
+ Requires-Dist: pgvector>=0.2.5
23
+ Requires-Dist: psycopg[binary]>=3.1
24
+ Requires-Dist: rich>=13.0
25
+ Requires-Dist: typer>=0.12
26
+ Provides-Extra: dev
27
+ Requires-Dist: build>=1.0; extra == 'dev'
28
+ Requires-Dist: pdoc>=14; extra == 'dev'
29
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
30
+ Requires-Dist: pytest>=8.0; extra == 'dev'
31
+ Requires-Dist: ruff>=0.4; extra == 'dev'
32
+ Provides-Extra: hermes
33
+ Description-Content-Type: text/markdown
34
+
35
+ # 🌙 luminary-memory
36
+
37
+ **A lightweight, self-hosted memory layer for AI agents.**
38
+
39
+ [![PyPI version](https://img.shields.io/pypi/v/luminary-memory?color=8ab4e8&label=PyPI)](https://pypi.org/project/luminary-memory)
40
+ [![Python](https://img.shields.io/pypi/pyversions/luminary-memory?color=8ab4e8)](https://pypi.org/project/luminary-memory)
41
+ [![License](https://img.shields.io/github/license/alertxsto/luminary-memory?color=8ab4e8)](LICENSE)
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)
45
+ [![Stars](https://img.shields.io/github/stars/alertxsto/luminary-memory?color=8ab4e8)](https://github.com/alertxsto/luminary-memory)
46
+
47
+ **Self-hosted · Private · Budget-aware · Self-maintaining**
48
+
49
+ ---
50
+
51
+ ## What your agent remembers is what it becomes.
52
+
53
+ Agents are only as good as what they remember. A stateless agent re-learns the same context every session — paying the same tokens, making the same mistakes. luminary-memory closes that gap with a local memory store that persists between runs, retrieves the right context on demand, and keeps itself tidy over time.
54
+
55
+ **Four retrieval strategies. One fused answer. Zero cloud.**
56
+
57
+ - **Semantic** — ONNX embeddings (384-dim, CPU, no GPU needed)
58
+ - **Keyword** — FTS5 BM25 (SQLite, zero config)
59
+ - **Temporal** — recency decay × access count
60
+ - **Graph** — entity co-occurrence with automatic curation
61
+
62
+ Strategies run in parallel and fuse via **Reciprocal Rank Fusion (k=60)** → **Jaccard deduplication (0.85)** → **token budget (4096)**.
63
+
64
+ ---
65
+
66
+ ## Quickstart
67
+
68
+ ```bash
69
+ pip install luminary-memory
70
+ ```
71
+
72
+ ```python
73
+ from luminary_memory import MemoryClient
74
+
75
+ client = MemoryClient(db_path="memory.db")
76
+
77
+ # store a durable fact
78
+ client.ingest("The deploy target is the staging cluster", tags=["deploy", "infra"])
79
+
80
+ # recall — four strategies fused into one ranked answer
81
+ result = client.recall("where do we deploy?")
82
+ for memory, score in zip(result.memories, result.scores):
83
+ print(f"{score:.3f} {memory.content}")
84
+ # → 0.942 The deploy target is the staging cluster
85
+ ```
86
+
87
+ ```bash
88
+ # CLI
89
+ luminary-memory add "deploy target is staging" --tags deploy
90
+ luminary-memory recall "where do we deploy?" --json
91
+ luminary-memory list
92
+ luminary-memory lifecycle
93
+ luminary-memory stats
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Hermes Agent — first-class memory provider
99
+
100
+ Drop-in. Install the provider with `pip install "luminary-memory[hermes]"`, then add
101
+ `memory.provider: luminary` to your Hermes config. That's it.
102
+
103
+ From the next session: **auto-recall** injects relevant memories every turn,
104
+ **auto-save** persists completed turns, and the model can call
105
+ `luminary_recall` / `luminary_ingest` / `luminary_list` on demand.
106
+
107
+ Two optional LLM-powered features keep the store sharp:
108
+
109
+ - **`ingest_llm`** — evaluates every turn before saving: drops chit-chat, stores factual summaries instead of raw transcripts.
110
+ - **`auto_maintain`** — reviews the store at session end: keeps current facts, updates changed ones, deletes stale or duplicate ones.
111
+
112
+ 18 settings are exposed in the [Hermes dashboard](https://alertxsto.github.io/luminary-memory) for zero-hassle tuning. See
113
+ [hermes/README.md](hermes/README.md) for the one-shot installer and full configuration.
114
+
115
+ ---
116
+
117
+ ## Configuration
118
+
119
+ Every setting has a `LUMINARY_*` env var or a `Settings` object.
120
+
121
+ | Setting | Env var | Default |
122
+ |---------|---------|---------|
123
+ | `backend` | `LUMINARY_BACKEND` | `sqlite` |
124
+ | `db_path` | `LUMINARY_DB_PATH` | `luminary_memory.db` |
125
+ | `pg_dsn` | `LUMINARY_PG_DSN` | — (pgvector only) |
126
+ | `embedding_model` | `LUMINARY_EMBEDDING_MODEL` | `BAAI/bge-small-en-v1.5` |
127
+ | `embedding_dim` | `LUMINARY_EMBEDDING_DIM` | `384` |
128
+ | `ingest_llm` | `LUMINARY_INGEST_LLM` | `false` |
129
+ | `rrf_k` | `LUMINARY_RRF_K` | `60` |
130
+ | `dedup_jaccard_threshold` | `LUMINARY_DEDUP_JACCARD_THRESHOLD` | `0.85` |
131
+ | `token_budget` | `LUMINARY_TOKEN_BUDGET` | `4096` |
132
+ | `ttl_default_seconds` | `LUMINARY_TTL_DEFAULT_SECONDS` | `null` |
133
+ | `prune_min_importance` | `LUMINARY_PRUNE_MIN_IMPORTANCE` | `0.2` |
134
+ | `consolidate_jaccard_threshold` | `LUMINARY_CONSOLIDATE_JACCARD_THRESHOLD` | `0.9` |
135
+
136
+ See [hermes/SKILL.md](hermes/SKILL.md) for the full provider config table (18 settings).
137
+
138
+ ---
139
+
140
+ ## Architecture
141
+
142
+ ```
143
+ ingest(text) ──► whitelist filter ──► (LLM curation) ──► embed ──► SQLite / pgvector
144
+
145
+ recall(query) ──► semantic │ keyword │ temporal │ graph
146
+ ──► RRF fusion ──► Jaccard dedup ──► token budget ──► ranked results
147
+
148
+ lifecycle() ──► cleanup (TTL) ──► consolidate (near-dupes) ──► prune (low-value)
149
+
150
+ maintenance() ──► LLM reviews store ──► keep │ update │ delete stale facts
151
+ ```
152
+
153
+ Built-in lifecycle keeps the store lean. LLM maintenance (optional) keeps it accurate. `health_score()` gives you a 0-100 checkup with actionable recommendations.
154
+
155
+ ---
156
+
157
+ ## Documentation
158
+
159
+ | Section | |
160
+ |---------|-----|
161
+ | [Quickstart](docs/quickstart.md) | Install and first use |
162
+ | [Architecture](docs/architecture.md) | Pipelines and data flow |
163
+ | [Python API](docs/api.md) | `MemoryClient` reference |
164
+ | [CLI](docs/cli.md) | All subcommands |
165
+ | [Recall](docs/recall.md) | Four strategies + fusion |
166
+ | [Lifecycle](docs/lifecycle.md) | Cleanup, consolidation, pruning, LLM maintenance |
167
+ | [Backends](docs/backends.md) | SQLite vs pgvector |
168
+ | [Hermes integration](docs/hermes-integration.md) | Provider, config, installer |
169
+ | [Roadmap](ROADMAP.md) | v0.2.3 → v1.0.0 |
170
+ | [Benchmarks](benchmarks/RESULTS.md) | 230 ms recall @ 5k, 0 LLM tokens |
171
+
172
+ ---
173
+
174
+ ## License
175
+
176
+ [Apache-2.0](LICENSE) © 2026 Dwiky Candra
@@ -0,0 +1,128 @@
1
+ # PLAN v0.2.4 — Coverage 90% + Health Score
2
+
3
+ **Version:** 0.2.4 · **Milestone:** Quality hardening + health introspection
4
+ **Goal:** Raise test coverage from 82% → ≥90% (roadmap DoD) and ship
5
+ `MemoryClient.health_score()` for store quality monitoring.
6
+
7
+ ---
8
+
9
+ ## Phase 1 — Coverage: test the untested (T1–T5)
10
+
11
+ Targets identified by `pytest --cov --cov-report=term-missing`:
12
+
13
+ | Module | Current | Target | Missing lines to cover |
14
+ |--------|---------|--------|------------------------|
15
+ | `hermes/config_schema.py` | 11% | ≥90% | Standalone fallback shim (no hermes runtime) |
16
+ | `ingest/llm.py` | 68% | ≥90% | `review_memories`, `_call_llm` error/empty paths, enrich failures |
17
+ | `api.py` | 75% | ≥90% | `run_maintenance` actions, `delete`/`update` edges, error handling |
18
+ | `hermes/provider.py` | 81% | ≥90% | maintenance trigger, shutdown, prefetch guards, error paths |
19
+
20
+ ### T1 — config_schema standalone coverage
21
+ - Test: import `config_schema.py` **without** hermes-agent runtime (simulate CI)
22
+ - Assert `CONFIG_SCHEMA` shim exposes `name`, `label`, `storage`, 18 fields
23
+ - Assert `auto_maintain` and `ingest_llm` fields present
24
+
25
+ ### T2 — llm.py enricher paths
26
+ - Test `OpenAICompatibleEnricher.review_memories` with mocked `_call_llm`
27
+ - returns valid actions JSON → parsed
28
+ - returns `{}` → `{"skipped": ...}` handled by caller
29
+ - raises (network) → returns `{}` (best-effort, no crash)
30
+ - Test `_call_llm` with mocked `urlopen`:
31
+ - 200 with choices → content returned
32
+ - 200 empty choices → `""`
33
+ - HTTPError → propagates to caller fallback
34
+ - Test `enrich()` fallback when `base_url` empty → `EnrichedContent(content=text)`
35
+
36
+ ### T3 — api.py maintenance + CRUD edges
37
+ - Test `run_maintenance`:
38
+ - no enricher → `{"skipped": ...}`
39
+ - empty store → `{"reviewed": 0, ...}`
40
+ - enricher returns delete/update/keep actions → applied correctly
41
+ - enricher returns malformed actions (not a list) → `{"error": "bad LLM response"}`
42
+ - enricher returns action for unknown id → skipped
43
+ - Test `update()` with changed content → `updated_at` bumped, embedding recomputed
44
+ - Test `delete()` on non-existent id → graceful (no raise)
45
+
46
+ ### T4 — provider.py lifecycle paths
47
+ - Test `on_session_end` with `auto_maintain=true` + `ingest_llm=true` → `run_maintenance` called, logged
48
+ - Test `on_session_end` with maintenance raising → exception logged, not propagated
49
+ - Test `shutdown` writer-thread close (regression: no SQLite thread-affinity crash)
50
+ - Test prefetch guards: `auto_recall=false`, `mode=tools`, shutdown flag → no prefetch
51
+
52
+ ### T5 — coverage gate
53
+ - Add `--cov-fail-under=90` to CI workflow + `Makefile`/`pyproject` pytest config
54
+ - Verify `pytest -q --cov=luminary_memory` ≥ 90% locally
55
+
56
+ ---
57
+
58
+ ## Phase 2 — Health score (T6–T8)
59
+
60
+ ### T6 — `health_score()` API in `api.py`
61
+
62
+ ```python
63
+ def health_score(self) -> dict:
64
+ """Store health report: overall 0-100 + per-dimension breakdown."""
65
+ ```
66
+
67
+ Dimensions (computed from existing store data — no new schema):
68
+
69
+ | Dimension | Weight | Signal |
70
+ |-----------|--------|--------|
71
+ | `duplicate_rate` | 25% | % memories with a near-dupe (Jaccard > 0.85) — lower better |
72
+ | `staleness` | 25% | % memories not accessed in 30d (decayed) — lower better |
73
+ | `importance` | 20% | % memories above `prune_min_importance` — higher better |
74
+ | `density` | 15% | memories with graph relations / total — higher better |
75
+ | `size` | 15% | store size vs `token_budget` scale (0 = empty, 100 = healthy volume) |
76
+
77
+ Score = weighted sum. Returns:
78
+
79
+ ```python
80
+ {
81
+ "score": 87.5,
82
+ "dimensions": {
83
+ "duplicate_rate": {"value": 0.02, "weight": 0.25, "health": 98.0},
84
+ "staleness": {...}, "importance": {...}, "density": {...}, "size": {...}
85
+ },
86
+ "recommendations": ["2 stale memories older than 30d — run lifecycle prune"]
87
+ }
88
+ ```
89
+
90
+ `recommendations` — generated from low-scoring dimensions (≤70):
91
+ - duplicates → "run lifecycle consolidate"
92
+ - stale → "run lifecycle prune or LLM maintenance"
93
+ - low importance → "raise prune_min_importance or review store"
94
+
95
+ ### T7 — CLI `health` subcommand
96
+
97
+ ```bash
98
+ luminary-memory health --json
99
+ luminary-memory health
100
+ # 📊 Memory Health: 87.5/100
101
+ # • Duplicates: 2.0% ✅
102
+ # • Stale (>30d): 4.0% ✅
103
+ # • Importance: 92% ✅
104
+ # • Graph density: 33% ⚠️
105
+ # • Size: 60% ✅
106
+ # → 2 stale memories — run `luminary-memory lifecycle`
107
+ ```
108
+
109
+ ### T8 — health score tests + docs
110
+
111
+ - Test: empty store → score 0? or 100? (decide: empty store = 100 "nothing wrong" — document)
112
+ - Test: all duplicates → low duplicate_rate dimension
113
+ - Test: all stale → low staleness dimension
114
+ - Test: healthy mixed store → score ≥ 80
115
+ - Test CLI `health` output shape (`--json` parseable)
116
+ - Docs: `docs/lifecycle.md` + README (health section), CHANGELOG entry
117
+
118
+ ---
119
+
120
+ ## Definition of Done (v0.2.4)
121
+
122
+ - [ ] `pytest -q` green (≥90% coverage, CI gate)
123
+ - [ ] `ruff check src tests` clean
124
+ - [ ] CLI smoke: `luminary-memory health` + `--json`
125
+ - [ ] Health score verified against real store (`~/.hermes/luminary/memory.db`)
126
+ - [ ] CHANGELOG 0.2.4 entry
127
+ - [ ] Version bumped to 0.2.4
128
+ - [ ] Tag + GitHub release + PyPI upload (auto-publish)
@@ -0,0 +1,142 @@
1
+ # 🌙 luminary-memory
2
+
3
+ **A lightweight, self-hosted memory layer for AI agents.**
4
+
5
+ [![PyPI version](https://img.shields.io/pypi/v/luminary-memory?color=8ab4e8&label=PyPI)](https://pypi.org/project/luminary-memory)
6
+ [![Python](https://img.shields.io/pypi/pyversions/luminary-memory?color=8ab4e8)](https://pypi.org/project/luminary-memory)
7
+ [![License](https://img.shields.io/github/license/alertxsto/luminary-memory?color=8ab4e8)](LICENSE)
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)
11
+ [![Stars](https://img.shields.io/github/stars/alertxsto/luminary-memory?color=8ab4e8)](https://github.com/alertxsto/luminary-memory)
12
+
13
+ **Self-hosted · Private · Budget-aware · Self-maintaining**
14
+
15
+ ---
16
+
17
+ ## What your agent remembers is what it becomes.
18
+
19
+ Agents are only as good as what they remember. A stateless agent re-learns the same context every session — paying the same tokens, making the same mistakes. luminary-memory closes that gap with a local memory store that persists between runs, retrieves the right context on demand, and keeps itself tidy over time.
20
+
21
+ **Four retrieval strategies. One fused answer. Zero cloud.**
22
+
23
+ - **Semantic** — ONNX embeddings (384-dim, CPU, no GPU needed)
24
+ - **Keyword** — FTS5 BM25 (SQLite, zero config)
25
+ - **Temporal** — recency decay × access count
26
+ - **Graph** — entity co-occurrence with automatic curation
27
+
28
+ Strategies run in parallel and fuse via **Reciprocal Rank Fusion (k=60)** → **Jaccard deduplication (0.85)** → **token budget (4096)**.
29
+
30
+ ---
31
+
32
+ ## Quickstart
33
+
34
+ ```bash
35
+ pip install luminary-memory
36
+ ```
37
+
38
+ ```python
39
+ from luminary_memory import MemoryClient
40
+
41
+ client = MemoryClient(db_path="memory.db")
42
+
43
+ # store a durable fact
44
+ client.ingest("The deploy target is the staging cluster", tags=["deploy", "infra"])
45
+
46
+ # recall — four strategies fused into one ranked answer
47
+ result = client.recall("where do we deploy?")
48
+ for memory, score in zip(result.memories, result.scores):
49
+ print(f"{score:.3f} {memory.content}")
50
+ # → 0.942 The deploy target is the staging cluster
51
+ ```
52
+
53
+ ```bash
54
+ # CLI
55
+ luminary-memory add "deploy target is staging" --tags deploy
56
+ luminary-memory recall "where do we deploy?" --json
57
+ luminary-memory list
58
+ luminary-memory lifecycle
59
+ luminary-memory stats
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Hermes Agent — first-class memory provider
65
+
66
+ Drop-in. Install the provider with `pip install "luminary-memory[hermes]"`, then add
67
+ `memory.provider: luminary` to your Hermes config. That's it.
68
+
69
+ From the next session: **auto-recall** injects relevant memories every turn,
70
+ **auto-save** persists completed turns, and the model can call
71
+ `luminary_recall` / `luminary_ingest` / `luminary_list` on demand.
72
+
73
+ Two optional LLM-powered features keep the store sharp:
74
+
75
+ - **`ingest_llm`** — evaluates every turn before saving: drops chit-chat, stores factual summaries instead of raw transcripts.
76
+ - **`auto_maintain`** — reviews the store at session end: keeps current facts, updates changed ones, deletes stale or duplicate ones.
77
+
78
+ 18 settings are exposed in the [Hermes dashboard](https://alertxsto.github.io/luminary-memory) for zero-hassle tuning. See
79
+ [hermes/README.md](hermes/README.md) for the one-shot installer and full configuration.
80
+
81
+ ---
82
+
83
+ ## Configuration
84
+
85
+ Every setting has a `LUMINARY_*` env var or a `Settings` object.
86
+
87
+ | Setting | Env var | Default |
88
+ |---------|---------|---------|
89
+ | `backend` | `LUMINARY_BACKEND` | `sqlite` |
90
+ | `db_path` | `LUMINARY_DB_PATH` | `luminary_memory.db` |
91
+ | `pg_dsn` | `LUMINARY_PG_DSN` | — (pgvector only) |
92
+ | `embedding_model` | `LUMINARY_EMBEDDING_MODEL` | `BAAI/bge-small-en-v1.5` |
93
+ | `embedding_dim` | `LUMINARY_EMBEDDING_DIM` | `384` |
94
+ | `ingest_llm` | `LUMINARY_INGEST_LLM` | `false` |
95
+ | `rrf_k` | `LUMINARY_RRF_K` | `60` |
96
+ | `dedup_jaccard_threshold` | `LUMINARY_DEDUP_JACCARD_THRESHOLD` | `0.85` |
97
+ | `token_budget` | `LUMINARY_TOKEN_BUDGET` | `4096` |
98
+ | `ttl_default_seconds` | `LUMINARY_TTL_DEFAULT_SECONDS` | `null` |
99
+ | `prune_min_importance` | `LUMINARY_PRUNE_MIN_IMPORTANCE` | `0.2` |
100
+ | `consolidate_jaccard_threshold` | `LUMINARY_CONSOLIDATE_JACCARD_THRESHOLD` | `0.9` |
101
+
102
+ See [hermes/SKILL.md](hermes/SKILL.md) for the full provider config table (18 settings).
103
+
104
+ ---
105
+
106
+ ## Architecture
107
+
108
+ ```
109
+ ingest(text) ──► whitelist filter ──► (LLM curation) ──► embed ──► SQLite / pgvector
110
+
111
+ recall(query) ──► semantic │ keyword │ temporal │ graph
112
+ ──► RRF fusion ──► Jaccard dedup ──► token budget ──► ranked results
113
+
114
+ lifecycle() ──► cleanup (TTL) ──► consolidate (near-dupes) ──► prune (low-value)
115
+
116
+ maintenance() ──► LLM reviews store ──► keep │ update │ delete stale facts
117
+ ```
118
+
119
+ Built-in lifecycle keeps the store lean. LLM maintenance (optional) keeps it accurate. `health_score()` gives you a 0-100 checkup with actionable recommendations.
120
+
121
+ ---
122
+
123
+ ## Documentation
124
+
125
+ | Section | |
126
+ |---------|-----|
127
+ | [Quickstart](docs/quickstart.md) | Install and first use |
128
+ | [Architecture](docs/architecture.md) | Pipelines and data flow |
129
+ | [Python API](docs/api.md) | `MemoryClient` reference |
130
+ | [CLI](docs/cli.md) | All subcommands |
131
+ | [Recall](docs/recall.md) | Four strategies + fusion |
132
+ | [Lifecycle](docs/lifecycle.md) | Cleanup, consolidation, pruning, LLM maintenance |
133
+ | [Backends](docs/backends.md) | SQLite vs pgvector |
134
+ | [Hermes integration](docs/hermes-integration.md) | Provider, config, installer |
135
+ | [Roadmap](ROADMAP.md) | v0.2.3 → v1.0.0 |
136
+ | [Benchmarks](benchmarks/RESULTS.md) | 230 ms recall @ 5k, 0 LLM tokens |
137
+
138
+ ---
139
+
140
+ ## License
141
+
142
+ [Apache-2.0](LICENSE) © 2026 Dwiky Candra
@@ -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`, `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), `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`.
@@ -49,6 +49,7 @@ The provider reads `$HERMES_HOME/luminary/config.json` (created on first save wi
49
49
  | `llm_timeout` | `60` | Enricher request timeout (seconds) |
50
50
  | `recall_indicator` | `true` | Show `🌙 Luminary — recalled N memories` |
51
51
  | `retain_indicator` | `true` | Show `🌙 Luminary — memory saved` |
52
+ | `auto_maintain` | `false` | **LLM store review at session end** — keeps/updates/deletes stale, contradicted, or duplicate facts (requires `ingest_llm`) |
52
53
 
53
54
  ### LLM memory curation (v0.2.2+)
54
55
 
@@ -0,0 +1,108 @@
1
+ # Lifecycle
2
+
3
+ Two maintenance layers keep the store lean: deterministic passes
4
+ (`run_lifecycle()`) and LLM-driven curation (`run_maintenance()`).
5
+
6
+ ## `run_lifecycle()` — deterministic passes
7
+
8
+ ### cleanup — TTL expiry
9
+
10
+ Removes memories whose `ttl_seconds` has elapsed.
11
+
12
+ ### consolidate — merge near-duplicates
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.
15
+
16
+ ### prune — drop low-value memories
17
+
18
+ Removes memories below a minimum importance (`LUMINARY_PRUNE_MIN_IMPORTANCE`, default 0.2).
19
+
20
+ ## `run_maintenance()` — LLM-driven curation (v0.2.2+)
21
+
22
+ Sends the store to the configured LLM enricher, which reviews every memory and
23
+ decides **keep** / **update** / **delete**:
24
+
25
+ - **delete** — obsolete, contradicted, or duplicate facts (e.g. the old
26
+ deploy target after it changed).
27
+ - **update** — facts that changed, with replacement content.
28
+ - **keep** — still-current facts.
29
+
30
+ Requires an LLM enricher (set `ingest_llm: true` + `llm_*` config); no-ops
31
+ otherwise. One LLM call per review run (all memories in a single call).
32
+
33
+ ```python
34
+ client = MemoryClient(db_path="memory.db", enricher=enricher)
35
+ print(client.run_maintenance())
36
+ # {'reviewed': 4, 'deleted': 2, 'updated': 0}
37
+ ```
38
+
39
+ ### Automatic maintenance in the Hermes provider
40
+
41
+ With `auto_maintain: true` in `~/.hermes/luminary/config.json` (plus
42
+ `ingest_llm: true`), the provider runs `run_maintenance()` automatically at
43
+ every session end:
44
+
45
+ ```json
46
+ {
47
+ "ingest_llm": true,
48
+ "llm_base_url": "https://api.commandcode.ai/provider/v1",
49
+ "llm_model": "deepseek/deepseek-v4-flash",
50
+ "llm_api_key": "your-key",
51
+ "auto_maintain": true
52
+ }
53
+ ```
54
+
55
+ Results are recorded in the transparency log
56
+ (`~/.hermes/luminary/luminary.log`): `maintenance {'reviewed': N, 'deleted': N, 'updated': N}`.
57
+
58
+ ## `health_score()` — store health report (v0.2.4+)
59
+
60
+ Returns a 0-100 health score with a per-dimension breakdown, computed from
61
+ existing store data (no new schema):
62
+
63
+ | Dimension | Weight | What it measures |
64
+ |-----------|--------|------------------|
65
+ | `duplicate_rate` | 25% | Share of memories with a near-duplicate (Jaccard > threshold) |
66
+ | `staleness` | 25% | Share of memories not accessed in 30 days |
67
+ | `importance` | 20% | Share of memories above `prune_min_importance` |
68
+ | `density` | 15% | Share of memories with graph relations |
69
+ | `size` | 15% | Store volume (scales toward 100 at ~1k memories) |
70
+
71
+ ```python
72
+ report = client.health_score()
73
+ print(report["score"]) # 87.5
74
+ print(report["recommendations"]) # actionable hints
75
+ ```
76
+
77
+ CLI:
78
+
79
+ ```bash
80
+ luminary-memory health # human-readable bar
81
+ luminary-memory health --json # raw JSON
82
+ ```
83
+
84
+ ```
85
+ 📊 Memory Health: 87.5/100 █████████░
86
+ ✅ duplicate_rate: 98%
87
+ ⚠️ density: 33%
88
+ → 2 stale memories (>30d) — run lifecycle prune or LLM maintenance
89
+ ```
90
+
91
+ Empty store scores 100 (nothing wrong); low-scoring dimensions produce
92
+ recommendations.
93
+
94
+ ## Scheduling
95
+
96
+ Run via cron for a self-maintaining store:
97
+
98
+ ```cron
99
+ 0 4 * * * /usr/local/bin/luminary-memory lifecycle
100
+ ```
101
+
102
+ Or programmatically:
103
+
104
+ ```python
105
+ client = MemoryClient(db_path="memory.db")
106
+ print(client.run_lifecycle())
107
+ client.close()
108
+ ```
@@ -61,6 +61,25 @@ Any OpenAI-compatible endpoint works. Costs one small LLM call per retained
61
61
  turn (temperature 0, strict JSON). If the enricher fails, the provider falls
62
62
  back to storing the turn verbatim — it never blocks.
63
63
 
64
+ ### Store maintenance (auto_maintain)
65
+
66
+ With `auto_maintain: true` (plus `ingest_llm: true`), the provider also
67
+ reviews the store at every session end — the LLM keeps current facts, updates
68
+ changed ones, and **deletes stale, contradicted, or duplicate memories**:
69
+
70
+ ```json
71
+ {
72
+ "ingest_llm": true,
73
+ "llm_base_url": "https://api.commandcode.ai/provider/v1",
74
+ "llm_model": "deepseek/deepseek-v4-flash",
75
+ "llm_api_key": "your-key",
76
+ "auto_maintain": true
77
+ }
78
+ ```
79
+
80
+ Results land in the transparency log:
81
+ `maintenance {'reviewed': N, 'deleted': N, 'updated': N}`.
82
+
64
83
  ## Manual install (no script)
65
84
 
66
85
  ```bash
@@ -76,6 +76,22 @@ client.list(limit=20) # most recent first
76
76
  Use this before re-ingesting — if a fact is already stored, update instead of
77
77
  duplicating.
78
78
 
79
+ ### Store maintenance
80
+
81
+ The store keeps itself clean two ways:
82
+
83
+ ```python
84
+ # deterministic passes (TTL, consolidate, prune)
85
+ client.run_lifecycle()
86
+
87
+ # LLM review: keep current facts, update changed ones, delete stale/duplicates
88
+ client.run_maintenance() # requires an LLM enricher (ingest_llm)
89
+ ```
90
+
91
+ In the Hermes provider, `auto_maintain: true` (plus `ingest_llm: true`) runs
92
+ `run_maintenance()` automatically at every session end — no manual trigger
93
+ needed. Results are logged to `~/.hermes/luminary/luminary.log`.
94
+
79
95
  ## Configuration — Tweaks
80
96
 
81
97
  Provider config lives in `~/.hermes/luminary/config.json` (auto-created,
@@ -92,6 +108,7 @@ Provider config lives in `~/.hermes/luminary/config.json` (auto-created,
92
108
  | `retain_every_n_turns` | `1` | Save every N turns (higher = fewer, batched saves) |
93
109
  | `ingest_llm` | `false` | **LLM memory curation** — drops chit-chat, stores factual summary instead of raw transcript |
94
110
  | `llm_base_url` / `llm_model` / `llm_api_key` | `""` | OpenAI-compatible enricher endpoint/model/key |
111
+ | `auto_maintain` | `false` | **LLM store review at session end** — keeps/updates/deletes stale or duplicate facts (needs `ingest_llm`) |
95
112
  | `recall_indicator` | `true` | Show `🌙 Luminary — recalled N memories` |
96
113
  | `retain_indicator` | `true` | Show `🌙 Luminary — memory saved` |
97
114
  | `backend` | `sqlite` | `sqlite` (zero config) or `pgvector` (scale) |