A memory that can change its mind


Last month your customer moved their order database from Postgres to MariaDB. You told the agent, and it wrote that down. This month you ask, casually, which database the order service uses — and it answers Postgres without hesitation. When you go look, the newer fact is there, the older one is still there too, and nothing in either of them says which one you should believe. The hard part of memory was never storage. It is changing your mind: the world moves, a note turns out to have been wrong, a statement stops holding — and “forgetting” should not mean “the text is still sitting in the file.”

The local fact store holographic spent the last few weeks filling in exactly that half. It used to live inside the Hermes tree as a bundled provider; on October 11 it moved to its maintainer’s own repository and started shipping as a catalog plugin, and on October 13 it was bumped to 0.13.0. That upgrade brought more than a change of address.

From overwrite to revision: five actions

Until recently, there were roughly two things you could do with a remembered fact: add one, or delete it and add it again. The second option quietly changed the fact’s id, so anything pointing at that id broke. A fact now has its own history, and the actions split five ways:

Action When you use it What it means
change the world moved (same thing, new answer) a new version of the same fact; the id stays
correct the note was wrong when written a correction; the superseded wording stops appearing
end it no longer holds, but it was never wrong close it, keep the history
revert you want to undo the last edit back to the previous version
history you want to see what this fact has been through lists every version

Compatibility is handled: the old spellings still work. add supersedes is treated as change (and no longer changes the id), update content as correct, and remove as forget. Your existing scripts do not need rewriting.

Asking “what did we think back then”: as_of

Once history exists, a new question appears: do you want to know what is true now, or what you believed on September 10? The two answers can differ, and during an incident it is usually the second one you need.

Search and list therefore accept an as_of argument such as as_of: 2026-09-10. It answers only from the versions that held on that date, and returns a separate undetermined list for facts whose state on that date cannot be established. An unknown start is reported as unknown rather than invented, which is the part worth noticing. Default search still sees only current facts: historical text lives in its own table and index, so it never pollutes everyday results.

Every version also records where it was written — platform, chat or thread id, session id, and the turn author’s id and name. Chat titles are never stored, so provenance does not quietly drag your group names into the database.

Forgetting for real

On many systems “delete” flips a flag while the text stays in the file and in backups. forget goes further: the fact and every version of it are removed, both full-text indexes are rebuilt, the operation runs with secure_delete, then VACUUMs and truncates the WAL — the goal being that the text leaves the file, not just the query results.

What remains is a tombstone holding the id and a keyed hash, never the text. That keeps auto-extraction from resurrecting the fact, and lets other tools clean their own copies by id. The cost is worth stating plainly: this cannot be undone.

One bot, many unrelated groups: scope: chat and scope: thread

If your bot sits in several customer groups, cramming every fact into one database is a liability. scope: chat gives each conversation its own database; scope: thread goes one level finer, per forum topic. Both use the chat and thread ids the core already passes to memory providers — no core changes and no routing logic of your own.

Three safety lines: credentials, images, untrusted text

A memory store has an easily overlooked risk surface: whatever it holds is injected into every later turn. Writing is therefore not enough — content is checked on the way out too.

  • Credentials with a value are never stored. A credential word with its value next to it (password hunter2, API key sk-…) is refused with a reason; the word alone is still a legitimate fact (“I use a password manager”). 0.13.0 widened the window to three words while cutting false alarms: the token is 0.125 USD is a price, not a password.
  • An image is not a fact. Markdown or HTML image syntax is never treated as a fact, because the client that renders it fetches that address itself, and data can ride along in the path or the query string.
  • Recall checks again before injecting. In 0.13.0 a fact is re-examined on the way out: chat-role or tool-call markup, instruction-like phrasing, a credential with its value, invisible characters and images all keep a fact out of recall, logged once per process. Note that this does not delete anything — search, list and history still show it, because you asked and you are entitled to correct or forget it.

One trap worth knowing: writes from cron

If you run memory maintenance on a schedule — a nightly tidy, say — there was a bug that stayed quiet for a long time: since 0.2.0, memory writes from a cron job simply did not take effect. The core passes agent_context: "cron", and the plugin treated every such context as read-only, so your maintenance job kept reporting success while storing nothing. The nightly consolidation plugin is the kind of thing that runs into this.

That is now split apart: explicit fact_store / fact_feedback calls from cron write again (cron_writes, on by default), while automatic writes — auto-extraction, mirroring, recall counts — stay off there. A manual tidy-up script can do its job without quietly accumulating facts unattended.

About the move: there is nothing for you to do

Holographic used to live in the core tree (plugins/memory/holographic/); since October 11 it is a catalog plugin maintained by itpartypattaya. The good news is that only the code changed address:

  • the provider name is unchanged — memory.provider: holographic still works;
  • the config section is unchanged — still plugins.hermes-memory-store;
  • the database is unchanged — still $HERMES_HOME/memory_store.db, or the db_path you set;
  • the tools are unchanged.

The upgrade path is automatic: hermes update installs the catalog plugin for every profile home that names the provider, and if you update through the desktop app the agent installs it and tells you the first time it starts. If the install cannot happen, you are not left silently memory-less — with security.allow_lazy_installs: false, offline, or a declined install, the warning names the exact hermes plugins install holographic command for that profile. Two commands confirm the state:

hermes memory status
hermes plugins list

The full install and switch flow:

hermes plugins install holographic   # from the plugin catalog
hermes memory setup                  # pick a provider interactively
# or set it directly:
hermes config set memory.provider holographic

The mechanics of the move match what we wrote in memory providers leaving core; the difference this time is what the plugin grew afterwards. (If you installed Nous Research’s interim copy from its own repository, hermes plugins update holographic moves you onto the catalog entry and your data stays put.)

How it compares

Option What it stores Best for
Built-in MEMORY.md / USER.md preferences and facts you always want loaded everyone (always active)
holographic (this post) a local SQLite fact store with version history and trust scores fully local, when you need revisions and real deletion
Semantic memory (LanceDB) long-term memory retrieved by vector similarity recall by meaning rather than by fact
Nightly consolidation (dreaming) corroborates candidate facts overnight and proposes what to keep you already keep a fact store and want it to converge

Multilingual recall also gained ground. Simplified and Traditional Chinese are recognised as each other, Japanese spelling variants match, German compounds split both ways, Russian same-root words come from a dictionary, and English, Spanish, French and Portuguese word forms are covered — data from Open English Wordnet, jieba, SudachiDict, Wikidata Lexemes and DerivBase.Ru, under CC BY 4.0, MIT, Apache-2.0 and CC0 licences respectively. The maintainer’s blind-set numbers: Chinese questions written in the other script went from 33% to 100% recalled, and Russian same-root questions from 83% to 92%. Those figures are the maintainer’s own measurements — useful, not gospel. If you want less noise, recall_indicator (on by default) and auto_extract (off by default) are the two switches to reach for; trust moves +0.05 for helpful feedback and −0.10 for unhelpful.

The short version

  • The world changes and notes turn out wrong. A memory that can revise itself deserves the name: change / correct / end / revert keep the versions, and as_of takes you back to what held on a given day.
  • Forgetting is a destructive operation: every version, every index, every leftover in the file, leaving a tombstone with no text — and it cannot be undone.
  • Re-checking content before injection is what makes this store safe to trust: credentials, images and imperative-sounding text never ride into the next turn unnoticed.
  • If holographic is already configured, upgrading asks nothing of you. If it is not, it is now a catalog plugin and one command installs it.