Skip to content

Migrate to 0.16

0.16 removes the sleep pipeline and adds sessions, a head server, a curator that works on a branch, and a store policy file. The git tree, the memory file format, index.db, and state.db carry over unchanged. Every command that reads or searches the store works as it did in 0.15.x, apart from the fields the table below removes.

Upgrade in this order:

  1. On 0.15.x, merge or discard every sleep/<date> branch.
  2. If you want a strict write bar, write and commit memhtml.config.json.
  3. Install 0.16.
  4. Replace a sleep run schedule with curate run and a reviewed curate merge.
  5. Put session prune on the schedule, and decide whether to run a head server.
Removed in 0.16 What to use instead
memhtml sleep run and sleep resume memhtml curate run, and curate run --resume to continue a stopped run
memhtml sleep review git log and git diff over the curate/<date> branch, and the report in the curate.run payload
memhtml sleep merge memhtml curate merge
memhtml sleep plan memhtml curate run --dry-run, which shows what a run would do and writes nothing
memhtml sleep status The curate/<date> branches themselves: git branch --list 'curate/*'
memhtml apply --consolidate last-wins --detect-conflicts, which reports a contradiction without changing the write, and memhtml correct to supersede a fact
MCP memory_write_batch consolidate detect_conflicts, and memory_correct
The consolidated_into and superseded_path fields on each batch result, and summary.consolidated Nothing. A batch result carries conflict and near_duplicates, and the summary counts total, written, deduped, failed, and skipped.
lastSleep on memhtml status, and last_sleep on MCP memory_status Nothing. A landed curator run’s record is its branch and its commit.
stuckSleepRuns on memhtml doctor Nothing. A curator run that fails before it lands keeps its operations in its session for --resume.
The MCP resource memhtml://sleep/{run-id} The curate.run payload’s report
The consolidator, which distilled session transcripts into memories during a sleep run Nothing writes memories from transcripts in 0.16. The trace index stays, and memhtml trace search and trace links still read it.

No command answers the sleep.report, sleep.review, sleep.merge, and sleep.plan response types any more. They stay in the response-type list because that list is append-only.

Settle the sleep branches before you upgrade

Section titled “Settle the sleep branches before you upgrade”

0.16 can’t finish a sleep run. A sleep/<date> branch can carry a ledger, .memhtml/sleep/sleep-<date>.pending.jsonl, of database writes the run earned, such as which transcripts it consolidated, which edges it promoted, and which entity merges it applied. memhtml sleep merge lands the branch and then applies that ledger to index.db and state.db. No 0.16 command reads a ledger, so a sleep branch you merge with plain git after the upgrade lands its files and never applies its ledger. Settle every branch while 0.15.x is still installed:

Terminal window
git -C ~/memhtml branch --list 'sleep/*'
memhtml sleep status # let a run in progress finish, or discard it
memhtml sleep review sleep/2026-10-16
memhtml sleep merge sleep/2026-10-16 # land it, ledger included
git -C ~/memhtml branch -D sleep/2026-10-16 # then delete the landed branch
git -C ~/memhtml branch -D sleep/2026-10-17 # or discard it, ledger and all

Settle the oldest branch first. A 0.15.x run that succeeds leaves HEAD on its own branch, so a run started before you check out main again builds on it, and sleep merge refuses the newer branch until the older one lands. Check out main before sleep merge, and read merged in its answer, because a refusal still exits 0. sleep merge keeps the branch it lands, so delete each settled branch with git branch -D. When git branch --list 'sleep/*' prints nothing, the store is ready.

After the upgrade, the reports that earlier merges committed under .memhtml/sleep/ stay in the tree as history. Nothing in 0.16 reads or writes them, and you can leave the directory where it is. memhtml init still creates .memhtml/sleep/.gitkeep in a new store.

In 0.16, records written through a session meet a write bar. The store’s memhtml.config.json decides how strict it is. With no file, the bar refuses no memory type and doesn’t ask a record to name its subject. If you want a strict bar, write and commit the file before you install 0.16. Then the first session commit on the new build is already judged by it:

{
"writeBar": {
"refusedTypes": [{ "type": "episodic", "reason": "a run narrative belongs in the trace index, not in memory" }],
"requireAnchor": true
}
}

0.15.x ignores the file, so committing it early is safe. Once 0.16 is installed, run memhtml config to check the policy in force. Set the store policy lists every key, its default, and why a typo in the file stops writes instead of loosening them.

The same file decides what MEMHTML_SESSION does to the old write commands. With the default v1Doors mode, closed-in-session, a process that has the variable set gets ERR_SESSION_BOUND from memhtml write, apply, correct, and task add. The MCP memory_write, memory_write_batch, and memory_correct tools return it too when the MCP server’s own environment has the variable. 0.15.x never read the variable, so this only matters for an agent runtime that sets it. Set "v1Doors": "open" to keep those commands open everywhere. Write through a session shows how a run writes instead.

Terminal window
npm i -g memhtml
memhtml manifest | jq '.data.commands | map(.name) | map(select(startswith("session") or startswith("curate") or startswith("head") or . == "config"))'

The store needs no conversion. 0.16 adds no index or state migration. memhtml index update picks up where 0.15.x left it.

0.16 adds a few paths under .memhtml/ that git doesn’t track: sessions/ for session logs, snapshots/ for cached copies of the corpus, vectors/ for the head’s vector cache, head.sock for a running head server, and checkout.lock while a writer holds the checkout. A new store’s .gitignore names the first four. A store scaffolded before 0.16 has an older .gitignore, so the first session start, snapshot write, head embed, and head serve each add their path to .git/info/exclude, which stays local to the clone. checkout.lock is an empty directory, which git never lists, so git status stays clean either way.

If the store already has .memhtml/snapshots/ or .memhtml/vectors/ from a pre-release build, those files keep working. Snapshots and vector caches now carry a format key. A file without one reads as format 1, the current format, so nothing needs re-embedding.

A 0.15.x schedule ran the whole pipeline on a branch and left the merge to you:

30 3 * * * cd $HOME && MEMHTML_ROOT=$HOME/memhtml memhtml sleep run >> /var/log/memhtml/sleep.log 2>&1

In 0.16 the curator is one command on the same schedule, and the merge stays a reviewed step:

30 3 * * * cd $HOME && MEMHTML_ROOT=$HOME/memhtml MEMHTML_CURATOR_MODEL=bedrock:global.anthropic.claude-opus-5 memhtml curate run --dense >> /var/log/memhtml/curate.jsonl 2>> /var/log/memhtml/curate.err

The run commits to curate/<UTC date> and never moves main. Review the branch with git, then land it:

Terminal window
git -C ~/memhtml log --oneline main..curate/2026-10-18
git -C ~/memhtml diff --stat main...curate/2026-10-18
memhtml curate merge curate/2026-10-18

curate merge runs the head gate before it lands and refuses with ERR_DISCRIMINATION_FAILED when the branch ranks the records it shares with main worse than the gate tolerates. To throw a run away, git branch -D its branch. --model fake runs the curator with no credential, which is how to try the schedule on a test store first. Curate the corpus covers the run, the review, the gate, curate collapse, and --charter.

Some sleep phases have no replacement. Confidence decay, retention triage, reprieve, relationship mining, edge typing, task detection, and trace consolidation don’t run in 0.16. The curator’s charter covers deduplication, labels, entity aliases, inbox placement, arcs, and dangling links.

The sleep run’s state-export phase is gone too, so nothing runs memhtml state export for you: run it on one machine only, with the other upkeep commands, as preserve the state plane describes.

Variable Default What it does
MEMHTML_SESSION unset The session every process of one agent run writes through. See bind a whole run.
MEMHTML_COMMIT_DEADLINE_MS 60000 How long session commit and session rebase wait for a head server’s answer. 0 means no bound.
MEMHTML_EXEC_POOL_SIZE one fewer than the machine’s available parallelism, 1 to 4 How many session exec scripts a head server runs at once.
MEMHTML_EXEC_WORKER_HEAP_MB 2048 The heap limit of each head server script worker.
MEMHTML_EMBED_WARM_IDLE_MS 0 Off by default. Set above 0, a head server sends one tiny embed after that many quiet milliseconds so the next search finds a warm connection.
MEMHTML_EMBED_DEADLINE_MS 450 How long a head search waits for its query embed before it answers without the vector arm.
MEMHTML_CURATOR_MODEL unset The default --model for curate run and curate collapse.
MEMHTML_MCP_HEAD on Whether the MCP server’s memory_search and memory_recall ask a head server first.

Configure the environment lists every MEMHTML_ variable the binary reads.

In 0.16, memory_search and memory_recall ask a running head server before they read the index, so a record a session committed a moment ago is found before index update runs. With no head server running, the connection fails in a few milliseconds and both tools answer from the index exactly as 0.15.x did. A call that sets include_archived to true or names a non-empty as_of, a query with a double quote, or a query with no term the head indexes always goes to the index.

Set MEMHTML_MCP_HEAD=off in the MCP server’s environment and restart the server to send memory_search and memory_recall to the index as 0.15.x did.

A session commit doesn’t update index.db. memhtml search, memhtml recall, and any MCP call that answers from the index see a session’s records after the next memhtml index update. Keep the index update line from the upkeep commands. memhtml status reports indexFresh: false while the index is behind.

Each session leaves a small log under .memhtml/sessions/, and only session prune removes it. Add a weekly prune:

Terminal window
memhtml session prune --repo $HOME/memhtml --older-than 7d --dense >> /var/log/memhtml/prune.jsonl 2>> /var/log/memhtml/prune.err

session prune never removes a log that still holds operations. It lists one past the cutoff under unlanded, and you can land it with memhtml session rebase --id <id> and then memhtml session commit --id <id> --message <summary> --drop-refused. Run memhtml session prune --older-than 7d --dry-run first to see what it would remove.

A head server is optional. It keeps the corpus loaded so the session and head commands that ask it don’t load the corpus on every call, and it serves the MCP search tools the current tip of the ref it follows. Run a head server covers starting it, the fallback rules, and a service-manager unit.