This is the story of how a schema migration bug, a chicken-and-egg update check, and a nested Tokio runtime turned 72 hours into three patch releases. We're documenting it in full because every failure mode here is worth remembering — and worth avoiding.
0.8.2 shipped schema V3 with temporal edge validity. On homogeneous chains, the
V2→V3 migration worked perfectly. But real chains are messy: many contain thoughts
written under V1 sitting alongside V2 thoughts. When
load_binary_thoughts() peeked only the first thought's
schema_version and applied that format to the entire chain, mixed chains
crashed with UnexpectedVariant or UUID parsing errors.
The chain data on disk was never corrupted — the append-only hash chain was intact. The read path just couldn't handle version diversity within a single chain.
We replaced load_binary_thoughts() with
load_binary_thoughts_per_thought(), which reads each thought
individually, peeks its own schema_version, and dispatches to the
correct deserializer. 11 new migration tests were added covering all 30
ThoughtType variants, all 11 ThoughtRelationKind variants,
all ThoughtRole variants, signed thoughts, and mixed V1+V2+V3 chains.
WHITEPAPER.md was rewritten into 12 sections to accurately document the
per-thought version boundary that we'd previously gotten wrong.
Here's the part that hurt: the update check ran after migrations.
When the daemon started, it would first load and migrate the chain, then
check for a newer version. If the migration crashed, the update check never ran —
so the fix couldn't install itself. Users had to manually
cargo install mentisdb --force to get the patched version.
0.8.4 moved the update check before any chain loading or migration. It also added two new CLI subcommands:
mentisdbd update — check for updates and prompt to installmentisdbd force-update — download and install the latest version
without promptingWith 0.8.4, a daemon that starts on a broken chain can still check for and install a fix. The chicken-and-egg loop is broken.
0.8.4 introduced a new crash: run_update_standalone() created a
nested Tokio runtime inside #[tokio::main]. Tokio
panics with "Cannot start a runtime from within a runtime" when you try
this. The symptom was immediate: running mentisdbd update or
mentisdbd force-update would panic every time.
The fix: make run_update_standalone() async and let it ride on the
existing #[tokio::main] runtime instead of spawning its own. One
function signature change, one panic eliminated.
#[tokio::main] already
creates a runtime. Calling Tokio::runtime::Runtime::new() inside it
will panic. Make the inner function async and .await it instead.
ThoughtType variants passed unit tests. The migration crashed because
the integration path — load entire chain, peek first version, deserialize
all — wasn't tested. Coverage of the library isn't coverage of the dispatch.
The pattern: each bug was hidden by the fix for the previous one. The migration crash (0.8.2) was fixed (0.8.3), but the update catch-22 meant users couldn't get the fix automatically. The update fix (0.8.4) introduced a runtime panic (0.8.5). Three releases, three different failure modes, each invisible until the previous failure was resolved.
cargo install mentisdb --force
The --force flag is required — without it,
cargo install will see an existing binary and skip the installation.
Make sure you're on 0.8.5 or later.
MentisDB is an open-source durable memory layer for AI agents. It stores memories in an append-only hash-chained log, retrieves them with hybrid lexical+semantic+graph search, and runs entirely locally with no cloud dependencies. GitHub · Docs · Website