hermes-local-rag 1.3.1__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 (47) hide show
  1. hermes_local_rag-1.3.1/.github/workflows/ci.yml +21 -0
  2. hermes_local_rag-1.3.1/.github/workflows/publish-pypi.yml +28 -0
  3. hermes_local_rag-1.3.1/.gitignore +19 -0
  4. hermes_local_rag-1.3.1/LICENSE +21 -0
  5. hermes_local_rag-1.3.1/PKG-INFO +123 -0
  6. hermes_local_rag-1.3.1/README.md +100 -0
  7. hermes_local_rag-1.3.1/assets/branding/local-rag-icon-transparent.png +0 -0
  8. hermes_local_rag-1.3.1/assets/branding/local-rag-icon-transparent.webp +0 -0
  9. hermes_local_rag-1.3.1/assets/branding/local-rag-icon.jpg +0 -0
  10. hermes_local_rag-1.3.1/assets/branding/local-rag-icon.png +0 -0
  11. hermes_local_rag-1.3.1/assets/branding/local-rag-icon.webp +0 -0
  12. hermes_local_rag-1.3.1/assets/branding/local-rag-mark.svg +36 -0
  13. hermes_local_rag-1.3.1/assets/branding/local-rag-preview-1600x900.jpg +0 -0
  14. hermes_local_rag-1.3.1/assets/branding/local-rag-preview-1600x900.png +0 -0
  15. hermes_local_rag-1.3.1/assets/branding/local-rag-preview-1600x900.webp +0 -0
  16. hermes_local_rag-1.3.1/assets/branding/local-rag-social-1280x640.jpg +0 -0
  17. hermes_local_rag-1.3.1/assets/branding/local-rag-social-1280x640.png +0 -0
  18. hermes_local_rag-1.3.1/assets/branding/local-rag-social-1280x640.webp +0 -0
  19. hermes_local_rag-1.3.1/conftest.py +24 -0
  20. hermes_local_rag-1.3.1/install.py +97 -0
  21. hermes_local_rag-1.3.1/local_rag/README.md +57 -0
  22. hermes_local_rag-1.3.1/local_rag/__init__.py +333 -0
  23. hermes_local_rag-1.3.1/local_rag/backfill.py +426 -0
  24. hermes_local_rag-1.3.1/local_rag/chunking.py +25 -0
  25. hermes_local_rag-1.3.1/local_rag/cli.py +236 -0
  26. hermes_local_rag-1.3.1/local_rag/config.py +99 -0
  27. hermes_local_rag-1.3.1/local_rag/dashboard/__init__.py +1 -0
  28. hermes_local_rag-1.3.1/local_rag/dashboard/dist/index.js +301 -0
  29. hermes_local_rag-1.3.1/local_rag/dashboard/dist/style.css +51 -0
  30. hermes_local_rag-1.3.1/local_rag/dashboard/manifest.json +14 -0
  31. hermes_local_rag-1.3.1/local_rag/dashboard/plugin_api.py +503 -0
  32. hermes_local_rag-1.3.1/local_rag/dashboard/src/index.js +301 -0
  33. hermes_local_rag-1.3.1/local_rag/dashboard/src/style.css +51 -0
  34. hermes_local_rag-1.3.1/local_rag/embedder.py +60 -0
  35. hermes_local_rag-1.3.1/local_rag/extraction.py +47 -0
  36. hermes_local_rag-1.3.1/local_rag/plugin.yaml +5 -0
  37. hermes_local_rag-1.3.1/local_rag/policy.py +34 -0
  38. hermes_local_rag-1.3.1/local_rag/service.py +80 -0
  39. hermes_local_rag-1.3.1/local_rag/sessions.py +12 -0
  40. hermes_local_rag-1.3.1/local_rag/store.py +321 -0
  41. hermes_local_rag-1.3.1/local_rag/tests/test_dashboard_api.py +346 -0
  42. hermes_local_rag-1.3.1/local_rag/tests/test_full.py +507 -0
  43. hermes_local_rag-1.3.1/local_rag/tests/test_local_rag.py +497 -0
  44. hermes_local_rag-1.3.1/local_rag/visual.py +62 -0
  45. hermes_local_rag-1.3.1/local_rag/visual_store.py +86 -0
  46. hermes_local_rag-1.3.1/pyproject.toml +48 -0
  47. hermes_local_rag-1.3.1/uv.lock +1078 -0
@@ -0,0 +1,21 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: macos-14
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: astral-sh/setup-uv@v6
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.11"
19
+ - run: uv sync --all-groups
20
+ - run: uv run pytest
21
+ - run: uv build
@@ -0,0 +1,28 @@
1
+ name: publish-pypi
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ publish:
13
+ name: Build and publish to PyPI
14
+ runs-on: ubuntu-latest
15
+ environment:
16
+ name: pypi
17
+ url: https://pypi.org/project/hermes-local-rag/
18
+ permissions:
19
+ contents: read
20
+ id-token: write
21
+ steps:
22
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
23
+ - uses: astral-sh/setup-uv@d0d8abe699bfb85fec6de9f7adb5ae17292296ff # v6
24
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
25
+ with:
26
+ python-version: "3.11"
27
+ - run: uv build
28
+ - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
@@ -0,0 +1,19 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .pytest_cache/
4
+ .venv/
5
+ dist/
6
+ !local_rag/dashboard/dist/
7
+ !local_rag/dashboard/dist/**
8
+ build/
9
+ *.egg-info/
10
+ .DS_Store
11
+ .coverage
12
+ assets/*.zip
13
+
14
+ # Never commit local memory, models, exports, or credentials
15
+ local-rag/
16
+ models/
17
+ *.sqlite*
18
+ *.jsonl
19
+ .env*
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 condr-at
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,123 @@
1
+ Metadata-Version: 2.5
2
+ Name: hermes-local-rag
3
+ Version: 1.3.1
4
+ Summary: Private local hybrid text and visual memory provider for Hermes Agent
5
+ Project-URL: Repository, https://github.com/condr-at/hermes-local-rag
6
+ Project-URL: Issues, https://github.com/condr-at/hermes-local-rag/issues
7
+ Author: condr-at
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
14
+ Requires-Python: >=3.11
15
+ Requires-Dist: ai-edge-litert<3,>=2.1; platform_system == 'Darwin' or platform_system == 'Linux'
16
+ Requires-Dist: huggingface-hub<2,>=0.34
17
+ Requires-Dist: jsonschema<5,>=4
18
+ Requires-Dist: numpy<3,>=2.0
19
+ Requires-Dist: onnxruntime<2,>=1.20
20
+ Requires-Dist: pillow<13,>=11
21
+ Requires-Dist: tokenizers<1,>=0.22
22
+ Description-Content-Type: text/markdown
23
+
24
+ # Hermes Local RAG
25
+
26
+ [![Hermes Local RAG — private local memory that keeps the useful card and bins the noise](https://raw.githubusercontent.com/condr-at/hermes-local-rag/main/assets/branding/local-rag-preview-1600x900.webp)](https://github.com/condr-at/hermes-local-rag)
27
+
28
+ Private, fully local hybrid text and visual memory for [Hermes Agent](https://github.com/NousResearch/hermes-agent), implemented through the official `MemoryProvider` extension point.
29
+
30
+ ## Features
31
+
32
+ - EmbeddingGemma 300M through LiteRT/XNNPACK, with configurable 128/256/512/768-dimensional Matryoshka embeddings (512d default)
33
+ - SQLite + FTS5 + vector similarity, score thresholds, freshness/importance boosts, source diversity, and bounded context injection
34
+ - Physical profile/user namespaces before retrieval
35
+ - Explicit contextual admission through `local_rag_remember`, with normalized atomic items instead of raw turns
36
+ - Selective historical backfill with pre-LLM filtering, structured extraction, resumable preview, human review, and explicit apply
37
+ - Independent scope, durability, status, confidence, importance, provenance, deduplication, deletion, migrations, and backups
38
+ - Project- and session-aware retrieval boundaries; built-in Markdown memory is mirrored as global durable context
39
+ - Project-root-confined text-file indexing with secret and prompt-injection rejection
40
+ - Optional CLIP ViT-B/32 ONNX visual index in a separate 512d vector space
41
+ - Button-driven setup inside Hermes Dashboard; no model server, vector database server, or Hermes core patch
42
+
43
+ ## Install without Terminal
44
+
45
+ Prerequisite: an existing Hermes Agent installation.
46
+
47
+ 1. Open **Hermes Dashboard → Plugins → Install**.
48
+ 2. Install `condr-at/hermes-local-rag/local_rag`.
49
+ 3. Open the new **Local RAG** tab.
50
+ 4. Click **Install dependencies**.
51
+ 5. Open and accept the required Gemma Terms, create a read-only Hugging Face token, paste it into the password field, and click **Sign in**.
52
+ 6. Choose **Text only** or **Text + visual**, then click **Download selected models**.
53
+ 7. Optionally create a historical preview, edit and accept individual candidates, then explicitly apply the reviewed subset.
54
+ 8. Save the memory settings and click **Activate Local RAG**.
55
+ 9. Click **Run health check**.
56
+
57
+ The dashboard never displays or logs the Hugging Face token. Model downloads and setup subprocesses use fixed argument lists and a controlled environment rather than a user shell. Gemma Terms acceptance is explicit and cannot be bypassed by the installer.
58
+
59
+ The setup wizard:
60
+
61
+ 1. installs pinned runtime dependencies into the Hermes venv;
62
+ 2. downloads selected model artifacts to `$HERMES_HOME/models`;
63
+ 3. writes configuration atomically;
64
+ 4. activates `memory.provider=local_rag`;
65
+ 5. checks runtime imports, models, the database, and provider availability.
66
+
67
+ It never deletes `$HERMES_HOME/local-rag`, where indexes and configuration live. Backfill is off by default and requires explicit confirmation.
68
+
69
+ ### Terminal fallback
70
+
71
+ The technical installer remains available for development and recovery:
72
+
73
+ ```bash
74
+ git clone https://github.com/condr-at/hermes-local-rag.git
75
+ cd hermes-local-rag
76
+ python3 install.py
77
+ ```
78
+
79
+ Verify after installation or a Hermes update:
80
+
81
+ ```bash
82
+ python3 install.py --check
83
+ ```
84
+
85
+ Then restart the gateway, or start a new Desktop session.
86
+
87
+ ## Configuration
88
+
89
+ `~/.hermes/local-rag/config.json`:
90
+
91
+ ```json
92
+ {
93
+ "embedding_dimensions": 512,
94
+ "episodic_ttl_days": null,
95
+ "summary_ttl_days": null
96
+ }
97
+ ```
98
+
99
+ `null` means infinite retention. Changing `embedding_dimensions` requires explicit reindexing; startup fails loudly rather than mixing incompatible vectors.
100
+
101
+ ## Backfill
102
+
103
+ Raw transcript backfill is disabled. Historical sessions pass through role filtering, credential and prompt-injection rejection, bounded structured extraction, and strict validation. Preview writes only a mode-`0600` review artifact; every candidate starts rejected, and only explicitly accepted items can be applied. Namespace, project, session, timestamps, and source-message provenance come from the trusted export rather than the model.
104
+
105
+ The Dashboard owns the normal preview → edit/accept → apply flow. The equivalent recovery CLI is:
106
+
107
+ ```bash
108
+ hermes local_rag preview --plan /path/to/review.json
109
+ # Edit only accepted flags/text after reviewing the artifact.
110
+ hermes local_rag apply --plan /path/to/review.json
111
+ ```
112
+
113
+ Preview is resumable by session and never writes the memory database. Re-applying a reviewed plan is idempotent through scope-aware exact deduplication.
114
+
115
+ ## Maintenance
116
+
117
+ The provider exposes tools for status, search, deletion, candidate review, file/session ingestion, pruning, and visual search. A standalone CLI is also installed as `hermes-local-rag`.
118
+
119
+ See [`local_rag/README.md`](local_rag/README.md) for architecture, policies, tools, and recovery details.
120
+
121
+ ## Privacy and licensing
122
+
123
+ No indexed data, model weights, credentials, or session exports belong in this repository. Model weights are downloaded directly from their upstream repositories and retain their own terms. EmbeddingGemma is governed by Gemma Terms. Plugin code is MIT licensed.
@@ -0,0 +1,100 @@
1
+ # Hermes Local RAG
2
+
3
+ [![Hermes Local RAG — private local memory that keeps the useful card and bins the noise](https://raw.githubusercontent.com/condr-at/hermes-local-rag/main/assets/branding/local-rag-preview-1600x900.webp)](https://github.com/condr-at/hermes-local-rag)
4
+
5
+ Private, fully local hybrid text and visual memory for [Hermes Agent](https://github.com/NousResearch/hermes-agent), implemented through the official `MemoryProvider` extension point.
6
+
7
+ ## Features
8
+
9
+ - EmbeddingGemma 300M through LiteRT/XNNPACK, with configurable 128/256/512/768-dimensional Matryoshka embeddings (512d default)
10
+ - SQLite + FTS5 + vector similarity, score thresholds, freshness/importance boosts, source diversity, and bounded context injection
11
+ - Physical profile/user namespaces before retrieval
12
+ - Explicit contextual admission through `local_rag_remember`, with normalized atomic items instead of raw turns
13
+ - Selective historical backfill with pre-LLM filtering, structured extraction, resumable preview, human review, and explicit apply
14
+ - Independent scope, durability, status, confidence, importance, provenance, deduplication, deletion, migrations, and backups
15
+ - Project- and session-aware retrieval boundaries; built-in Markdown memory is mirrored as global durable context
16
+ - Project-root-confined text-file indexing with secret and prompt-injection rejection
17
+ - Optional CLIP ViT-B/32 ONNX visual index in a separate 512d vector space
18
+ - Button-driven setup inside Hermes Dashboard; no model server, vector database server, or Hermes core patch
19
+
20
+ ## Install without Terminal
21
+
22
+ Prerequisite: an existing Hermes Agent installation.
23
+
24
+ 1. Open **Hermes Dashboard → Plugins → Install**.
25
+ 2. Install `condr-at/hermes-local-rag/local_rag`.
26
+ 3. Open the new **Local RAG** tab.
27
+ 4. Click **Install dependencies**.
28
+ 5. Open and accept the required Gemma Terms, create a read-only Hugging Face token, paste it into the password field, and click **Sign in**.
29
+ 6. Choose **Text only** or **Text + visual**, then click **Download selected models**.
30
+ 7. Optionally create a historical preview, edit and accept individual candidates, then explicitly apply the reviewed subset.
31
+ 8. Save the memory settings and click **Activate Local RAG**.
32
+ 9. Click **Run health check**.
33
+
34
+ The dashboard never displays or logs the Hugging Face token. Model downloads and setup subprocesses use fixed argument lists and a controlled environment rather than a user shell. Gemma Terms acceptance is explicit and cannot be bypassed by the installer.
35
+
36
+ The setup wizard:
37
+
38
+ 1. installs pinned runtime dependencies into the Hermes venv;
39
+ 2. downloads selected model artifacts to `$HERMES_HOME/models`;
40
+ 3. writes configuration atomically;
41
+ 4. activates `memory.provider=local_rag`;
42
+ 5. checks runtime imports, models, the database, and provider availability.
43
+
44
+ It never deletes `$HERMES_HOME/local-rag`, where indexes and configuration live. Backfill is off by default and requires explicit confirmation.
45
+
46
+ ### Terminal fallback
47
+
48
+ The technical installer remains available for development and recovery:
49
+
50
+ ```bash
51
+ git clone https://github.com/condr-at/hermes-local-rag.git
52
+ cd hermes-local-rag
53
+ python3 install.py
54
+ ```
55
+
56
+ Verify after installation or a Hermes update:
57
+
58
+ ```bash
59
+ python3 install.py --check
60
+ ```
61
+
62
+ Then restart the gateway, or start a new Desktop session.
63
+
64
+ ## Configuration
65
+
66
+ `~/.hermes/local-rag/config.json`:
67
+
68
+ ```json
69
+ {
70
+ "embedding_dimensions": 512,
71
+ "episodic_ttl_days": null,
72
+ "summary_ttl_days": null
73
+ }
74
+ ```
75
+
76
+ `null` means infinite retention. Changing `embedding_dimensions` requires explicit reindexing; startup fails loudly rather than mixing incompatible vectors.
77
+
78
+ ## Backfill
79
+
80
+ Raw transcript backfill is disabled. Historical sessions pass through role filtering, credential and prompt-injection rejection, bounded structured extraction, and strict validation. Preview writes only a mode-`0600` review artifact; every candidate starts rejected, and only explicitly accepted items can be applied. Namespace, project, session, timestamps, and source-message provenance come from the trusted export rather than the model.
81
+
82
+ The Dashboard owns the normal preview → edit/accept → apply flow. The equivalent recovery CLI is:
83
+
84
+ ```bash
85
+ hermes local_rag preview --plan /path/to/review.json
86
+ # Edit only accepted flags/text after reviewing the artifact.
87
+ hermes local_rag apply --plan /path/to/review.json
88
+ ```
89
+
90
+ Preview is resumable by session and never writes the memory database. Re-applying a reviewed plan is idempotent through scope-aware exact deduplication.
91
+
92
+ ## Maintenance
93
+
94
+ The provider exposes tools for status, search, deletion, candidate review, file/session ingestion, pruning, and visual search. A standalone CLI is also installed as `hermes-local-rag`.
95
+
96
+ See [`local_rag/README.md`](local_rag/README.md) for architecture, policies, tools, and recovery details.
97
+
98
+ ## Privacy and licensing
99
+
100
+ No indexed data, model weights, credentials, or session exports belong in this repository. Model weights are downloaded directly from their upstream repositories and retain their own terms. EmbeddingGemma is governed by Gemma Terms. Plugin code is MIT licensed.
@@ -0,0 +1,36 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" role="img" aria-labelledby="title desc">
2
+ <title id="title">Local RAG memory drawer</title>
3
+ <desc id="desc">A dark archive drawer holding an ivory memory card, with an amber node mark and a rejected crumpled note.</desc>
4
+ <defs>
5
+ <linearGradient id="body" x1="0" y1="0" x2="1" y2="1">
6
+ <stop offset="0" stop-color="#343330"/>
7
+ <stop offset="1" stop-color="#151615"/>
8
+ </linearGradient>
9
+ <linearGradient id="paper" x1="0" y1="0" x2="0" y2="1">
10
+ <stop offset="0" stop-color="#fff4da"/>
11
+ <stop offset="1" stop-color="#e9d7b5"/>
12
+ </linearGradient>
13
+ <filter id="shadow" x="-30%" y="-30%" width="160%" height="180%">
14
+ <feDropShadow dx="0" dy="18" stdDeviation="18" flood-color="#000" flood-opacity=".28"/>
15
+ </filter>
16
+ </defs>
17
+ <g filter="url(#shadow)">
18
+ <rect x="89" y="78" width="334" height="340" rx="44" fill="url(#body)"/>
19
+ <rect x="119" y="116" width="274" height="224" rx="26" fill="#0e0f0e"/>
20
+ <rect x="139" y="137" width="234" height="170" rx="24" fill="url(#paper)"/>
21
+ <rect x="112" y="249" width="288" height="180" rx="27" fill="url(#body)" stroke="#4a4843" stroke-width="5"/>
22
+ <path d="M112 268h95c10 0 12 28 28 28h42c16 0 18-28 28-28h95v-19H112z" fill="#232321"/>
23
+ <rect x="188" y="334" width="136" height="44" rx="10" fill="#101110" stroke="#535049" stroke-width="5"/>
24
+ <circle cx="256" cy="403" r="17" fill="#252522" stroke="#55524c" stroke-width="4"/>
25
+ </g>
26
+ <g fill="none" stroke="#d98b14" stroke-width="10" stroke-linecap="round" stroke-linejoin="round">
27
+ <path d="M286 191l-34 49m34-49l38 49m-72 0h72"/>
28
+ <circle cx="286" cy="181" r="14" fill="#fff4da"/>
29
+ <circle cx="245" cy="249" r="14" fill="#fff4da"/>
30
+ <circle cx="331" cy="249" r="14" fill="#fff4da"/>
31
+ </g>
32
+ <g transform="translate(405 295) rotate(8)">
33
+ <path d="M0 20l19-18 17 12 17-8 12 22-12 17 7 19-23 10-15-12-22 5-8-23z" fill="#e8d8ba" stroke="#c7b28d" stroke-width="4"/>
34
+ <path d="M5 24l17 15 14-21 15 29" fill="none" stroke="#baa27b" stroke-width="3"/>
35
+ </g>
36
+ </svg>
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+ import shutil
4
+ import sys
5
+ import types
6
+
7
+ try:
8
+ import agent.memory_provider # noqa: F401
9
+ except ImportError:
10
+ agent = types.ModuleType("agent")
11
+ memory_provider = types.ModuleType("agent.memory_provider")
12
+
13
+ class MemoryProvider:
14
+ pass
15
+
16
+ memory_provider.MemoryProvider = MemoryProvider
17
+ agent.memory_provider = memory_provider
18
+ sys.modules["agent"] = agent
19
+ sys.modules["agent.memory_provider"] = memory_provider
20
+
21
+
22
+ def pytest_sessionfinish(session, exitstatus):
23
+ for name in (".pytest_cache",):
24
+ shutil.rmtree(name, ignore_errors=True)
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import os
6
+ import shutil
7
+ import subprocess
8
+ import sys
9
+ from pathlib import Path
10
+
11
+
12
+ TEXT_REPO = "litert-community/embeddinggemma-300m"
13
+ TEXT_FILES = ["embeddinggemma-300M_seq512_mixed-precision.tflite"]
14
+ TOKENIZER_REPO = "google/embeddinggemma-300m"
15
+ TOKENIZER_FILES = ["tokenizer.json", "tokenizer_config.json", "special_tokens_map.json"]
16
+ VISUAL_REPO = "Xenova/clip-vit-base-patch32"
17
+ VISUAL_FILES = [
18
+ "onnx/vision_model_quantized.onnx",
19
+ "onnx/text_model_quantized.onnx",
20
+ "tokenizer.json",
21
+ "tokenizer_config.json",
22
+ "config.json",
23
+ "preprocessor_config.json",
24
+ ]
25
+
26
+
27
+ def run(command: list[str], **kwargs) -> None:
28
+ print("+", " ".join(command))
29
+ subprocess.run(command, check=True, **kwargs)
30
+
31
+
32
+ def main() -> int:
33
+ parser = argparse.ArgumentParser(description="Install Hermes Local RAG without touching the Hermes checkout")
34
+ parser.add_argument("--home", default=os.environ.get("HERMES_HOME", str(Path.home() / ".hermes")))
35
+ parser.add_argument("--skip-models", action="store_true", help="Install code and dependencies without downloading model artifacts")
36
+ parser.add_argument("--check", action="store_true", help="Only verify an existing installation")
37
+ args = parser.parse_args()
38
+
39
+ home = Path(args.home).expanduser().resolve()
40
+ checkout = home / "hermes-agent"
41
+ python = Path(os.environ.get("HERMES_PYTHON", checkout / "venv" / "bin" / "python"))
42
+ hermes = shutil.which("hermes")
43
+ if not python.is_file() or not hermes:
44
+ raise SystemExit("Hermes installation not found. Install Hermes Agent first or set HERMES_HOME/HERMES_PYTHON.")
45
+
46
+ plugin_target = home / "plugins" / "local_rag"
47
+ text_target = home / "models" / "embeddinggemma-litert"
48
+ visual_target = home / "models" / "clip-onnx"
49
+ required = [plugin_target / "plugin.yaml", text_target / TEXT_FILES[0], visual_target / VISUAL_FILES[0], visual_target / VISUAL_FILES[1]]
50
+ if args.check:
51
+ missing = [str(path) for path in required if not path.exists()]
52
+ run([hermes, "memory", "status"])
53
+ if missing:
54
+ raise SystemExit("Missing installation artifacts:\n" + "\n".join(missing))
55
+ env = {**os.environ, "PYTHONPATH": str(home / "plugins")}
56
+ run([str(python), "-c", "from local_rag import LocalRagProvider; assert LocalRagProvider().is_available()"], env=env)
57
+ print("Hermes Local RAG installation is healthy.")
58
+ return 0
59
+
60
+ uv = shutil.which("uv")
61
+ if not uv:
62
+ raise SystemExit("uv is required because Hermes venvs may not include pip")
63
+ repository = Path(__file__).resolve().parent
64
+ run([uv, "pip", "install", "--python", str(python), str(repository)])
65
+
66
+ plugin_target.parent.mkdir(parents=True, exist_ok=True)
67
+ temporary = plugin_target.with_name("local_rag.installing")
68
+ shutil.rmtree(temporary, ignore_errors=True)
69
+ shutil.copytree(repository / "local_rag", temporary, ignore=shutil.ignore_patterns("__pycache__", "*.pyc"))
70
+ if plugin_target.exists():
71
+ backup = plugin_target.with_name("local_rag.previous")
72
+ shutil.rmtree(backup, ignore_errors=True)
73
+ plugin_target.replace(backup)
74
+ temporary.replace(plugin_target)
75
+
76
+ if not args.skip_models:
77
+ hf = python.parent / "hf"
78
+ if not hf.is_file():
79
+ raise SystemExit("Hugging Face CLI was not installed into the Hermes venv")
80
+ text_target.mkdir(parents=True, exist_ok=True)
81
+ visual_target.mkdir(parents=True, exist_ok=True)
82
+ try:
83
+ run([str(hf), "download", TEXT_REPO, *TEXT_FILES, "--local-dir", str(text_target)])
84
+ run([str(hf), "download", TOKENIZER_REPO, *TOKENIZER_FILES, "--local-dir", str(text_target)])
85
+ run([str(hf), "download", VISUAL_REPO, *VISUAL_FILES, "--local-dir", str(visual_target)])
86
+ except subprocess.CalledProcessError as exc:
87
+ raise SystemExit(
88
+ "Model download failed. EmbeddingGemma is gated: accept Gemma Terms on Hugging Face and run `hf auth login`, then rerun install.py."
89
+ ) from exc
90
+
91
+ run([hermes, "config", "set", "memory.provider", "local_rag"])
92
+ print("Installed. Restart the Hermes gateway or start a new Desktop session, then run: python install.py --check")
93
+ return 0
94
+
95
+
96
+ if __name__ == "__main__":
97
+ raise SystemExit(main())
@@ -0,0 +1,57 @@
1
+ # Hermes Local RAG
2
+
3
+ User-local `MemoryProvider` for private hybrid recall. It lives outside the Hermes checkout and survives normal updates.
4
+
5
+ ## Storage and isolation
6
+
7
+ - Text: `~/.hermes/local-rag/memory.sqlite` (SQLite WAL + FTS5 + local vectors)
8
+ - Images: `~/.hermes/local-rag/visual.sqlite`
9
+ - Namespace: `<profile>:<platform-user>`, with Desktop/CLI mapped to `<profile>:local`
10
+ - Model weights are shared read-only; records are always filtered by namespace before ranking.
11
+
12
+ ## Models
13
+
14
+ - Text: EmbeddingGemma 300M LiteRT `seq512`, 512-dimensional Matryoshka output by default; configurable to 128/256/512/768.
15
+ - Visual: quantized CLIP ViT-B/32 ONNX, 512 dimensions. Loaded lazily only for visual tools.
16
+
17
+ The 512-token artifact is intentional. Normal chunks are at most 384 words with 64-word overlap; context injection has a separate 3,200-character hard budget. A 2048-token model would increase interactive work without improving these bounded chunks.
18
+
19
+ Model weights are not distributed by this plugin. EmbeddingGemma remains subject to Gemma Terms; CLIP artifacts retain their upstream license.
20
+
21
+ ## Dashboard setup
22
+
23
+ After installing the plugin from **Hermes Dashboard → Plugins**, open the **Local RAG** tab. The wizard installs dependencies, accepts a read-only Hugging Face token through a local password field, downloads the selected models, saves retention and embedding settings, activates the provider, and performs a health check. No Terminal is required for the normal path.
24
+
25
+ The token is passed directly to `huggingface_hub.login`, is never placed in a subprocess argument, response, config file, or setup log, and remains governed by Hugging Face's credential storage. Gemma Terms must still be accepted by the user in the browser.
26
+
27
+ ## Ingestion
28
+
29
+ - User turns and session summaries are retained indefinitely by default.
30
+ - `~/.hermes/local-rag/config.json` can set `episodic_ttl_days` and `summary_ttl_days` to positive day counts; `null` means no expiry.
31
+ - Explicit preferences, decisions, and environment statements enter a review queue.
32
+ - Approved candidates and built-in Hermes memory writes become durable records.
33
+ - Assistant claims and raw tool output are never promoted as user facts.
34
+ - Secret-like content, `.env`, private keys, unsupported/binary files, oversized files, and paths outside the current project root are rejected before embedding.
35
+
36
+ ## Retrieval
37
+
38
+ Hybrid ranking combines semantic similarity, FTS5 exact matches, importance, freshness, and a durable-memory boost. Low-scoring matches are omitted. Context injection includes provenance, limits repeated sources, and labels all retrieved text as untrusted data rather than instructions.
39
+
40
+ ## Agent tools
41
+
42
+ `local_rag_remember`, `local_rag_search`, `local_rag_status`, `local_rag_forget`, `local_rag_review`, `local_rag_approve`, `local_rag_reject`, `local_rag_index_file`, `local_rag_prune`, `local_rag_index_image`, `local_rag_search_images`, `local_rag_forget_image`.
43
+
44
+ ## Maintenance CLI
45
+
46
+ From the Hermes checkout:
47
+
48
+ ```sh
49
+ PYTHONPATH="$HOME/.hermes/plugins" venv/bin/python -m local_rag.cli status
50
+ PYTHONPATH="$HOME/.hermes/plugins" venv/bin/python -m local_rag.cli --namespace default:local search "query"
51
+ ```
52
+
53
+ Raw transcript backfill is disabled. Historical sessions must first undergo selective semantic extraction into normalized memory items; raw user turns, assistant output, and extractive summaries are never indexed automatically.
54
+
55
+ ## Recovery
56
+
57
+ Hermes backup discovers `local-rag/` through `backup_paths()`. Schema upgrades create `memory.pre-v2.sqlite` before the first v2 migration. A changed embedding dimension stops startup with an explicit reindex error instead of corrupting existing vectors.