MongoDB memory provider plugin for Hermes Agent — hybrid search, time-decay, TTL forgetting, and entity graph traversal in a single backend.
Project description
MongoDB Memory Provider for Hermes Agent
Hybrid search, time-decay relevance, TTL-driven forgetting, and entity graph traversal — served from a single MongoDB cluster (self-hosted or Atlas free tier).
Why MongoDB?
Existing Hermes memory providers each pick one storage angle: local SQLite (Holographic), cloud-only API (Mem0, Supermemory, RetainDB), knowledge graph (Hindsight), or vector-only stores. MongoDB collapses all of them into one backend.
| Capability | This plugin | Closest alternative |
|---|---|---|
| Native hybrid (vector + BM25) ranking | ✅ Atlas $rankFusion |
RetainDB ($20/mo cloud-only) |
| Self-hosted and cloud with one URI swap | ✅ | OpenViking (AGPL-3.0) |
| TTL-driven automatic forgetting | ✅ Mongo TTL indexes | None |
| Entity graph traversal without a graph DB | ✅ $graphLookup |
Hindsight (separate KG) |
| Time-decay relevance built into search | ✅ in-pipeline $exp |
None |
| Free tier with cloud durability | ✅ Atlas free tier | Holographic (local-only) |
| Cross-device sync | ✅ via Atlas | Cloud providers only |
In other words: vector search, BM25, structured queries, TTL, and graph traversal are all the same database — no glue between SQLite and a vector store, no separate graph engine.
Requirements
- Python ≥ 3.10
- A MongoDB 7.0+ cluster, either:
- Atlas free tier (M0) — recommended; enables
$rankFusionhybrid search and managed vector indexes - Self-hosted (community / enterprise) — works with the portable BM25 + cosine fallback path
- Atlas free tier (M0) — recommended; enables
- (Optional) an embedding provider key — OpenAI or Voyage AI. Without one, the plugin runs as a tuned BM25 + entity-graph store.
Install
pip install hermes-mongodb-memory
# Optional vector backends:
pip install "hermes-mongodb-memory[openai]"
pip install "hermes-mongodb-memory[voyage]"
pip install "hermes-mongodb-memory[all]" # both
Setup
Path 1 — Guided (recommended)
hermes memory setup # pick "mongodb" from the provider list
hermes mongodb init-indexes
The wizard prompts for connection URI, database, embedding provider, and tenant scope, then writes:
$HERMES_HOME/mongodb.json— non-secret values$HERMES_HOME/.env—HERMES_MONGODB_URIand any embedding API key
Path 2 — Manual
hermes config set memory.provider mongodb
echo 'HERMES_MONGODB_URI="mongodb+srv://USER:PASS@cluster.mongodb.net/?retryWrites=true"' >> ~/.hermes/.env
hermes mongodb init-indexes
Path 3 — Local development
git clone https://github.com/alexbevi/mongodb_hermes_memory.git
cd mongodb_hermes_memory
pip install -e ".[dev,all]"
# Hermes auto-discovers plugins in ~/.hermes/plugins/<name>/
ln -s "$(pwd)/hermes_mongodb_memory" ~/.hermes/plugins/mongodb
docker compose up -d # local Mongo 7 replica set
export HERMES_MONGODB_URI="mongodb://localhost:27017/?replicaSet=rs0"
Atlas free tier (zero-cost path)
- Create an Atlas account and a free M0 cluster.
- Network Access → Add your IP (or
0.0.0.0/0for development). - Database Access → Create a user.
- Connect → Drivers → copy the
mongodb+srv://...string. - Paste it into
hermes memory setup(or setHERMES_MONGODB_URI). - (Optional, enables hybrid search) Create the search indexes — see Atlas Search indexes below.
Configuration
$HERMES_HOME/mongodb.json — env vars override file values.
| Key | Default | Description |
|---|---|---|
connection_uri |
— | MongoDB URI (env: HERMES_MONGODB_URI) |
database |
hermes_memory |
Database name |
embedding_provider |
none |
none / openai / voyage |
embedding_api_key |
— | Provider API key (env: HERMES_MONGODB_EMBEDDING_API_KEY) |
embedding_model |
text-embedding-3-small |
Embedding model name |
embedding_dim |
1536 |
Must match your Atlas Vector Search index |
tenant_scope |
per-workspace |
global / per-workspace / per-profile |
auto_extract |
false |
Run regex extractor at session end |
extraction_llm |
false |
Use Hermes' configured LLM for richer extraction |
time_decay_half_life_days |
30 |
Half-life for relevance decay (0 disables) |
default_ttl_days |
0 |
Default TTL for new memories (0 = never) |
hybrid_vector_weight |
0.6 |
Vector vs BM25 weight (0–1) |
prefetch_limit |
5 |
Memories injected into each turn |
turn_ttl_days |
30 |
TTL for raw turn capture (0 = forever) |
Tools
The model can call six tools while the provider is active:
| Tool | Purpose |
|---|---|
mongo_remember |
Store a memory with category, entities, tags, optional TTL |
mongo_search |
Hybrid query (vector + BM25 + time-decay) — call before answering personal questions |
mongo_recall |
Walk the entity co-occurrence graph for related memories |
mongo_forget |
Remove or set short TTL on a memory by id |
mongo_profile |
Summary of latest preferences, projects, decisions |
mongo_reflect |
Cluster recent memories by entity for cross-category synthesis |
Indexes
hermes mongodb init-indexes creates the following on memories:
| Name | Shape | Why |
|---|---|---|
tenant_category_recent |
{tenant_id, category, created_at} |
Fast mongo_profile and per-category list scans |
tenant_entities |
{tenant_id, entities} |
Entity recall + $graphLookup start point |
tenant_tags (sparse) |
{tenant_id, tags} |
Tag filtering without bloating non-tagged docs |
ttl_expires_at (sparse, TTL=0) |
{expires_at} |
MongoDB TTL monitor evicts ephemeral memories |
content_text |
{content: "text"} |
Portable BM25 fallback for self-hosted clusters |
Plus on turns:
tenant_session_turn—{tenant_id, session_id, turn_idx}turns_ttl— TTL onexpires_at
Atlas Search indexes
For the hybrid-search fast path, create these in the Atlas UI (or via the Atlas Admin API):
// Atlas Search index "hermes_memory_text"
{ "mappings": { "fields": { "content": { "type": "string" } } } }
// Atlas Vector Search index "hermes_memory_vector"
{
"fields": [
{ "type": "vector", "path": "embedding", "numDimensions": 1536, "similarity": "cosine" },
{ "type": "filter", "path": "tenant_id" },
{ "type": "filter", "path": "category" },
{ "type": "filter", "path": "entities" }
]
}
Without these, the plugin transparently falls back to portable BM25 + in-process cosine.
Testing
# Unit tests (mongomock-backed, no docker required)
pytest tests/ -v --cov=hermes_mongodb_memory
# Integration tests against a real MongoDB
docker compose up -d
export MONGODB_TEST_URI="mongodb://localhost:27017"
pytest tests/test_integration.py -v -m integration
# Lint
ruff check .
Architecture
flowchart TB
subgraph Hermes["Hermes Agent (host)"]
Register["register(ctx)"]
Provider["MongoDBMemoryProvider"]
Prefetch["prefetch / queue_prefetch"]
SyncTurn["sync_turn"]
Tools["tools (6)"]
SessionEnd["on_session_end"]
Searcher["HybridSearcher"]
Embedder["EmbeddingClient<br/>(openai / voyage / none)"]
Store["MongoStore"]
Dispatcher["ToolDispatcher"]
Regex["RegexExtractor"]
LLM["LLMExtractor (optional)"]
Register --> Provider
Provider --> Prefetch
Provider --> SyncTurn
Provider --> Tools
Provider --> SessionEnd
Prefetch --> Searcher
Searcher --> Embedder
SyncTurn --> Store
Tools --> Dispatcher
Dispatcher --> Store
Dispatcher --> Searcher
SessionEnd --> Regex
SessionEnd --> LLM
Regex --> Store
LLM --> Store
end
subgraph Mongo["MongoDB / Atlas"]
Memories[("memories")]
Turns[("turns")]
Profiles[("profiles")]
Entities[("entities")]
RankFusion["$rankFusion<br/>$vectorSearch + $search (BM25)"]
GraphLookup["$graphLookup<br/>(entity traversal)"]
TTL["TTL indexes<br/>(automatic forgetting)"]
end
Searcher -.->|aggregation| RankFusion
Store -.->|CRUD + indexes| Memories
Store -.-> Turns
Store -.-> Profiles
Store -.-> Entities
Dispatcher -.->|mongo_recall| GraphLookup
Memories -.- TTL
classDef host fill:#f5f5f5,stroke:#444,color:#222;
classDef store fill:#e6f4ea,stroke:#2e7d32,color:#1b5e20;
classDef op fill:#fff3e0,stroke:#ef6c00,color:#5d4037;
class Register,Provider,Prefetch,SyncTurn,Tools,SessionEnd,Searcher,Embedder,Store,Dispatcher,Regex,LLM host;
class Memories,Turns,Profiles,Entities store;
class RankFusion,GraphLookup,TTL op;
Background daemon threads handle prefetch and sync_turn so a flaky cluster never blocks the conversation. A 5-failure / 120-second circuit breaker pauses Mongo writes when something is wrong upstream.
Releasing
Publishing is scripted in scripts/publish.sh:
scripts/publish.sh build # build sdist + wheel only (dry run)
scripts/publish.sh test # build, lint, test, upload to TestPyPI
scripts/publish.sh prod # same, upload to PyPI, tag v<version>
The script enforces a clean working tree, asserts that pyproject.toml and
hermes_mongodb_memory/__init__.py agree on the version, runs ruff + pytest,
calls python -m build, and uses twine to upload. Configure credentials in
~/.pypirc or via TWINE_USERNAME=__token__ / TWINE_PASSWORD=pypi-....
Contributing
PRs welcome. Conventional Commits required (feat(scope): ..., fix(scope): ...); tests required for new behavior; coverage gate is 80%.
License
MIT — same as Hermes Agent.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hermes_mongodb_memory-0.1.0.tar.gz.
File metadata
- Download URL: hermes_mongodb_memory-0.1.0.tar.gz
- Upload date:
- Size: 44.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1872ae3ebc35b8fc156fc937ee786594eb64679f78eda747be9e131a5b4b922e
|
|
| MD5 |
bdfadb9808a9bfb30bc92e80070bc852
|
|
| BLAKE2b-256 |
1f66e178ebbfd1717ca7400be4cc1d7a2a5451dfe0ffd615650741e4c3e2764f
|
File details
Details for the file hermes_mongodb_memory-0.1.0-py3-none-any.whl.
File metadata
- Download URL: hermes_mongodb_memory-0.1.0-py3-none-any.whl
- Upload date:
- Size: 33.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b4d935c5ecb4c518aaa87d3b862993afee07825e0214809dff9ad4d72efd1f1
|
|
| MD5 |
e2e16a7e28b9d67c66126015c8261d3f
|
|
| BLAKE2b-256 |
50856f1b0cec591e2234cc96a24982ebcbd200e250a94a03b82482921c3a9280
|