Basic Memory
What's New

Basic Memory v0.24

Filesystem-style read tools, revision-safe writes, documents as notes, time-aware observations, cross-project search in one query, and a manual your agent can read.

Basic Memory v0.24 shipped in October 2026 (v0.24.0 release notes). Install v0.24.1 or later: it pins FastAPI so fresh installs start cleanly. The theme is an agent-grade knowledge base. Agents can browse notes the way they browse a codebase. Writes are guarded so two agents can't silently overwrite each other. PDFs and Office files become searchable notes, and observations can say when they're true.

Read notes like a filesystem

Six POSIX-style read tools now ship on by default next to the rich tools: cat, grep, ls, find, tail, and man. Projects act as mount points: ls / lists them, and a path whose first segment names a project routes to it, so any path a tool returns can be passed straight back.

  • cat reads a whole note, one section by heading, a line range, or up to a token budget. Notes are indexed by heading, so an agent can read the part it needs and skip the rest of the note
  • grep finds keyword matches and returns match windows with surrounding context lines. Pass semantic=True to rank by meaning instead
  • find filters by metadata predicates (status=active, confidence>0.6) and can project frontmatter fields
  • tail shows the most recently updated notes, and ls browses folders

The CLI gains the same verbs: bm cat, bm head, bm grep, bm ls, bm find, bm tail, and bm tree. Set enable_posix_tools=false to hide the MCP versions. See the MCP Tools Reference and CLI Reference.

Cheaper discovery

  • Compact results. search_notes(compact=True) and build_context(compact=True) return identifiers, metadata, and relation targets without note bodies. An agent can pick what to read before it pays for the content
  • Line reads. read_note accepts start_line and end_line and returns numbered lines
  • Metadata-only reads. read_note(include_content=False) returns the title, permalink, path, checksum, and updated_at without the body

Writes that don't clobber each other

When several agents share a knowledge base, one of them will eventually overwrite something it never read. v0.24 makes that impossible when the agent asks for it:

  • Revision guards. Pass expected_checksum to edit_note, or to write_note together with overwrite=True. The write applies only while the note is still the revision you read. Otherwise nothing changes and you get a NOTE_REVISION_CONFLICT with the current checksum. read_note and cat return that checksum in JSON output
  • Refusals are errors. A refused write_note, edit_note, delete_note, or move_note now comes back as an MCP tool error (isError) instead of an ordinary result, so a client checking isError never mistakes a refused write for a successful one
  • Similar-note advisory. When a new note looks like notes that already exist, write_note lists them and asks whether you meant to update one of them. JSON output carries them as similar_notes. Nothing is merged automatically
  • Locked notes. locked: true in frontmatter makes a note read-only to the API and MCP tools: edits, overwrites, and deletes are refused with HTTP 423. Edits made directly on disk still work
  • Authorship. When the runtime knows who is writing, accepted writes stamp created_by and updated_by into frontmatter. In Basic Memory Cloud, API-key writes read <member> via <key name>. Local installs don't supply an author and leave these keys untouched

Documents become notes

PDFs, Word documents, PowerPoint decks, and CSV files can be imported as searchable Markdown:

pip install "basic-memory[pdf,documents]"
bm import document reports/q3-review.pdf

Each import writes an extracted-text sidecar note next to the file (q3-review.pdf.md) that links back to the source with a derived_from relation, plus a provenance run note under document-ingestion-runs/. Extraction runs in a bounded worker process. Re-importing an unchanged file is a no-op, and the import refuses to overwrite a sidecar you've edited. See Documents and PDFs.

Observations that know when they're true

An observation can now carry a time qualifier:

- [decision] @effective:2026-06-10 The cache layer will use Redis.
- [milestone] @due:2026-11-01 Ship the importer
- [event] @occurred:"June 10, 2026" Kickoff with the design team

The kinds are effective, valid (the default), occurred, due, and mentioned, and ranges like @effective[2026-06-10,2026-07-27) work too. search_notes adds valid_at, valid_overlaps, and time_kind filters, so "what was true on June 15?" is a query rather than a guess. See Observations and Relations.

A richer graph

  • Markdown links are relations. Ordinary links to files in the project ([Guide](../guides/Guide.md), reference-style links, /-rooted paths) become links_to relations, as wikilinks already did. External URLs and images are ignored, and your Markdown is never rewritten
  • Deleting a note keeps the links to it. Inbound relations become unresolved instead of being erased, so broken-link reports stay honest and recreating the note re-links them
  • Notes as MCP resources. Every memory:// URL answers the standard MCP resources/read with the note's raw Markdown

Search across projects in one query

search_notes(search_all_projects=True) now runs one scoped query per database instead of one search per project, and a new projects=[...] parameter searches a chosen subset. Results are ranked together, not merged page by page, and each hit says which project it came from. Vector search ranks only the projects in scope, so a small project is no longer crowded out of a shared index.

Other search improvements:

  • Semantic search is always on. The semantic_search_enabled setting is gone. FastEmbed and sqlite-vec are core dependencies
  • CJK and other unsegmented scripts. Full-text search finds words inside Chinese, Japanese, Korean, Thai, Lao, Tibetan, Myanmar, and Khmer text
  • Filtered vector search fills its page. A vector or hybrid search with filters keeps reading until it has enough matching rows, instead of returning a short page
  • Better metadata filters. gte/in work without the $, one field can take several operators, and $contains and $exists are new
  • Any OpenAI-compatible embedding endpoint. The openai provider honors semantic_embedding_api_base and semantic_embedding_api_key, so it works with llama.cpp, vLLM, TEI, LM Studio, and Ollama

See Semantic Search and Metadata Search.

A manual your agent can read

Basic Memory now ships its own manual and serves it over MCP. There is one section-3 page per tool (search-notes(3), write-note(3), and so on), plus reference pages such as comark(7). The server instructions point agents at a tool's page before they first use it. Read the manual with the man tool, with memory://man/<page> resources, or with bm man <topic> in a terminal. The synopses and parameter lists are generated from the live tool schemas, so the manual can't drift from the tools.

Wiki pages and OKF export

  • bm wiki generates deterministic index.md and log.md navigation pages for each folder, and never overwrites hand-written ones
  • bm okf export writes a project as a static OKF v0.2 bundle (wikilinks become standard Markdown links), and bm okf check validates one

Install into your agent in one command

bm install claude-code   # or: codex, tau, pi

bm install installs the Basic Memory plugin or package for each host, with --dry-run and --yes. v0.24 also adds integrations for Tau and Pi, which recall prior sessions at startup and capture knowledge as work settles. They share Coding Session, Task, and Decision schemas with the Claude Code and Codex packages. See Tau, which currently needs a Tau build with upstream support, and Pi.

Operations

  • bm project add waits for indexing before it returns (--no-wait opts out), and bm project index NAME reindexes one project
  • bm status --json reports readiness per stage (files, relations, embeddings), and bm status --wait waits until every stage settles
  • bm prune removes index entries for files your .bmignore or .gitignore now excludes
  • Faster Team push and pull. One recursive listing, eight concurrent transfers, streaming file bodies, and backoff on rate limits
  • Safer HTTP transport. bm mcp --transport streamable-http binds to 127.0.0.1 by default and rejects DNS-rebinding requests

Security fixes

v0.24.0 fixes a high-severity DNS-rebinding issue (GHSA-4gfv-c2mm-mvj2) in the HTTP transports. All earlier releases are affected if you run --transport sse or streamable-http. Stdio, the default, is not. The release also caps graph traversal depth at 5, raises dependency floors, and limits read_content images to PNG, JPEG, and WebP. See the Changelog for details.

Upgrading

v0.24 runs a dozen database migrations automatically on first start. It also changes several MCP and CLI contracts: refused writes are tool errors, the POSIX tools are on by default, read_content returns only PNG, JPEG, and WebP images, bm cloud sync is deprecated, and the HTTP transport no longer listens on every interface.

Before you upgrade an integration or automation, read Upgrade to v0.24 for the breaking changes and the actions they require.

For the complete list of changes, see the Changelog and the v0.24.0 release on GitHub.