This blog has been dead for a while. The repository has not — there are roughly two dozen merged changes sitting on main since 3.15.1 went out in July, and nobody who isn't reading commit messages would know. That's my fault, so here's the catch-up.
One thing first, so nobody upgrades into a surprise: 3.16.0 is not released. Everything below is merged to main and unreleased. If you install from PyPI today you are on 3.15.1 and none of this is in your hands yet. I am being pedantic about this because 3.15.0 never actually reached PyPI, and I would rather over-communicate than repeat that.
The breaking one: unknown embedding models now fail loudly
This is the most important change on main, and it comes from a community contributor — Paolo Antinori, with review from Denis that made the final patch considerably sharper than the first draft.
The bug: if you pointed Mnemosyne at an embedding model it did not
recognize, it silently assumed 384 dimensions. A vector table is
dimensioned once, at creation. So that silent guess got baked into a
fresh database permanently, and vector search was corrupt from the
first write — quietly, with no error, for anyone using a model outside
our built-in table. If you ran a custom endpoint with something like
mxbai-embed-large,
this was you.
Dimension resolution is now centralized in one place, checks an
explicit override first, then the model table, and raises on an unknown
model instead of guessing.
The breaking part: a custom
endpoint with a model not in our table now requires
MNEMOSYNE_EMBEDDING_DIM
set explicitly, or startup exits with an actionable error. Blank values
from Docker Compose and .env files are treated as unset rather than as
an invalid explicit value, because that is what people actually mean.
If your store was created under the old silent-384 behavior, setting the true dimension can trip the existing mismatch guard. Use the documented reindex path — the override is not a one-step fix, and the docs say so.
Related, and smaller: the
bge-m3
alias now resolves to its real 1024 dimensions instead of erroring, and
mnemosyne doctor
now reports the resolved dimension alongside the model, so you can
confirm your setup without reading a traceback.
A theme: operations that used to report success while failing
Looking back over this batch, the pattern is unmistakable. Most of these are not "the feature didn't work." They are "the feature didn't work and told you it did," which is strictly worse.
- Vector rebuilds. Reindexing now fails on incomplete embedding batches and failed derived-vector writes rather than declaring victory over a half-built index. A failed repair also exits non-zero, which matters if you are running it from a script.
-
MCP invalidation. Targeting
a memory outside your scope returned success and changed nothing. It
now returns
memory_not_found, preserving scope isolation instead of quietly pretending. - Invalidation replacements. A replacement id that is unknown or out of scope is now rejected before the target is touched, so a rejected replacement cannot leave a link behind.
- Recall diagnostics were entirely dead under the polyphonic recall flag — the flag production deployments actually use. The polyphonic branch returned before the recording block, so the diagnostics tool reported zero calls no matter how much traffic you pushed through it. The voices now map onto the existing diagnostic tiers and record properly.
-
Windows backup paths.
mnemosyne backup /c/...from Git Bash silently landed on a drive-relative path and reported success for a location you never asked for. Ambiguous destinations are now rejected up front. -
Silent plugin import failures. A
bare
except: passmeant a missing file could disable memory injection and tool registration in Hermes with zero diagnostic output. It logs now.
Cache coherence and configuration that means something
Enhanced Recall keeps a persisted query cache, and it had two holes: a fresh write did not evict results another instance had warmed, and an invalidation left stale rows visible until the TTL expired. Both are closed. Live peer coherence between running instances is still tracked separately — I would rather name the remaining gap than let you assume it isn't there.
Configuration got the same treatment. Recall weights and the degradation batch size were read once and frozen, which made hot-reloading them theater. They now resolve as config file, then environment, then defaults, on every pass — and enhanced-recall cache entries are isolated by the effective weight snapshot, so changing weights cannot serve you results computed under the old ones.
There is also a new knob,
MNEMOSYNE_LEXICAL_GATE_MIN,
for overriding the lexical admission gate, documented alongside the
measured recall-flag data rather than as a mystery dial.
Hermes integration
Hermes 0.6.0 shipped, and the provider work behind it is a decent chunk
of this batch. Session rebinding was the big one: rotating your agent
session with
/new,
/resume,
/branch,
undo, or context compression left memory bound to the previous session,
so subsequent writes and reads went to the wrong place entirely.
Alongside that: a runtime compatibility guard that rejects a Mnemosyne install whose virtualenv targets a different Python minor version before it can fail confusingly later, root-only plugin installs, shared tools correctly advertised in the plugin manifest, hardened automatic prefetch relevance, and packaged manifest versions that match the released package.
Smaller things worth knowing
-
mnemosyne --versionexists now, and reports without initializing your data. So doesmnemosyne-hermes --version, which reports both core and provider versions. - A MiniMax provider preset with regional endpoints and model config.
- Persona token-cap truncation no longer drops small sections just because a large one didn't fit — it skips the oversized section and keeps evaluating.
- The hygiene audit-to-clean pipeline works end to end again, including banks with legacy importance values outside the normal range.
- File-import dry runs now pass through every surface — core, MCP, both Hermes providers, CLI — and report a distinct status so nothing can mistake a simulation for a completed import.
What this batch says about the project
Very little of this is glamorous. There is no headline feature in the list at all. The shiny thing I am working on — multimodal memory — is a back-shed project with no release attached to it, and it stays there until it earns its way out. This batch is the unglamorous half: making failures loud, making configuration real, making Windows work, closing cache holes.
It is also the first batch that is visibly not one person's work. The breaking fix came from an outside contributor. Most of the "reports success while failing" fixes came from Denis , who is now co-maintainer. Several of the bug reports came from users who dug in far enough to hand us a diagnosis rather than a symptom.
3.16.0 will go out when the remaining work is done and the release tooling has verified it actually reached PyPI. Until then, the changelog on main is the source of truth, and I will try not to let this blog go quiet again.
Found something broken? Open an issue. A bug report with a reproduction is worth more to this project than almost anything else you could send us, and this release batch is the proof.
