Verbatim local-first memory for Hermes Agent — store raw turns in SQLite, no extraction, no cloud, no auth.
Project description
memex-hermes
Verbatim local-first memory for Hermes Agent. Stores every turn raw — no LLM extraction, no cloud, no auth, no API keys.
Why memex-hermes (vs Mem0 / Supermemory / hermes-memory)
Most memory layers for Hermes extract "facts" from your conversations and discard the originals. That's lossy by design — if the extractor misses nuance, you can never recover it.
memex-hermes does the opposite:
| memex-hermes | Mem0 / Supermemory | hermes-memory | |
|---|---|---|---|
| What's stored | raw turns, full text | extracted facts | structured memory |
| Backend | local SQLite + FTS5 | cloud SaaS | local SQLite |
| Auth / API key | none | required | none |
| LLM cost at capture | zero | per-turn extraction | depends |
| Restore originals | always possible | impossible | partial |
| Backfill old history | ✅ memex-hermes-backfill |
❌ | ❌ |
| Cross-client corpus | ✅ shared with Claude Code, OpenClaw, Telegram via memex-mvp |
❌ | ❌ |
| Anthropic-eats-this risk | low (we're the substrate) | high (we'd be the layer that becomes redundant) | medium |
memex is the substrate. Pair it with Mem0 / Supermemory if you want extraction on top — they'll happily index memex's verbatim store while you still hold the originals.
Install
Three steps: install the pip package, generate a tiny shim folder Hermes will discover, activate in config.
# 1. Install into Hermes' Python environment (recommended)
uv pip install memex-hermes --python $HOME/.hermes/hermes-agent/venv/bin/python
# Or with vanilla pip:
pip install memex-hermes
# 2. Create the shim folder Hermes discovers
# (Hermes scans ~/.hermes/plugins/memory/ — pip entry_points are NOT used
# for memory provider discovery as of Hermes v0.10.x.)
memex-hermes init
# 3. Activate in Hermes config — edit ~/.hermes/config.yaml:
# memory:
# provider: "memex"
# 4. Restart Hermes. The plugin auto-activates.
Why the extra init step? Hermes' memory-provider discovery is folder-based, not entry-point-based (verified by reading plugins/memory/__init__.py in hermes-agent v0.10.x). The init command creates a 3-line shim at ~/.hermes/plugins/memex/__init__.py that imports from the pip-installed package. (Note the asymmetry: bundled Hermes plugins live at <hermes-agent>/plugins/memory/<name>/, but user plugins live at ~/.hermes/plugins/<name>/ — no memory/ subdir. We follow Hermes' actual discovery code.) Benefits:
- Auto-upgrades:
pip install -U memex-hermesupdates the plugin on next Hermes restart. No need to re-run init. - Tiny on-disk footprint in
~/.hermes/: just a stub, all real code lives in pip site-packages. - Forward-compatible: if a future Hermes adds entry_point support, our
pyproject.tomlalready declares it and the same code works for both paths.
To uninstall the plugin without touching the pip package: memex-hermes uninstall. To check current status: memex-hermes status.
memex is zero-config — there's nothing else to set up. The DB lives at ~/.memex/data/memex.db (override with MEMEX_DB env var or ~/.hermes/memex.json containing {"db_path": "..."}).
Backfill historical Hermes sessions
memex-hermes ships a one-shot backfill so you can import everything Hermes already remembers:
# Default: reads ~/.hermes/state.db, writes to ~/.memex/data/memex.db
memex-hermes-backfill
# Dry-run to see what would happen
memex-hermes-backfill --dry-run
# Only sessions since a date
memex-hermes-backfill --since 2026-04-01
# Custom paths
memex-hermes-backfill --hermes-home /opt/hermes --memex-db /data/memex.db
Idempotent — re-running is safe (UNIQUE(source, conversation_id, msg_id) dedups).
What gets captured
Every Hermes lifecycle hook routes verbatim data into memex.db:
| Hook | What we store |
|---|---|
sync_turn(user, assistant) |
both messages of every turn, verbatim |
on_session_end(messages) |
safety net — full final history, idempotent re-insert |
on_memory_write(action, target, content) |
mirror of built-in MEMORY.md / USER.md edits |
on_pre_compress(messages) |
turns about to be compressed → preserved before context drops them |
on_delegation(task, result) |
subagent task and result observations |
Recall is two-phase:
queue_prefetch(query)after each turn → background FTS5 search, result cachedprefetch(query)before next LLM call → returns cached context (~500 token budget), injected into the user message so prompt cache stays valid
And the LLM gets three MCP tools:
memex_search(query)— find records, returns IDs + 100-char previews (Tier 1)memex_get(ids)— fetch full verbatim text by ID (Tier 2 — only when needed)memex_recent(conversation_id)— last N messages in a thread (chronological)
This is the progressive disclosure pattern (popularised by claude-mem) — ~10× token savings vs returning full text in every search result.
Conversation IDs
memex-hermes groups messages so the same user's messages on the same platform share a conversation across all Hermes sessions:
| Hermes session metadata | Conversation ID |
|---|---|
platform="telegram", user_id="97592799" |
hermes-telegram-97592799 |
platform="discord", user_id="123abc" |
hermes-discord-123abc |
platform="cli" (no user_id) |
hermes-cli-<session8> |
platform="cron" |
hermes-cron-<session8> |
| Memory file mirror | hermes-memory-file-memory / -user |
Same model as memex-mvp uses for OpenClaw (openclaw-tg-<sender_id>).
Verify after install
# Hermes side — check provider is loaded:
hermes memory status
# Should show: "memex" active
# memex-mvp CLI (if installed) — see captured rows:
memex overview
memex recent --source hermes
memex search "ваш тестовый запрос"
If memex CLI isn't installed, query SQLite directly:
sqlite3 ~/.memex/data/memex.db \
"SELECT COUNT(*), MIN(date(ts,'unixepoch')), MAX(date(ts,'unixepoch'))
FROM messages WHERE source='hermes'"
Logs
logging.getLogger("memex_hermes") — appears in Hermes' standard log stream at ~/.hermes/logs/. Set Hermes log level to DEBUG to see prefetch + sync details.
What memex-hermes is NOT
- ❌ It is not a fact-extractor. If you want extraction, install Mem0 alongside.
- ❌ It is not a vector store. Search is FTS5 (text). Optional sqlite-vec hybrid recall is on the memex-mvp roadmap.
- ❌ It is not a multi-tenant cloud. Local-first; one SQLite file per machine.
- ❌ It is not the only writer. memex.db is shared — memex-mvp daemons, MCP imports, this plugin, all coexist via
UNIQUE(source, conv_id, msg_id).
License
MIT. See LICENSE in the parent repository.
Source / issues
- Repo: https://github.com/parallelclaw/memex-mvp (plugin lives in
plugins/memex-hermes/) - Issues: https://github.com/parallelclaw/memex-mvp/issues
- Homepage: https://memex.parallelclaw.ai
Related
- memex-mvp — Node.js CLI + MCP server for the same
memex.db. Install separately for thememex search,memex overview,memex_searchMCP tool, web dashboard, and daemons for Claude Code / OpenClaw / Telegram / Obsidian / Cursor / Cowork. - install-memex-claw — installation skill for OpenClaw users.
Project details
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 memex_hermes-0.1.2.tar.gz.
File metadata
- Download URL: memex_hermes-0.1.2.tar.gz
- Upload date:
- Size: 46.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fdd16fee657114522052ae77fbc5721bcd07ea182e87475e4f52a113e9bc1716
|
|
| MD5 |
7f91c4f3de380a475afcf77c074bdac9
|
|
| BLAKE2b-256 |
414847104b550ca9079bd8e6a118008f85862b72b3d5e470ff3712ac98b723b5
|
File details
Details for the file memex_hermes-0.1.2-py3-none-any.whl.
File metadata
- Download URL: memex_hermes-0.1.2-py3-none-any.whl
- Upload date:
- Size: 35.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a30eeb49e0bb984af3907bb18a22888d4ab6d8dc8fb7ef8985dfabf50e5f254c
|
|
| MD5 |
1d9de5cc9c61f7d74d35fc5308748886
|
|
| BLAKE2b-256 |
9fc9347e68c7fa56385dee4e9f35063c0965d8902e8719dd5a8a2ce7ac634cb9
|