Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Holographic Memory Provider
Local SQLite fact store with FTS5 search, trust scoring, entity resolution, and HRR-based compositional retrieval.
Requirements
None — uses SQLite (always available). NumPy optional for HRR algebra.
Setup
hermes memory setup # select "holographic"
Or manually:
hermes config set memory.provider holographic
Config
Config in config.yaml under plugins.hermes-memory-store:
| Key | Default | Description |
|---|---|---|
db_path |
$HERMES_HOME/memory_store.db |
SQLite database path |
project_scoped |
false |
Explicit source-linked current-project candidates; ignores db_path |
auto_extract |
false |
Auto-extract facts at session end |
default_trust |
0.5 |
Default trust score for new facts |
hrr_dim |
1024 |
HRR vector dimensions |
Tools
| Tool | Description |
|---|---|
fact_store |
9 actions: add, search, probe, related, reason, contradict, update, remove, list |
fact_feedback |
Rate facts as helpful/unhelpful (trains trust scores) |
Optional Project Scope
Set plugins.hermes-memory-store.project_scoped: true explicitly to opt in.
The default legacy mode is unchanged. Project mode resolves the provider's exact
current session against the core project scope, never an active-project pointer or
tool-supplied session override. Unresolved/ambiguous projects are denied.
Each project uses $HERMES_HOME/holographic/projects/<sha256>.db, with a key derived
from resolved profile home, project identity, and the exact current session's
user_id read from canonical state.db metadata. NULL has its own tagged sentinel,
distinct from empty strings and named users. Custom db_path and the legacy
global database are not consulted. A changed session project switches stores on
the next tool call. on_session_switch releases the old store and binds the new
session under the same lock used by project tools. No global configuration changes.
Trusted caller session_id kwargs must match the binding or receive session_changed;
model arguments cannot override it. During an asynchronous queued switch, callers
must supply that trusted context to fail closed. Direct callers omitting it retain
compatibility and cannot detect the not-yet-delivered switch.
Add and reads return fact_ref; update/remove/feedback require this opaque reference,
not the local integer fact_id. It binds the profile/project/principal digest, a
random persistent store UUID, fact ID and candidate revision hash. The reference is
an identifier, not authorization: scope is always resolved from trusted metadata.
Content/tags/category updates and source replacement invalidate old references;
feedback and retrieval only change ranking and leave references valid. Reopening a
store preserves its UUID; rebuilding creates a different UUID even if IDs repeat.
Restoring an exact backup restores its UUID and candidate versions too, so references
to that exact snapshot can become valid again; there is no external restore counter.
Older project-only stores without principal partitioning are not auto-migrated or read.
{"action":"add","content":"Candidate deployment choice","sources":[{"session_id":"original-session-id","message_id":123}]}
For mutation use {"action":"remove","fact_ref":"<returned fact_ref>"} or
{"action":"update","fact_ref":"<returned fact_ref>","content":"Revised candidate","sources":[...]}.
sources is required for add and content update; source-only updates are supported.
content_hash is optional on
input and always stored after source verification. Message IDs must be positive
integers, supplied hashes must be lowercase SHA-256 hex. The core original-message
reader enforces project/principal membership, lifecycle, secret and multimodal
filtering. Every linked source must still exist and have the same hash on retrieval.
Facts without source links are never returned. Contradiction pairs require both
candidates to pass. Fact/entity/vector/source changes share one SQLite transaction;
a failed final scope/source check rolls back mutations.
Responses expose identity, scope, assertion: candidate_not_confirmed, and
trust_semantics: ranking_only_not_confirmation. A successful add has
status: candidate; reads have status: ok with per-item candidate status.
Trust scores and feedback are ranking signals, not factual confirmation.
Source linkage does not prove that a candidate's wording follows from its source.
Automatic prefetch returns empty in this mode, and built-in memory mirroring and
session-end auto-extraction do nothing even if auto_extract is enabled.
No automatic LLM calls, external service, legacy migration or conclusion-version
engine is added.
Boundaries: source/scope checks are optimistic across the session and project
databases, not a distributed transaction. Revoked candidates are retained locally
but suppressed from tools; remove also requires a currently valid source, so revoked
candidates cannot be purged through these tools (governance limitation). Retrieval applies the existing
candidate limits before source filtering, so a page can underfill; it does not claim
complete recall: reads explicitly return partial: true and coverage.complete: false.
Source edits restored to the exact same safe text/hash become
eligible again. The plugin uses this profile's canonical state.db.