Files
de4292ed4e feat(hermes): add managed native prefetch provider (#143)
* feat: add native Hermes memory provider

* feat(hermes): support scoped private CA trust

* feat(hermes): bound write timeout separately from reads

* fix(hermes): support truststore scoped CA snapshots

* feat(hermes): add managed prefetch provider

Co-authored-by: kindong <727777477@qq.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: kindong <727777477@qq.com>
Co-authored-by: alvinfei <alvinfei@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-22 16:51:15 +08:00
..

Native Hermes memory provider

hy_memory implements the Hermes MemoryProvider contract pinned by this repository to Hermes v0.21.6. Its primary product mode is a MemHub-managed, read-only recall provider:

Hermes queue_prefetch / prefetch
  → MemHub loopback Broker /context
  → authorized Core Context v1 or SDK-native Context v2

The provider uses Python's standard library only. It does not embed the Hy Memory SDK, own a database, start a server, or receive a Core bearer token.

MemHub-managed installation

MemHub's Hermes “Connect” action installs:

~/.hermes/plugins/hy_memory/
  __init__.py
  plugin.yaml
  provider.py
  connection.json

~/.hermes/config.yaml
  memory.provider: hy_memory
  mcp_servers.one-memory: ...

~/.hermes/skills/memhub-recall/SKILL.md

connection.json contains only the Broker discovery path and the private host credential file path. The credential remains in MemHub's owner-only permission store. Each request reloads discovery and credential state, validates loopback Broker identity, refuses redirects/proxies, and uses the host grant.

Clicking Connect is approval to replace the current Hermes memory.provider. The install journal records the previous value. Turning the integration off through MemHub restores it if the setting and provider files have not been modified since installation.

Deleting the MemHub application directly may not provide a cleanup opportunity. An orphaned provider therefore fails safely: Hermes continues normally without recalled memory when the Broker or credential is unavailable.

Hermes must be fully restarted after installation or removal.

Recall lifecycle

Automatic recall is enabled by default:

  1. At the end of turn N, Hermes calls queue_prefetch(query_N).
  2. The provider performs authorized background recall.
  3. At the start of turn N+1, prefetch(query_N+1) consumes the warmed result without blocking. The two query strings do not need to match.

Hermes retains previously injected context in later history. To prevent repeated context growth, the provider maintains the set of injected opaque memory_id values for each Hermes session_id:

  • only IDs not previously injected in that session are returned;
  • duplicate IDs within one response collapse to the first item;
  • identical text with different IDs remains distinct;
  • switching sessions uses that session's own set;
  • reset/rewind clears the target session's set;
  • results searched but never injected do not enter the set.

Only opaque IDs are persisted under $HERMES_HOME/.one-memory/hy-memory-seen.json, so deduplication survives a Hermes restart without storing recalled content.

recall_status() reports only newly injected items.

Recalled content is external, untrusted data and never instructions. Injected blocks use the same escaped memhub_memory_context boundary that MemHub source adapters strip if a host persists injected context.

Write and anti-recursion boundary

The MemHub-managed provider is read-only:

  • it exposes hy_memory_search as an explicit fallback;
  • it does not expose hy_memory_add;
  • automatic capture is disabled;
  • Hermes conversation ingestion remains owned by MemHub's source scanner.

This prevents recalled memory injected into Hermes history—or an assistant paraphrase of it—from being written back as a new memory.

The legacy direct-service mode described below can opt into automatic capture, but captures user-authored text only. It ignores assistant text and the messages payload containing injected memory context. Explicit add remains a deliberate user/tool action in that mode.

Optional operator-managed direct mode

If no managed connection.json exists, the provider retains the contribution's operator-managed direct mode. Configure it explicitly:

export HY_MEMORY_URL=http://127.0.0.1:19527
export HY_MEMORY_USER_ID=your-explicit-owner-id
export HY_MEMORY_AGENT_ID=your-explicit-agent-id
Environment variable Default Accepted values
HY_MEMORY_CONNECTION_FILE sibling connection.json if present absolute managed connection file
HY_MEMORY_USER_ID required in direct mode nonblank, at most 256 characters
HY_MEMORY_AGENT_ID required in direct mode nonblank, at most 256 characters
HY_MEMORY_URL http://127.0.0.1:19527 origin only
HY_MEMORY_CA_FILE OS trust explicit PEM CA for direct HTTPS
HY_MEMORY_API_KEY unset reverse-proxy Bearer credential
HY_MEMORY_TIMEOUT 5 finite seconds, 0.1–30
HY_MEMORY_WRITE_TIMEOUT read timeout finite seconds, 0.1–120
HY_MEMORY_LIMIT 5 integer, 1–20
HY_MEMORY_MAX_CHARS 4000 integer, 256–16000
HY_MEMORY_MAX_BODY_BYTES 262144 integer, 1024–1048576
HY_MEMORY_AUTO_RECALL true true or false
HY_MEMORY_AUTO_CAPTURE false true or false; direct mode only

The bare Hy Memory HTTP server does not authenticate or authorize clients. Never expose it to untrusted clients. Remote direct mode requires HTTPS through an authenticating gateway and network policy blocking direct backend access.

Offline tests

PYTHONPATH="$PWD" python -m pytest plugins/hermes/tests -o addopts='' -q
python -m ruff check plugins/hermes

When HERMES_MEMORY_PROVIDER_SNAPSHOT is set, tests load that pinned Hermes contract snapshot. Otherwise they use the installed contract or the local fixture. Tests cover protocol, isolation, session deduplication, recursion prevention, transport deadlines, and installation behavior; they do not claim live recall quality.