Upgrade to v0.24
v0.24 applies its database migrations automatically, and most local setups need no manual action. Install v0.24.1 or later: v0.24.0 can fail on a fresh install with a FastAPI import error (see Troubleshooting). MCP clients, scripts, and cloud sync workflows do need a review. Work through the sections below before you rely on existing automation.
Update MCP clients
Refused writes are tool errors
A refused write_note, edit_note, delete_note, or move_note now returns an MCP tool error (isError: true) instead of an ordinary result. That includes:
write_noteto an existing note withoutoverwrite- A revision conflict on
expected_checksum(NOTE_REVISION_CONFLICT) - A note that moved (
NOTE_PATH_CONFLICT) - A directory outside the project
- A concurrent-edit conflict on
edit_note - A refusal from a read-only API key or a locked note
Nothing is written in any of these cases. In JSON mode the error message carries the same payload as before (action: "conflict", error: "NOTE_ALREADY_EXISTS", and so on). Clients that parsed the result text for "Edit Failed" or "Move Failed" should check isError instead. Retry logic should treat a refused append as not written: it never is.
Six more tools are visible
The POSIX read tools cat, grep, ls, find, tail, and man are on by default, so clients see six more tools, and the server instructions describe projects as mount points. To hide them:
bm config set enable_posix_tools false
Other MCP contract changes
edit_note(operation="replace_section")fails when the exact heading isn't in the note, instead of appending a duplicate section. Give headings in full (## Open items #urgent). Useappendto add a new section on purposebuild_context(compact=True)no longer loads observations, and compact JSON no longer has anobservationskey. Amemory://title URL that matches more than one note is refused. Pass the permalink instead- Boolean searches (
AND,OR,NOT) without an explicitsearch_typenow run as full-text, soNOTexcludes a term found anywhere in the note read_contentresolves only exact paths, permalinks, titles, and ids. A miss is "Resource not found" rather than a fuzzy match on another file- No session project. A call without
projectalways uses the default project, locally and in the cloud.write_noteandedit_notenow end with[Project: 'name'] delete_projecton a cloud-routed project always deletes the project's cloud files.delete_notesapplies only to local projectsread_contentimages. Only PNG, JPEG, and WebP images are returned. GIF, TIFF, BMP, and other image files return "Unsupported image format" instead of a JPEG. Text, JSON, and other binary files are unchanged- Traversal limits.
build_contextandrecent_activityacceptdepthfrom 1 to 5 (default1) and refuse larger values with an error naming the limit. The/memory/recentAPI capspage_sizeandmax_relatedat 100 and returns 422 beyond that
Update CLI automation
- Missing notes exit 1. Reading a note that doesn't exist exits with status 1 in every output mode, and JSON reads carry
error: "NOTE_NOT_FOUND". Scripts that checked for null fields with exit status 0 must check the exit status bm import documentresolves a relative path against the project root, not the current directory, matchingbm lsandbm catbm project addnow indexes a local project before it returns. Pass--no-waitto keep the old behaviorbm project add --cloud --visibility privateis refused. Cloud projects areworkspaceorshared
bm project remove on cloud projects
bm project remove on a cloud-routed project now always deletes the project's cloud files. There is no longer a way to keep them. The files can be recovered only from a cloud snapshot (bm cloud snapshot list). The command asks for confirmation, which --yes skips.It also no longer deletes the local sync directory as a side effect of --delete-notes. Pass the new --delete-local-files flag for that. Local projects behave as before.
Move off bm cloud sync and bisync
bm cloud sync, bm cloud bisync, and bm cloud bisync-reset are deprecated and will be removed in a future release. They still work on Personal workspaces, print a deprecation notice on every run, and exit with that notice on Team workspaces. Switch to the additive push/pull workflow:
bm cloud pull --name my-project # bring cloud changes down
bm cloud push --name my-project # send local changes up
Push and pull never delete files on the destination, and --on-conflict controls what happens when a file differs on both sides. See Cloud Sync.
Update configuration
These settings are retired. An existing value is ignored rather than rejected, so nothing breaks, but you should remove them:
| Setting | What changed |
|---|---|
semantic_search_enabled / BASIC_MEMORY_SEMANTIC_SEARCH_ENABLED | Semantic search is always on. Installs that had turned it off now download the embedding model and build vectors |
disable_permalinks / BASIC_MEMORY_DISABLE_PERMALINKS | Markdown notes always get a permalink. Notes indexed without one are backfilled during ordinary scans, which writes permalink into their frontmatter |
Other configuration changes:
- Environment overrides stay out of
config.json. A one-offBASIC_MEMORY_*variable used to become permanent the next time anything saved config. A save now keeps the file's own value. Commands that name a setting (bm config set,bm project default, and so on) still save it BASIC_MEMORY_PROJECT_ROOTrefuses project names that contain/(such asResearch/2026), so each project under a shared root stays one top-level directoryEmbeddingStatusgainsvector_runtime_available.semantic_search_enabledis still emitted as a deprecated alias of it, so older CLIs keep working against upgraded servers
Check the HTTP transport
basic-memory mcp --transport streamable-http (or sse) now binds to 127.0.0.1 by default instead of 0.0.0.0. The unauthenticated HTTP server is no longer reachable from the network unless you ask for it:
basic-memory mcp --transport streamable-http --host 0.0.0.0
A non-loopback --host prints a warning. On a loopback bind, both HTTP transports reject requests whose Host or Origin header is foreign (DNS-rebinding protection). Set FASTMCP_HTTP_ALLOWED_HOSTS and FASTMCP_HTTP_ALLOWED_ORIGINS to allow more. The official Docker image already passes --host 0.0.0.0 and needs no change. See Docker.
Let migrations finish
About a dozen revisions run automatically on first start. The ones you might notice:
- Section index. A new
note_sectiontable backs heading-levelcatreads - Time index. A new table indexes observation time qualifiers for
valid_atandvalid_overlapsfilters - Script n-grams. Full-text search gains unigrams and bigrams for CJK and other unsegmented scripts. Existing notes gain this recall after a reindex (
bm reindex --search) - Project-partitioned vectors. The sqlite-vec table gains a
project_idpartition key. Existing vectors are carried over without re-embedding - Relations survive deletes.
relation.to_idbecomesON DELETE SET NULL. Relations lost to the old cascade stay lost. Re-index the affected notes to bring them back as unresolved - Search uniqueness by row kind, readiness timestamps (
last_indexed_at), deferred-embedding tracking, and async_checksumthat stops one-way sync tools from triggering endless re-indexing
Markdown files remain the source of truth and the index is rebuildable. If you want a pre-migration snapshot, back up memory.db before upgrading.
Postgres deployments
On Postgres, vector nearest-neighbour queries now run on the HNSW index with an iterative scan, which requires pgvector 0.8 or later. An older extension is reported as a dependency error instead of quietly returning short result pages. Vector storage is created when the database is initialized, never while serving.
Continue setup
- What's New in v0.24 — the highlights
- MCP Tools Reference — new tools and parameters
- CLI Reference — new commands and changed flags
- Configuration — current settings

