hermes-plugin-qdrant-memory 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. hermes_plugin_qdrant_memory-0.2.0/LICENSE +21 -0
  2. hermes_plugin_qdrant_memory-0.2.0/MANIFEST.in +6 -0
  3. hermes_plugin_qdrant_memory-0.2.0/PKG-INFO +495 -0
  4. hermes_plugin_qdrant_memory-0.2.0/README.md +476 -0
  5. hermes_plugin_qdrant_memory-0.2.0/hermes_plugin_qdrant_memory.egg-info/PKG-INFO +495 -0
  6. hermes_plugin_qdrant_memory-0.2.0/hermes_plugin_qdrant_memory.egg-info/SOURCES.txt +67 -0
  7. hermes_plugin_qdrant_memory-0.2.0/hermes_plugin_qdrant_memory.egg-info/dependency_links.txt +1 -0
  8. hermes_plugin_qdrant_memory-0.2.0/hermes_plugin_qdrant_memory.egg-info/entry_points.txt +5 -0
  9. hermes_plugin_qdrant_memory-0.2.0/hermes_plugin_qdrant_memory.egg-info/requires.txt +6 -0
  10. hermes_plugin_qdrant_memory-0.2.0/hermes_plugin_qdrant_memory.egg-info/top_level.txt +1 -0
  11. hermes_plugin_qdrant_memory-0.2.0/pyproject.toml +40 -0
  12. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/__init__.py +33 -0
  13. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/cli.py +887 -0
  14. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/config.py +313 -0
  15. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/config_schema.py +111 -0
  16. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/dedupe.py +26 -0
  17. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/embedding.py +114 -0
  18. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/extraction.py +90 -0
  19. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/inventory.py +153 -0
  20. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/ledger.py +686 -0
  21. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/mcp_server.py +57 -0
  22. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/migration.py +525 -0
  23. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/models.py +130 -0
  24. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/ownership.py +48 -0
  25. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/plugin.yaml +13 -0
  26. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/progress.py +89 -0
  27. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/provider.py +568 -0
  28. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/qdrant_store.py +332 -0
  29. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/reset.py +317 -0
  30. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/retry.py +51 -0
  31. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/runtime.py +314 -0
  32. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/standalone.py +203 -0
  33. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/tools.py +81 -0
  34. hermes_plugin_qdrant_memory-0.2.0/qdrant_memory/version.py +3 -0
  35. hermes_plugin_qdrant_memory-0.2.0/scripts/demo.sh +168 -0
  36. hermes_plugin_qdrant_memory-0.2.0/setup.cfg +4 -0
  37. hermes_plugin_qdrant_memory-0.2.0/tests/test_backend_contracts.py +102 -0
  38. hermes_plugin_qdrant_memory-0.2.0/tests/test_bot_scope.py +267 -0
  39. hermes_plugin_qdrant_memory-0.2.0/tests/test_bounded_recovery.py +350 -0
  40. hermes_plugin_qdrant_memory-0.2.0/tests/test_checkpoint_lifecycle.py +133 -0
  41. hermes_plugin_qdrant_memory-0.2.0/tests/test_ci_gate.py +58 -0
  42. hermes_plugin_qdrant_memory-0.2.0/tests/test_cli_output.py +88 -0
  43. hermes_plugin_qdrant_memory-0.2.0/tests/test_config_embedding.py +183 -0
  44. hermes_plugin_qdrant_memory-0.2.0/tests/test_deletion_ordering.py +188 -0
  45. hermes_plugin_qdrant_memory-0.2.0/tests/test_discovery_cli.py +65 -0
  46. hermes_plugin_qdrant_memory-0.2.0/tests/test_host_lifecycle.py +130 -0
  47. hermes_plugin_qdrant_memory-0.2.0/tests/test_input_validation.py +105 -0
  48. hermes_plugin_qdrant_memory-0.2.0/tests/test_inventory_export.py +903 -0
  49. hermes_plugin_qdrant_memory-0.2.0/tests/test_live_metrics.py +38 -0
  50. hermes_plugin_qdrant_memory-0.2.0/tests/test_maintenance.py +263 -0
  51. hermes_plugin_qdrant_memory-0.2.0/tests/test_manifest_contract.py +47 -0
  52. hermes_plugin_qdrant_memory-0.2.0/tests/test_migration.py +177 -0
  53. hermes_plugin_qdrant_memory-0.2.0/tests/test_migration_endpoints.py +143 -0
  54. hermes_plugin_qdrant_memory-0.2.0/tests/test_migration_progress.py +352 -0
  55. hermes_plugin_qdrant_memory-0.2.0/tests/test_migration_resume.py +93 -0
  56. hermes_plugin_qdrant_memory-0.2.0/tests/test_migration_superseded.py +348 -0
  57. hermes_plugin_qdrant_memory-0.2.0/tests/test_profile_scope.py +86 -0
  58. hermes_plugin_qdrant_memory-0.2.0/tests/test_provider.py +104 -0
  59. hermes_plugin_qdrant_memory-0.2.0/tests/test_recovery_benchmark.py +20 -0
  60. hermes_plugin_qdrant_memory-0.2.0/tests/test_recovery_evaluation.py +112 -0
  61. hermes_plugin_qdrant_memory-0.2.0/tests/test_remote_qdrant.py +229 -0
  62. hermes_plugin_qdrant_memory-0.2.0/tests/test_reset_recovery.py +502 -0
  63. hermes_plugin_qdrant_memory-0.2.0/tests/test_retention.py +181 -0
  64. hermes_plugin_qdrant_memory-0.2.0/tests/test_review_regressions.py +208 -0
  65. hermes_plugin_qdrant_memory-0.2.0/tests/test_session_provenance.py +257 -0
  66. hermes_plugin_qdrant_memory-0.2.0/tests/test_setup_contract.py +262 -0
  67. hermes_plugin_qdrant_memory-0.2.0/tests/test_shutdown_contract.py +100 -0
  68. hermes_plugin_qdrant_memory-0.2.0/tests/test_store_runtime.py +113 -0
  69. hermes_plugin_qdrant_memory-0.2.0/tests/test_writer_ownership.py +168 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kang Liu
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,6 @@
1
+ # The demo recording stays in the repository only. It must not increase the
2
+ # download size of the release packages.
3
+ prune assets
4
+
5
+ # The text demo script is small and ships with the source distribution.
6
+ include scripts/demo.sh
@@ -0,0 +1,495 @@
1
+ Metadata-Version: 2.4
2
+ Name: hermes-plugin-qdrant-memory
3
+ Version: 0.2.0
4
+ Summary: Durable Qdrant memory for Hermes, standalone CLI and local MCP
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/cnkang/hermes-plugin-qdrant-memory
7
+ Project-URL: Repository, https://github.com/cnkang/hermes-plugin-qdrant-memory
8
+ Project-URL: Issues, https://github.com/cnkang/hermes-plugin-qdrant-memory/issues
9
+ Project-URL: Changelog, https://github.com/cnkang/hermes-plugin-qdrant-memory/blob/main/CHANGELOG.md
10
+ Requires-Python: >=3.11
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: qdrant-client<2,>=1.15
14
+ Requires-Dist: httpx<1,>=0.28
15
+ Requires-Dist: portalocker<4,>=3.2
16
+ Provides-Extra: mcp
17
+ Requires-Dist: mcp<2,>=1.30; extra == "mcp"
18
+ Dynamic: license-file
19
+
20
+ # Qdrant Memory for Hermes
21
+
22
+ [![CI](https://github.com/cnkang/hermes-plugin-qdrant-memory/actions/workflows/ci.yml/badge.svg)](https://github.com/cnkang/hermes-plugin-qdrant-memory/actions/workflows/ci.yml)
23
+ [![Platform compatibility](https://github.com/cnkang/hermes-plugin-qdrant-memory/actions/workflows/platform-compat.yml/badge.svg)](https://github.com/cnkang/hermes-plugin-qdrant-memory/actions/workflows/platform-compat.yml)
24
+ [![Standalone CLI and MCP](https://github.com/cnkang/hermes-plugin-qdrant-memory/actions/workflows/standalone.yml/badge.svg)](https://github.com/cnkang/hermes-plugin-qdrant-memory/actions/workflows/standalone.yml)
25
+ [![CodeQL](https://github.com/cnkang/hermes-plugin-qdrant-memory/actions/workflows/codeql.yml/badge.svg)](https://github.com/cnkang/hermes-plugin-qdrant-memory/actions/workflows/codeql.yml)
26
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
27
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
28
+
29
+ > **v0.1.0 — limited technical preview.** Give Hermes Agent durable, private
30
+ > long-term memory: your conversations become searchable memories in your own
31
+ > Qdrant store, with recall, update and scoped deletion under your control.
32
+ > The preview supports one writer per destination, with the documented
33
+ > durability limits. See the [validation record](docs/validation.md) for the
34
+ > current certification.
35
+
36
+ [English](README.md) | [简体中文](README.zh-CN.md)
37
+
38
+ Native long-term memory plugin for Hermes Agent, implemented as a `MemoryProvider`.
39
+ Hermes performs extraction
40
+ through its trusted `ctx.llm` facade. Qdrant stores named dense vectors and schema-v1
41
+ payloads. No Mem0 SDK, separate LLM SDK, telemetry, or core modifications.
42
+
43
+ Available in the official [Hermes Plugin Catalog](https://hermes-agent.nousresearch.com/docs/plugins/qdrant-memory)
44
+ as a community-maintained plugin.
45
+
46
+ ## How it works
47
+
48
+ ```mermaid
49
+ flowchart LR
50
+ turn["Hermes turn"] --> admit["Provider callback"]
51
+ admit --> ledger[("SQLite ledger<br/>durable admission")]
52
+ ledger -.async.-> extract["LLM extraction +<br/>relation checks"]
53
+ extract --> store[("Qdrant<br/>dense vectors + payloads")]
54
+ ask["Recall / search"] --> search["Scoped dense search"]
55
+ search --> store
56
+ ```
57
+
58
+ ## Why this plugin
59
+
60
+ - Durable, private memory for Hermes Agent: conversations become searchable
61
+ memories in your own Qdrant store, with recall, update and scoped deletion.
62
+ - A native Hermes `MemoryProvider`, not Mem0. The `migrate mem0` command
63
+ imports existing Mem0 exports.
64
+ - Embedded Qdrant needs no separate service. The same code targets
65
+ self-hosted Server and Qdrant Cloud.
66
+ - A fully local setup works: embedded Qdrant and local Ollama keep the data
67
+ on your machine.
68
+ - Data locality follows the destination. Extraction uses the LLM configured
69
+ in Hermes, and embedding uses the configured embedding service; either can
70
+ be remote. See [Data flow and privacy](#data-flow-and-privacy).
71
+ - Not supported in this preview: multi-writer Server/Cloud, hybrid search and
72
+ a web UI.
73
+
74
+ ## Additional compatibility with other agents
75
+
76
+ The plugin primarily provides Hermes Agent's durable memory integration. As an
77
+ additional capability, its shared backend can serve other agents through the
78
+ Runtime 0.2.0's `qdrant-memory --home PATH` JSON CLI and optional local stdio MCP
79
+ interface, without requiring Hermes. These interfaces support explicit scoped
80
+ memory operations and maintenance/migration; automatic extraction and prefetch
81
+ remain Hermes lifecycle features. See [standalone setup](docs/standalone.md) for
82
+ configuration and boundaries, and the agent-neutral
83
+ [qdrant-memory skill](https://github.com/cnkang/skills/tree/main/qdrant-memory)
84
+ for multi-agent installation and usage guidance.
85
+
86
+ The optional MCP server exposes four scoped tools: `qdrant_memory_search`,
87
+ `qdrant_memory_add`, `qdrant_memory_update` and `qdrant_memory_delete`. Compatible
88
+ clients launch it as a local stdio process and discover/call those tools;
89
+ maintenance and migration use the operator CLI. See the
90
+ [MCP capabilities and connection guide](docs/mcp.md) for setup, shared-memory
91
+ boundaries and the verified agent matrix. This is a tested source preview;
92
+ the published v0.1.0 plugin release does not include the MCP entrypoint.
93
+
94
+ ## See it in action
95
+
96
+ ![Terminal recording: install the plugin, store a preference, and recall it in a new session](https://raw.githubusercontent.com/cnkang/hermes-plugin-qdrant-memory/main/assets/demo.gif)
97
+
98
+ The recording shows the full flow on a clean profile: install from the
99
+ official Hermes Plugin Catalog, teach a preference, wait for the background
100
+ extraction, recall it in a new session, and clean up the demo scope. All steps
101
+ run in embedded mode. `scripts/demo.sh` reproduces the same walkthrough with
102
+ the pinned release.
103
+
104
+ ## Install
105
+
106
+ Requirements: Python 3.11+, a compatible Hermes installation, and a reachable
107
+ embedding service. The minimum supported Hermes release is v0.21.5 (v2026.9.24).
108
+ The [CI services](docs/ci.md) page documents the tested host versions.
109
+ The default model needs Ollama and enough local resources
110
+ to serve `qwen3-embedding:4b`.
111
+
112
+ Choose the **active profile's** home explicitly. Do not reuse another profile's data.
113
+
114
+ **Recommended: install from the official Hermes Plugin Catalog.**
115
+
116
+ ```bash
117
+ export HERMES_HOME="/absolute/path/to/your/hermes-profile"
118
+ ollama pull qwen3-embedding:4b
119
+ # Start Ollama if it is not running. Keep its service available.
120
+ hermes plugins install qdrant-memory
121
+ hermes plugins enable qdrant-memory
122
+ hermes memory setup
123
+ hermes config set memory.provider qdrant-memory
124
+ hermes qdrant-memory init
125
+ ```
126
+
127
+ The install resolves the catalog's reviewed commit and prints the entry's declared
128
+ tools, requirements and known issues before it clones anything.
129
+ `hermes plugins enable` prepares the declared dependencies through Hermes PM.
130
+
131
+ **Version-locked: install the pinned release through the Hermes CLI.**
132
+
133
+ ```bash
134
+ export HERMES_HOME="/absolute/path/to/your/hermes-profile"
135
+ ollama pull qwen3-embedding:4b
136
+ # Start Ollama if it is not running. Keep its service available.
137
+ hermes plugins install https://github.com/cnkang/hermes-plugin-qdrant-memory \
138
+ --ref 5babd3e4b4c022aad38a2b6db82cbd5b601f1ef8 # v0.1.0 release commit
139
+ hermes plugins enable qdrant-memory
140
+ hermes memory setup
141
+ hermes config set memory.provider qdrant-memory
142
+ hermes qdrant-memory init
143
+ ```
144
+
145
+ For this version-locked form, `hermes plugins install` checks out the given ref, and
146
+ `hermes plugins enable` prepares the declared dependencies through Hermes PM.
147
+ `--ref` takes a full 40-character commit SHA; the
148
+ [releases page](https://github.com/cnkang/hermes-plugin-qdrant-memory/releases)
149
+ lists the release commits. Do not pip-install into a managed Hermes
150
+ environment. Omit `--ref` to track `main`, the development line.
151
+
152
+ **Alternative: clone the release tag manually.**
153
+
154
+ ```bash
155
+ export HERMES_HOME="/absolute/path/to/your/hermes-profile"
156
+ mkdir -p "$HERMES_HOME/plugins"
157
+ RELEASE_TAG=v0.1.0 # set a published release tag
158
+ git clone --branch "$RELEASE_TAG" --depth 1 \
159
+ https://github.com/cnkang/hermes-plugin-qdrant-memory.git \
160
+ "$HERMES_HOME/plugins/qdrant-memory"
161
+ ollama pull qwen3-embedding:4b
162
+ # Start Ollama if it is not running. Keep its service available.
163
+ hermes memory setup
164
+ hermes config set memory.provider qdrant-memory
165
+ hermes qdrant-memory init
166
+ ```
167
+
168
+ Then verify the install:
169
+
170
+ ```bash
171
+ hermes qdrant-memory status
172
+ hermes qdrant-memory doctor
173
+ ```
174
+
175
+ A healthy install reports the destination, the embedding service and the
176
+ schema fingerprint. `doctor` validates runtime discovery, manifest parsing,
177
+ import and registration. For development installs, see
178
+ [development setup](docs/development.md).
179
+
180
+ The release notes, supported Hermes/Python versions and the current
181
+ limitations live in [docs/releases/v0.1.0.md](docs/releases/v0.1.0.md);
182
+ `main` stays the development line.
183
+
184
+ For local development, symlink the repository into a disposable profile:
185
+
186
+ ```bash
187
+ mkdir -p "$HERMES_HOME/plugins"
188
+ ln -s /path/to/hermes-plugin-qdrant-memory "$HERMES_HOME/plugins/qdrant-memory"
189
+ hermes memory setup
190
+ hermes config set memory.provider qdrant-memory
191
+ ```
192
+
193
+ Restart the conversation after configuration changes. Existing system prompts
194
+ and toolsets stay fixed for prompt caching. Packaged installations expose the
195
+ `hermes_agent.memory_providers` entry point and keep `cli.py` and `config_schema.py`
196
+ next to the package entry point.
197
+
198
+ Defaults use embedded Qdrant and Ollama `qwen3-embedding:4b` (2560 dimensions).
199
+ Run the embedding service and provision that model before you activate the provider.
200
+ For server/Cloud, configure the mode in `$HERMES_HOME/qdrant-memory.json`. Supply
201
+ `QDRANT_URL` / `QDRANT_API_KEY` in the active profile's secret scope.
202
+
203
+ ## Capabilities
204
+
205
+ - Embedded, self-hosted server and Cloud using the same Qdrant client.
206
+ - Ollama `/api/embed` and OpenAI-compatible `/v1/embeddings`, with strict probe,
207
+ vector-count/dimension validation and pipeline fingerprint checks.
208
+ - Main LLM inheritance, plugin auxiliary task routing and operator-trusted overrides.
209
+ - User/agent scope filtering for recall, exact-ID update and deletion.
210
+ - Turn persistence to the plugin's private SQLite ledger after Hermes admits the
211
+ provider callback. Serialized writes, cached session recall and builtin memory
212
+ mirroring use authoritative `previous_content`.
213
+ - SQLite WAL event/operation ledger, transport retries and restart recovery.
214
+ - Source-ID-only Mem0 JSON/Qdrant migration, re-embedding, dry runs, resumable
215
+ manifests, supplemental updates, and verification of IDs and payload hashes.
216
+ - Read-only `list` inventory, portable `export` (Mem0-importable JSON) and a
217
+ durable scoped `delete-all` with prepared-write fencing.
218
+
219
+ Unlike hosted memory services, your memory data lives in your own Qdrant
220
+ destination. The plugin makes no calls to external memory services. Its
221
+ private SQLite ledger (pending operations, dedupe/retry bookkeeping and session
222
+ mappings) stays in the local Hermes home. Back up that home together with your
223
+ Qdrant data. Migration from Mem0 is one-way, and version 0.1 has no vector
224
+ reuse or hybrid retrieval.
225
+
226
+ Similarity is a candidate-selection signal, not proof that two facts are identical.
227
+ `SAME` skips, `SUPERSEDES` updates, `CONFLICT` creates a linked record, and
228
+ `UNRELATED` adds a record. Migration uses source IDs instead of semantic merging.
229
+
230
+ The four agent tools are `qdrant_memory_search`, `qdrant_memory_add`,
231
+ `qdrant_memory_update`, and `qdrant_memory_delete`. Maintenance stays in the CLI:
232
+
233
+ ```bash
234
+ hermes qdrant-memory status
235
+ hermes qdrant-memory init
236
+ hermes qdrant-memory doctor
237
+ hermes qdrant-memory stats
238
+ hermes qdrant-memory verify
239
+ hermes qdrant-memory retry
240
+ ```
241
+
242
+ `status` is local-only. `doctor` and `verify` probe existing collections without
243
+ creating or repairing them. Run `init` after first-time configuration to probe
244
+ embeddings, create the collection, record its pipeline fingerprint and build
245
+ Server/Cloud payload indexes. It makes no LLM calls and writes no conversation
246
+ memories. Repeated runs validate the existing collection. Incompatible dimensions,
247
+ distance or fingerprint fail without overwriting existing data.
248
+ When the collection exists, `init` asks for `use` (the default on Enter) or `clear`.
249
+ Reuse validates the named dense vector, dimensions, distance and pipeline identity,
250
+ then checks every stored memory's payload, content hash and vector. A validation
251
+ failure returns a nonzero exit code. The plugin cannot reuse a nonempty
252
+ collection without a trusted fingerprint.
253
+ Clear probes embeddings first, then deletes and rebuilds the target collection and
254
+ discards that destination's local replay work and migration records. The plugin
255
+ keeps other destinations and the transcript provenance quarantine. Clearing is
256
+ irreversible, and deletion/recreation is not atomic. Rerun `init` if remote
257
+ recreation fails.
258
+ An interrupted clear leaves a durable reset intent. Other destination commands fail
259
+ with `reset_recovery_required`. Rerun `init` for the same destination to resume the
260
+ already authorized reset before you enable the provider.
261
+ For scripts, explicitly pass `--existing use` or `--existing clear`. The `clear`
262
+ choice authorizes deletion. `--collection NAME` overrides only this command's
263
+ target, not the collection configured for subsequent agent sessions.
264
+ `init`, `migrate` and `retry` require exclusive writer ownership in all deployment
265
+ modes. The OS lease coordinates local processes that use that profile destination.
266
+ It is not a distributed lock. Stop every Hermes session or gateway on every host
267
+ that writes to the same destination before you run them. If `doctor` already
268
+ reports `ok: true`, the collection is ready. Initialization is unnecessary. Remote
269
+ `doctor`, `stats` and `verify` can inspect it while the writer runs.
270
+ `retry` requeues failed events for the next provider
271
+ startup and retries prepared operations. Stop the agent before you run maintenance
272
+ on an embedded store. Qdrant's local persistence permits only one client process.
273
+
274
+ ## Memory inventory, export and scoped deletion
275
+
276
+ ```bash
277
+ hermes qdrant-memory list # read-only inventory
278
+ hermes qdrant-memory export --output backup.json # portable JSON for re-import
279
+ hermes qdrant-memory delete-all --user alice --confirm
280
+ ```
281
+
282
+ `list` reports stored memories with scope, provenance and timestamps. It also
283
+ reports the destination's pending/failed operation counts. Use `--user` and
284
+ `--agent` to filter. Omitting both covers the whole collection. `--limit`
285
+ bounds the output, and the command refuses `--agent` without `--user`.
286
+ `export` writes every stored memory, optionally one scope, as portable JSON in
287
+ the shape the Mem0 importer accepts. `hermes qdrant-memory migrate mem0
288
+ --source-json backup.json` then restores it into a fresh destination (imports
289
+ re-embed, and version 0.1 has no vector reuse). Round trips preserve text,
290
+ scope, categories and timestamps. Mem0-migrated memories re-import to the same
291
+ points, and native memories keep their original point UUID in the exported
292
+ record for provenance. The plugin writes exports owner-only and refuses to
293
+ overwrite without `--force`. An export covers stored memories only. Pending
294
+ events, retry history and crash-recovery state stay in the local ledger. Back
295
+ up the profile home for a full recovery point.
296
+
297
+ `delete-all` durably deletes stored memories and pending work for one scope
298
+ (`--user` required). It records a reset-style intent first. Then it fences every
299
+ enumerated point and every prepared write for that scope, including writes
300
+ whose points were never stored. It invalidates admitted-but-unprocessed turn
301
+ events for the scope, deletes the scope in one filtered operation, and clears
302
+ the intent only after the scope becomes empty. A scope is exactly one
303
+ (user, agent) pair. Omitting `--agent` selects the no-agent scope, and the
304
+ default profile scope uses an agent (`hermes`). Pass `--agent hermes` to
305
+ target it, or `--all-agents` to delete every agent scope of the user. Without
306
+ `--all-agents`, the result reports `other_agent_scopes` when other agent
307
+ scopes still hold memories. A literal `*` is an ordinary agent id, not a
308
+ wildcard. `--dry-run` previews the per-scope counts;
309
+ `--confirm` authorizes deletion. An interrupted deletion fails closed: other
310
+ commands and provider startup return `scope_delete_recovery_required` until
311
+ `delete-all --confirm` resumes it. Deletion intents are versioned and explicit.
312
+ A pre-versioned intent cannot show whether `*` is a single agent or all agents,
313
+ so the plugin refuses it (`scope_delete_legacy_intent`). Resolve it with
314
+ `--resolve-legacy single_agent`, or with `--resolve-legacy all_agents` when the
315
+ record's agent is `*` or absent. Turns admitted after the deletion can still
316
+ add new memories; everything admitted before it — stored memories, prepared
317
+ writes and unprocessed turn events — is removed or invalidated. `list`,
318
+ `export` and `delete-all` do not require the embedding service.
319
+
320
+ ## Data flow and privacy
321
+
322
+ This provider sends data only toward services you configure. What each component
323
+ carries and where it can go:
324
+
325
+ | Component | Carries | Destination |
326
+ | --- | --- | --- |
327
+ | Chat / agent turns | Your conversation | The model configured for the Hermes session |
328
+ | Memory extraction (`llm.mode: inherit`) | The turn's user and assistant text | The same session model — with a cloud model, turn text reaches that cloud |
329
+ | Relation checks | The candidate memory and the similar stored memory | Same routing as extraction; runs only when similarity selects a review candidate |
330
+ | Embeddings (`embedding`) | Memory and search text | Ollama by default, or your OpenAI-compatible endpoint |
331
+ | Storage (`qdrant`) | Memory payloads and provenance; the ledger stays local | Embedded local path, self-hosted server, or Qdrant Cloud |
332
+
333
+ Three common deployments:
334
+
335
+ | Deployment | Chat model | Extraction LLM | Embeddings | Storage |
336
+ | --- | --- | --- | --- | --- |
337
+ | Fully offline | local (for example Ollama) | inherits the local model | local Ollama | embedded local |
338
+ | Hybrid | cloud | inherits the cloud model by default | local Ollama | embedded local |
339
+ | Full cloud | cloud | cloud | OpenAI-compatible endpoint | Qdrant Cloud |
340
+
341
+ A fully offline setup needs enough local compute for the chat model and the
342
+ embeddings together. On a 24 GB host, a 27B local chat model plus local
343
+ embeddings exceeded comfortable VRAM during validation. Local-model turns can
344
+ take minutes each. Budget accordingly or use a smaller local model.
345
+
346
+ In the hybrid layout, extraction and relation checks inherit the session model.
347
+ Route them elsewhere with `llm.mode: task` (the plugin's auxiliary task on a
348
+ local model) or `llm.mode: override` (an explicit provider and model).
349
+ Extraction instructions exclude obvious credentials and transient statuses, but
350
+ any configured LLM or Qdrant destination can see the memories it processes.
351
+ Treat them accordingly. Logical scrubbing of the local
352
+ ledger is not secure erasure. See [operations](docs/operations.md) and
353
+ [security](docs/security.md).
354
+
355
+ Extraction and relation checks run as Hermes auxiliary calls. Their per-task
356
+ timeout defaults to 30 seconds, and a slow local model can exceed it easily.
357
+ Raise `auxiliary.qdrant_memory_extraction.timeout` (seconds) for fully local
358
+ deployments. A timed-out extraction becomes failed work, and
359
+ `hermes qdrant-memory retry` requeues it.
360
+
361
+ ## Configuration and migration
362
+
363
+ Behavior lives in `$HERMES_HOME/qdrant-memory.json`. Credentials belong in the
364
+ active profile's Hermes secret scope. Defaults use embedded Qdrant.
365
+ During setup, the wizard reuses existing `QDRANT_URL` and `QDRANT_API_KEY` from
366
+ the active profile's environment without another prompt. Setup reports their
367
+ presence without showing values, asks only for missing settings and saves environment
368
+ references rather than copying supplied values or keys. An environment URL replaces
369
+ any older explicit URL in the saved plugin settings. For server or
370
+ Cloud, set `qdrant.mode`, collection and endpoint. Cloud requires HTTPS and a
371
+ Database API key. [Configuration examples and defaults](docs/configuration.md)
372
+ cover Ollama, OpenAI-compatible embeddings, LLM routing and explicit fallbacks.
373
+
374
+ Use a separate target collection and keep the Mem0 source unchanged:
375
+
376
+ ```bash
377
+ hermes qdrant-memory migrate mem0 --source-json /path/to/export.json --dry-run
378
+ # Stop CLI/foreground writers; for an installed background gateway:
379
+ hermes gateway status
380
+ hermes gateway stop
381
+ hermes qdrant-memory migrate mem0 --source-json /path/to/export.json \
382
+ --target-collection hermes_qdrant_memory --resume --verify
383
+ hermes qdrant-memory verify --collection hermes_qdrant_memory
384
+ ```
385
+
386
+ Re-embedding is the default. `--resume` needs the same snapshot and pipeline.
387
+ Add `--retry-failed` to retry failed operations from that manifest. Migration
388
+ verification checks exact IDs, scope and payload hashes, not just record count.
389
+ Canceled migration records become terminal `SUPERSEDED` work. They never count
390
+ as successful writes. Resume preserves later deletion intent. `--verify` reports
391
+ the conflict as `migration_superseded` with a nonzero exit code. While failed
392
+ records remain, `--verify` reports `migration_incomplete` instead. Correct and
393
+ resume the failures before any conflict review or deliberate fresh import. Only
394
+ a fresh import or changed snapshot authorizes replanning.
395
+ Recovery reads operations and events in finite bounded pages. Retained ledger
396
+ history still needs disk-capacity monitoring.
397
+ Before a real import, stop all sessions/gateways writing to the target, including
398
+ for Server/Cloud. `writer_busy` requires stopping the active writer, not deleting
399
+ lock or ledger files. A successful dry-run does not check writer ownership.
400
+ Read the [migration guide](docs/migration-from-mem0.md) for executable gateway
401
+ stop/start, migration, verification and interrupted-import recovery commands.
402
+
403
+ ## Operations and security
404
+
405
+ The private SQLite ledger can contain raw turn events and prepared payloads. It
406
+ logically scrubs committed event bodies and committed/superseded operation bodies,
407
+ except operations still needed by an incomplete migration manifest. Identity/status
408
+ rows and manifests remain. Pending/failed work retains its body for recovery. There
409
+ is no time-based expiry for ledger rows or manifests. Deleting a Qdrant memory does
410
+ not purge pending or failed ledger work. Treat `state.db`, SQLite WAL/SHM sidecars,
411
+ copied snapshots and backups as sensitive. Stop the agent before you back up the
412
+ ledger with the embedded store. `init --existing clear` clears the selected
413
+ collection's ledger rows, but logical scrubbing/reset is not secure erasure from disk
414
+ pages or previously copied backups. Do not delete `state.db` to recover failed work.
415
+ Changing embedding identity requires a new collection.
416
+
417
+ The durability guarantee starts only after Hermes calls the provider's `sync_turn`
418
+ callback and the plugin commits the event to SQLite. Hermes currently submits that
419
+ callback to an in-memory background queue. An abrupt host exit or its bounded
420
+ shutdown can abandon work that has not reached plugin admission. After ledger
421
+ admission, the plugin replays pending events and prepared operations after restart.
422
+ This plugin ledger does not make the earlier host queue durable.
423
+
424
+ Tool arguments cannot override user/agent scope. Automatic writes exclude bot
425
+ and non-primary-agent turns. Treat recalled content as untrusted data. See
426
+ [security](docs/security.md), [operating procedures](docs/operations.md),
427
+ [troubleshooting](docs/troubleshooting.md) and [architecture](docs/architecture.md).
428
+
429
+ ## Compatibility and scope
430
+
431
+ Version 0.1 implements dense retrieval. Hybrid sparse vectors, RRF/DBSF, reranking
432
+ and recency weighting remain future capabilities. The plugin rejects unsupported
433
+ config. Named `dense` vectors preserve a path to future sparse vectors.
434
+
435
+ The plugin feature-detects embedding `inherit` and requires an explicit
436
+ `inherit_fallback`. The future host facade must provide `dimensions`,
437
+ `fingerprint`, `embed_documents()` and `embed_query()`. Current Hermes has no
438
+ documented global embedding facade.
439
+
440
+ Compatibility requires Hermes `MemoryProvider`, checkpoint v2, trusted turn authors,
441
+ authoritative builtin `previous_content`, scoped secrets and context threads.
442
+ Earlier tags have incomplete contracts. The minimum supported release is v0.21.5 (v2026.9.24). See
443
+ [validation](docs/validation.md) for tested environments and remaining live-service
444
+ checks. Read [configuration](docs/configuration.md), [migration](docs/migration-from-mem0.md),
445
+ [security](docs/security.md) and [operations](docs/operations.md) before deployment.
446
+
447
+ ## Development
448
+
449
+ Run Ruff lint and format checks before you commit. Install the repository
450
+ pre-commit hook as described in [development setup](docs/development.md). The hook
451
+ checks the staged snapshot. CI runs lint, both Python versions, Snyk and
452
+ SonarCloud. See [CI services](docs/ci.md) for the tested host versions and lanes.
453
+
454
+ Build isolated dependency environments with Hermes PM. Then run the host's
455
+ canonical test runner against this repository's tests. The tests import the real
456
+ host and use a temporary `HERMES_HOME`.
457
+
458
+ ```bash
459
+ cd /path/to/hermes-agent
460
+ python -m pm.build_env --source /path/to/hermes-agent --group test \
461
+ --export-requirements /tmp/hermes-qdrant-test-requirements.txt
462
+ python -c 'import sys, tomllib; from pathlib import Path; p = tomllib.loads(Path(sys.argv[1]).read_text()); print("\n".join(p["project"]["dependencies"] + p["dependency-groups"]["test"]))' \
463
+ /path/to/hermes-plugin-qdrant-memory/pyproject.toml >> /tmp/hermes-qdrant-test-requirements.txt
464
+ python -m pm.build_env --out /path/to/hermes-plugin-qdrant-memory/.test-env \
465
+ --requirements /tmp/hermes-qdrant-test-requirements.txt
466
+ HERMES_PYTHON=/path/to/hermes-plugin-qdrant-memory/.test-env/bin/python \
467
+ scripts/run_tests.sh /path/to/hermes-plugin-qdrant-memory/tests -j 1 --file-retries 0
468
+ ```
469
+
470
+ The build reads the plugin's `test` development dependency group from
471
+ `pyproject.toml`. The tested host PM exports runtime requirements only. Append the
472
+ plugin runtime dependencies and test group before you build the combined
473
+ environment.
474
+
475
+ Run the real embedding pilot from the plugin checkout with the host import path:
476
+
477
+ ```bash
478
+ PYTHONPATH=/path/to/hermes-agent .test-env/bin/python scripts/evaluate.py
479
+ ```
480
+
481
+ It uses a temporary embedded collection and UTF-8 JSON dataset. A custom dataset
482
+ contains `memories` objects with `id`/`text`, and `queries` with `query`/`relevant_ids`.
483
+ The default fixture now contains 24 labeled queries, including Chinese, English,
484
+ mixed-language and hard-negative cases. The
485
+ [original 12-query recording](docs/retrieval-baseline.json) is a historical
486
+ synthetic regression baseline; rerun the current fixture for current measurements.
487
+ These fixtures do not establish production recall quality. See the [recovery benchmark](docs/recovery-benchmark.md)
488
+ for a separate synthetic replay and retained-storage measurement.
489
+
490
+ CI runs tests, SonarCloud quality gates and Snyk dependency/code scans.
491
+ See [CI service setup](docs/ci.md) and [validation evidence](docs/validation.md).
492
+
493
+ ## License
494
+
495
+ MIT. Copyright © 2026 Kang Liu. See [LICENSE](LICENSE).