Ctrl K
ComunidadGuías…

CHANGELOG.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# CHANGELOG

## Unreleased

### Breaking Changes

- **Note formatting is removed.** The `format_on_save`, `formatter_command`,
  `formatters` and `formatter_timeout` settings, their `BASIC_MEMORY_*` environment
  variables, the `bm format` command and the bundled mdformat dependency are gone.
  Since 1.0 accepts a note's bytes before writing the file, `format_on_save` had
  stopped running for `bm_write` and `bm_edit` (#2005). Formatting the file after the
  write would make it differ from the accepted note, so the next sync would record it
  as an outside edit and the agent's next `expected_checksum` would conflict. Notes
  are now stored exactly as written. Old keys in `config.json` are ignored. To format
  notes, run your formatter from your editor, or over the project folder yourself.

## v1.0.0 (2026-10-29)

Basic Memory 1.0 is a clean-house release. The MCP server exposes only the `bm_*`
tools, the CLI is built on those same tools, and the pre-1.0 tools, commands and
compatibility code are removed rather than aliased. `docs/1.0.md` and
`bm man tools-migration` map every old tool and command to its replacement.

### Breaking Changes

- **SPEC-35.2: the MCP server exposes only the 1.0 `bm_*` tools**: `bm_read`, `bm_write`,
  `bm_edit`, `bm_delete`, `bm_move`, `bm_search`, `bm_context`, `bm_list`, `bm_find`,
  `bm_project`, `bm_schema` and `bm_man`, plus the separate, opt-in
  `bm_project_delete`. They replace the earlier tools one for one or by command:
  `read_note`/`read_content`/`view_note`/`cat` become `bm_read`, `search_notes`/`grep`
  become `bm_search`, `build_context` becomes `bm_context`, `recent_activity` and the
  project tools become `bm_project`, and the schema tools become `bm_schema`. The old
  tools and their modules are deleted, with no aliases. Arguments change too:
  `project` takes a name, a workspace-qualified name or an external ID; search takes
  `mode`, `filters`, `items`, `since` and `all_projects`; edits take `command`; context
  takes `identifier` and `since`. Refusals are MCP tool errors with a typed `error`
  (`NOT_FOUND`, `ALREADY_EXISTS`, `REVISION_CONFLICT`, `LOCKED`, `OUTSIDE_PROJECT`,
  ...). Update MCP allowlists, agent instructions, hooks and recorded fixtures, then
  restart clients so they reload the tool schemas (#1838, #1839, #1849, #1944, #1947,
  #1959, #1962, #1963, #1964).

- **Every project-scoped tool requires `project`.** `bm_read`, `bm_write`, `bm_edit`,
  `bm_move`, `bm_delete`, `bm_list`, `bm_find`, `bm_context` and `bm_schema` require a
  nonempty `project`, even with one project or a configured default.
  `bm_search` requires `project`, `projects` or `all_projects=true`, and
  `bm_project(command="recent")` requires `project`. A relative path no longer selects
  a project because it contains a slash. `bm_list(path="/")` lists the project's
  root; `bm_project(command="list")` lists projects (#1934).

- **The ChatGPT `search`/`fetch` adapters are no longer in the local server.** The
  hosted Cloud server provides them (#1964).

- **`bm tool` mirrors the `bm_*` tools.** One subcommand per tool (`read`, `write`,
  `edit`, `move`, `delete`, `list`, `find`, `search`, `context`, `project`, `schema`),
  with flags named after the tool's parameters (`--directory`, `--note-type`,
  `--command`, `--since`, `--mode`, `--items`, `--filters`). The subcommands
  `recent`, `projects`, `workspaces`, `validate`, `infer` and `diff` are removed, as are
  the old flags (`--folder`, `--operation`, `--after_date`, `--meta`), `--project-id`
  (`--project` takes an ID), `--plain`, and automatic JSON when piped. Output is the
  tool's text, or its JSON with `--json` (#1943).

- **`bm cat`, `head`, `grep`, `ls`, `find` and `tree` run on the `bm_*` tools, and
  `bm tail` is removed** (use `bm tool project recent`) (#1960). Behavior changes:
  - `--plain`, the Rich tables and JSON-when-piped are gone; output is the tool's
    text, or `--json`. `--project-id` is gone; pass the ID to `--project`.
  - Without `--project`, the default project is used. A `<project>/path` prefix no
    longer selects the project by itself, and a prefix that disagrees with
    `--project` is refused.
  - `bm ls /` lists the default project's root; `bm project list` lists projects.
  - `bm cat --lines` always counts the whole file, frontmatter included, and slices
    print numbered lines under a `Lines N-M of T` header. `bm head` loses
    `--frontmatter`/`--no-frontmatter` and prints numbered lines.
  - `bm grep -C/--context-lines` becomes `-C/--lines`, and `grep -C` drops notes with
    no matching line. `bm grep` returns notes only.
  - `--page-size` is 1-100 on every verb, and `bm find --fields` prints the tool's
    text. New flags: `bm grep --path`, `bm ls --glob`, `bm ls --sort`.

- **`bm cloud sync`, `bisync` and `bisync-reset` are removed.** They could delete
  cloud-only or local files. Use `bm cloud pull` and `bm cloud push`, which never delete
  on the destination and stop on conflicts until you pick `--on-conflict`. The old
  commands print the matching pull/push command and exit 1 without touching files
  (#1953, fixes #1845).

- **`bm schema` resolves its project like `bm tool`.** `--project` accepts a
  `workspace/project` name or a project ID, an unknown project fails with the tool's
  error, and with no `--project` and no default project it exits 1 (#1959).

- **LiteLLM is an optional extra.** The default install no longer includes the
  LiteLLM SDK. If you use LiteLLM embeddings or reranking, install
  `basic-memory[litellm]` (`441166185`).

### Features

- **`bm_read` reads line ranges of plain text files**, such as `.txt` and logs, with
  `start_line`/`end_line` (#1960).

- **Chat imports return the paths of the files they wrote** (#1878).

- **`bm_man` and 1.0 manual pages**: every `bm_*` tool has a section 3 manual page,
  served over MCP and by `bm man` (`aa8bf2644`).

- **`bm doctor` reports problems in your real projects, with the command that fixes
  each one.** It checks the project path, index readiness, search index integrity
  (duplicate, orphaned and missing rows) and note materialization, and only reads: it
  never changes a project, the config or the database. `--json` prints the full report.
  The write/index/search self-test runs in a sandbox with its own home, config and
  database. Cloud projects are listed as skipped (`e607f817d`, `60845266d`,
  `d52dbc986`).

- **`memory-doctor` skill** teaches an agent to run `bm doctor` and walk you through
  its suggested fixes (`573c3dfab`).

### Bug Fixes

- Startup project indexes were unowned background tasks that could outlive the
  server's database. They now run with the watcher, stop with it, and a project whose
  index fails is logged without stopping the watcher (#1967).

- **#1956**: Title search ranks the note whose title equals the query first, ahead of
  longer titles that contain it. Thanks @Flynn-Kawolsky for the report and the minimal
  repro (#1957).

- **#1852**: File events that arrived while the watcher reloaded its project list were
  dropped. They are now kept and indexed. Thanks @SWSAmor for the precise reproduction
  (#1951).

- One project whose directory no longer exists stopped file watching for every
  project. The watcher now leaves that project out and logs it (#1971).

- On SQLite, `a AND NOT b` returned no results; it now means `a NOT b`, as it already
  did on Postgres (#1972).

- **#1826**: A note whose search rows were lost (a migration that recreated the
  search index, a dropped refresh) stayed unsearchable, with no vectors, because its
  unchanged file never reached an index batch. Each index pass now rebuilds missing
  search rows and their vectors, and project status counts those notes (#1954).

- **#1862**: With an OpenAI-compatible endpoint that returns unnormalized vectors
  (such as Volcengine Ark), every semantic match fell below the similarity floor, so
  vector and hybrid search returned nothing on SQLite. The OpenAI provider now
  normalizes vectors; with a custom `api_base`, the next index pass re-embeds stored
  vectors automatically. Thanks @MbappeWU, who diagnosed this and proposed the fix in
  #1869 (#1948).

- Search ranking weights a note's title above its body in the SQLite bm25 score and
  keeps weighted scores across metadata filters (`56ba5a96a`, `e2a1a0780`,
  `6eda1221c`).

- Relation sources are re-embedded after a forward reference resolves (#1884).

- Ignore rules for a directory apply to the files under it, nested directory rules
  match by ancestry, and a byte-order mark at the start of an ignore file is skipped
  (#1929, #1949).

- Moves keep the configured project root (#1930). A timed-out search is reported as a
  tool error (#1942). Malformed `memory://` context locators return 400 (#1885). The
  JSON project list honors a server's project constraint (#1937).

- Tool output reads better: retry hints name the project as the call did, filter-only
  results show no score, `tag:` queries are repeated as typed, and section errors end
  their list with a period (#1974).

- The OpenClaw plugin works on OpenClaw 2026.10 (#1966).

- **#1817**: Files copied into a newly created project's folder before the watcher
  reloaded were never indexed, and the watcher ignored projects added after startup.
  The watcher now reloads project config, and after it attaches to a new project it
  runs a catch-up index pass, including while hidden-file activity continues. Thanks
  @TPSJASPER (#1861, #1866).

- **#1850, #1853**: On SQLite, deleting a large set of vector chunks failed with
  "Expression tree is too large", and an interrupted search-index migration left a
  scratch table that blocked the next startup. Deletes now run in batches of 200, and
  the migration drops a leftover scratch table before rebuilding. Thanks @MbappeWU
  (#1857, #1859, #1865).

- A stale read from object storage could save an older version of a note as a new
  accepted version, silently rolling the note back. A version that a newer accepted
  change replaced is now promoted only after an authoritative re-read confirms it
  (`a5b557acd`). A move that was superseded by a later one now cleans up its old file
  (`2e2c1be8e`).

- **#1798**: `bm doctor` offers a recovery for note saves left in flight by a process
  that exited. While file indexing still has work owed, duplicate, missing and orphaned
  search rows are warnings that the index pass may clear; they become errors once
  indexing settles.

- FastAPI is upgraded to 0.162.0, with the read cache keeping request identities
  stable on the new version. This replaces the 0.139.0 pin from v0.24.1
  (`2f66021c1`).

- **#1811**: Creating a local project with the name of an existing one but a different
  path is refused with `ALREADY_EXISTS`, naming both paths, instead of reporting
  success. The same path stays an idempotent re-index. Cloud creates skip the check,
  since hosted paths come from the project name (`efd157061`, `e03c2f28f`).

- Search normalizes recognized project prefixes in queries (`9a0211f96`).

- OpenClaw keeps explicit search filters and ignores empty tag shortcuts
  (`20cbcb538`, `bef49f458`). Tau prefers its native tool registrations
  (`2506147f9`).

- Recovery guidance in tool errors and the manuals now name the `bm_*` tools
  (#1864, #1868).

### Security

These come from a security review of the codebase (CodeRabbit deep scan).

- Project boundaries are enforced where imports and storage write files, against the
  resolved project root (#1931, `e46f1b4c5`).
- Note YAML rejects aliases and merge keys, which could expand without bound (#1933).
- ZIP imports, search queries, CSV previews, Markdown directive scanning, find/replace
  output, section heading suffixes and ChatGPT conversation graphs are bounded (#1939,
  #1927, #1926, `74e41b739`, `5f8a0303a`, #1916).
- Atomic file writes stage privately, and rclone credentials are created with private
  permissions (#1925, `1b8713e49`, `df611b0dc`).
- Literal directory prefixes are escaped before moves (#1915). Legacy directory uploads
  skip file symlinks, and upload destinations are validated after normalization
  (`d6d289d3e`, #1928).
- `bm cloud api-key save` prompts for the key without echoing it, so the key no longer
  has to appear in shell history (#1938).

## v0.24.1 (2026-10-22)

### Bug Fixes

- On a fresh install, `bm status` and other commands that load the API failed with
  `cannot import name 'get_flat_dependant' from 'fastapi.dependencies.utils'`. The read
  cache imports that FastAPI helper, FastAPI removed it in 0.140.7, and the
  `fastapi>=0.136.1` floor let new installs pick up 0.140.13 or later. FastAPI is now
  pinned to exactly 0.139.0, the version CI tests. Existing installs can work around it
  with `uv tool install basic-memory --with 'fastapi==0.139.0'`. Reported by lastguru.

## v0.24.0 (2026-10-22)

### Security

- **GHSA-4gfv-c2mm-mvj2** (high): A web page could reach a `basic-memory mcp --transport
  sse` or `streamable-http` server bound to `127.0.0.1` through DNS rebinding and call
  every MCP tool, including reading and deleting notes. The HTTP transports have no
  authentication, and the server did not check the `Host` or `Origin` header, so binding
  to localhost was not enough. Both HTTP transports now reject a foreign `Host` or
  `Origin` on a loopback bind and bind to `127.0.0.1` by default (#1697, see Breaking
  Changes). Releases before v0.24.0 are affected. Stdio, the default transport, is not.

- **GHSA-pqm2-2wxw-p5hx** (low): In hosted deployments a project's path is an
  object-storage prefix, but path validation still resolved it on the API host and
  followed the host's symlinks. A project named after a host directory, such as `etc`,
  let a caller learn which host paths are symlinks from whether a request was refused
  or returned "not found". No file contents were exposed. Remote project paths are now
  checked lexically and never touch the host filesystem. Local projects keep the
  symlink-aware check (#1807).

- **#1804**: `build_context` and `recent_activity` accepted any `depth`, and
  `/memory/recent` had no limit on `page_size`, `page` or `max_related`. On a densely
  linked project one deep call could run until the client timed out, and any
  authenticated caller, including a read-only API key, could repeat it. `depth` is now
  1-5 (the default stays 1), and `page_size` and `max_related` on `/memory/recent` are
  at most 100. The MCP tools refuse out-of-range values with an error naming the limit;
  the API returns 422.

- **#1805**: Security floors for direct dependencies: pyjwt >= 2.15.0 (14 advisories,
  reached through FastMCP's bearer auth) and litellm >= 1.91.5. The lock refreshes
  aiohttp, urllib3, multidict, cryptography, certifi and yarl, and FastMCP moves to
  4.1.3. Pillow cannot move to 13 while fastembed pins `pillow<13`, so `read_content`
  now decodes only PNG, JPEG and WebP and refuses other formats, GIF included
  (GHSA-74r2-7ff9-mjj2), before Pillow parses them. The Docker image requires Debian's
  October 2026 `ca-certificates` update and upgrades pip's own CA bundle.

### Breaking Changes

- **#1805**: `read_content` shows only PNG, JPEG and WebP images. GIF, TIFF, BMP and
  other image files return "Unsupported image format" instead of a JPEG. Text, JSON and
  other binary files are unchanged.

- **#1683**: A refused `write_note` is an MCP tool error (`isError`), as a failed
  `delete_note` or `move_note` is (#1641). This covers an existing note without
  `overwrite`, a revision conflict on `expected_checksum`, a note that moved, and a
  directory outside the project. Nothing is written in any of these cases. They used to
  come back as ordinary results, so a client checking `isError` counted a refused write as
  written. In JSON mode the error message is the same payload as before (`action:
  "conflict"`, `error: "NOTE_ALREADY_EXISTS"` and so on). `bm tool write-note` is
  unchanged: error on stderr, payload on stdout, exit status 1.

- **#1688**: A failed or refused `edit_note` is an MCP tool error (`isError`), as a
  refused `write_note` is (#1683). A refused write, such as the "modified concurrently"
  conflict when two clients append to one note, came back as an ordinary result whose
  text said "Edit Failed", so a client checking `isError` counted the append as written
  and never retried it. A refusal comes only from a write that rolled back, so a refused
  append is never in the note. In JSON mode the error message is the same payload as
  before. `bm tool edit-note` prints the error and exits with status 1. This reinstates
  #1662, which was reverted when its concurrency test found appends reported as refused
  that had landed; #1688 fixed that cause first. Thanks to @sammywachtel.

- **#1696**: Semantic search is always on, and the `semantic_search_enabled` setting is
  removed. FastEmbed and sqlite-vec are core dependencies, so the setting only mattered
  for installs that turned it off by hand; those installs now download the embedding model
  and build vectors. Old `config.json` files and `BASIC_MEMORY_SEMANTIC_SEARCH_ENABLED`
  are ignored rather than rejected. `bm reindex --embeddings` no longer refuses.
  `EmbeddingStatus` gains `vector_runtime_available`; `semantic_search_enabled` is still
  emitted as a deprecated alias of it, so older CLIs keep reading upgraded servers, and a
  status from an older server is still accepted. Where sqlite-vec cannot
  load (python.org Python on macOS), search still falls back to keyword-only, and a
  vector or hybrid query says semantic search is unavailable and points at the log.

- **#1697**: `basic-memory mcp --transport streamable-http|sse` binds to `127.0.0.1` by
  default instead of `0.0.0.0`, so the unauthenticated HTTP server is no longer reachable
  from the network unless you ask for it. A non-loopback `--host` prints a warning. On a
  loopback bind, both HTTP transports also reject requests whose `Host` or `Origin`
  header is foreign (DNS rebinding), honoring FastMCP's `FASTMCP_HTTP_ALLOWED_HOSTS` /
  `_ORIGINS`. A non-loopback bind gets that check only when those allowlists are set. The
  Docker image already passes `--host 0.0.0.0` and keeps working as before (#1578).

- **#1704**: `bm import document` resolves a relative path against the project root, not
  the current directory, matching `bm ls` and `bm cat`. A command that relied on the old
  behavior now fails with "File not found" and the resolved path.

- **#1702**: `build_context(compact=True)` no longer loads observations, and compact JSON
  no longer has an `observations` key (text-mode compact already hid them). Primary
  results, relations and related results are unchanged (#1571).

- **#1600**: `bm project remove` on a cloud-routed project always deletes the project's
  cloud files; there is no longer a way to keep them. It warns that the files can be
  recovered only from a cloud snapshot (`bm cloud snapshot list`) and asks for
  confirmation (`--yes` skips it). It no longer deletes the local sync directory as a
  side effect of `--delete-notes`; the new `--delete-local-files` flag does that. MCP
  `delete_project` on a cloud route also always deletes files, and `delete_notes` is now
  documented as local-only. Local projects behave as before. A cloud-only project
  removed without `--cloud` is now correctly treated as cloud-routed.

- **#1476**: The POSIX read tools (`cat`, `grep`, `ls`, `find`, `tail`, `man`) are on by
  default, so an MCP client now sees six more tools alongside the existing rich tools,
  and the server instructions describe projects as mount points. Set
  `enable_posix_tools=false` (or `BASIC_MEMORY_ENABLE_POSIX_TOOLS=false`) to hide them.

- **#1395**: Markdown notes always get a permalink. The `disable_permalinks` setting and
  `BASIC_MEMORY_DISABLE_PERMALINKS` are retired: an existing value is ignored rather
  than rejected, and the key is dropped from `config.json` when it is next normalized.
  Notes indexed without a permalink under the old setting are backfilled during ordinary
  scans, which writes a `permalink` into their frontmatter. Non-Markdown files are
  unchanged.

- **#1495**: Reading a note that does not exist exits with status 1 from the CLI in
  every output mode, and JSON reads carry `error: "NOTE_NOT_FOUND"`. Scripts that relied
  on exit status 0 with null fields need to check the status instead.

- **#1531**: `edit_note(operation="replace_section")` fails when the exact heading is
  not in the note, instead of appending a duplicate section and reporting success. A
  heading such as `## Open items #urgent` must be given in full; use `append` to create
  a new section on purpose.

- **#1343**: `bm project add --cloud --visibility private` is refused. The cloud has
  only `workspace` and `shared` visibility, so `private` had created a team-visible
  project while reporting success.

- **#1596**: `bm cloud sync`, `bm cloud bisync` and `bm cloud bisync-reset` are
  deprecated and will be removed in a future release. `bm cloud pull` / `bm cloud push`
  are the supported sync workflow on Personal and Team workspaces. The mirror commands
  are marked deprecated in `--help`, print a notice with the pull/push command on every
  run, still work on Personal workspaces, and on Team workspaces exit with that notice
  instead of a "Personal only" error. `bm project list` no longer shows Team projects
  with a local sync path as `cloud-only`: `sync_supported` is now true for every
  workspace, and `list_memory_projects` reports the same. Help examples no longer pass
  `--workspace Personal`.

### Features

- **#1552**: `edit_note` can edit only the revision you read. Pass `expected_checksum`
  (the full `checksum` from a JSON `read_note`, `write_note` or `edit_note` result) and
  the edit applies only while the note is still that revision. Otherwise nothing is
  written and the tool error is a revision conflict carrying the current checksum (JSON
  `error: "NOTE_REVISION_CONFLICT"`, `currentChecksum`, with the note's title, permalink
  and file path while it still exists, the same shape as `write_note`'s, #1719). A guarded
  `append` or `prepend`
  on a missing note is a conflict, not an auto-create. The v2 `PATCH` entity route
  accepts the same `x-bm-cloud-note-base-checksum` header the `PUT` route does.

- **#1552**: `read_note(include_content=False)` returns only a note's title, permalink,
  file path, full checksum and `updated_at`, without the body. Use it to refresh a stale
  `expected_checksum` without reading the whole note.

- **#1642**: `write_note` can overwrite only the revision you read. Pass
  `expected_checksum` with `overwrite=True` (CLI: `--overwrite --expected-checksum`)
  and the note is replaced only while it is still that revision. Otherwise nothing
  changes and the result is a revision conflict carrying the current checksum (JSON
  `error: "NOTE_REVISION_CONFLICT"` and `currentChecksum`, with `checksum` null because
  nothing was written, and the note at the path named by its stored title and permalink,
  #1719). A checksum for a path no note owns is also a
  conflict, so a note deleted since you read it is not recreated. Without
  `expected_checksum`, `overwrite=True` still replaces unconditionally.

- **#1636**: Note deletes record their actor in the accepted-change journal, as
  creates, updates, edits and moves already did. The delete route now asks the actor
  resolver like the other mutations (with a new `delete` mutation kind), so a runtime
  that identifies its callers can say who removed a note. With no resolver, which is
  every local install, the row is written exactly as before and deletes keep the
  `delete_note` source. Thanks to @sammywachtel (#1638).

- **#1550**: `bm okf export DESTINATION --project NAME` writes a static OKF v0.2 bundle
  from a local project, and `bm okf check BUNDLE_PATH` validates one. Export keeps
  concept frontmatter, categorized observations and relative asset paths, rewrites
  wikilinks to standard Markdown links resolved the way the graph resolves them, and
  records the original relation types in a `bm.okf_export` extension. It generates
  per-folder `index.md` files and a dated root `log.md` from the accepted-write journal.
  Export stages beside the destination, validates before publishing, refuses to
  overwrite without `--replace`, and restores the previous bundle if publication fails.
  `okf check` reports per-file, per-rule diagnostics and exits nonzero on any
  violation, including unreadable or non-regular files. Both commands take `--json`.

- **#1608**: Accepted note writes stamp `created_by` and `updated_by` into frontmatter
  when the runtime supplies an author, so the file itself says who wrote it. Cloud
  composes `<member> via <key name>` for API-key writes. The keys are server-stamped:
  whatever a writer submits for them is overwritten. `created_by` is set once and carried
  forward, and a note written before this change never gains one. Unchanged authorship
  does not rewrite the file, moves and deletes do not restamp, and local runtimes, which
  supply no author, leave both keys untouched.

- **#1558**: `QUERY /v2/search/` (and `POST /v2/search/` for clients that cannot send
  QUERY) searches an explicit set of projects in one database with one query. The body
  is the project search body plus `project_ids`, a required list of internal ids the
  caller has already authorized; an empty list answers no rows and there is no way to
  ask for every project. Full-text, vector, and hybrid retrieval run the same reader
  the project route runs, so one project here ranks exactly as its own route does, and
  results are one ranking over the union rather than merged per-project pages. Hits are
  hydrated only from projects in scope. Every search result, on both routes, now
  carries `project_id` and `project_external_id`.

- **#1558**: `search_notes(search_all_projects=True)` runs one scoped query per database
  instead of one search per project, so a local vault with many projects is one
  query, and each cloud workspace is one query, with results attributed to their
  project by the server rather than by which request they came back on. A new
  `projects` parameter searches a chosen subset by name or external id; an unknown
  name is an error. Cross-database results are still merged by score, one failing
  database is skipped with a warning and an inexact total, and a retryable outage
  or a server too old to attribute its results fails the whole page.

- **#1558**: Vector retrieval reads only the projects in scope and fills the window it
  asks for. The sqlite-vec table gains a `project_id` partition key, so a scoped
  nearest-neighbour query ranks each project's own vectors instead of taking the k
  nearest across the whole database and discarding the out-of-scope ones, which
  could leave a small project with an empty page for a query its notes answered.
  Existing local storage is carried into the partitioned table without re-embedding.
  On Postgres the nearest-neighbour statement now runs on the HNSW index (its
  tie-break sort keys had kept the planner on an exact scan of every vector), with
  `hnsw.ef_search` sized to the candidate window and an iterative scan that keeps
  going until the scope and manifest filters have admitted enough rows. That scan
  needs pgvector 0.8 or later; an older extension is reported as a dependency error
  instead of quietly returning short windows.

- **#1558**: A vector or hybrid search with structured filters (note types, dates,
  categories, metadata, path prefixes, valid time) now fills its candidate window.
  The vector index ranks by similarity alone, so a window taken straight from it and
  filtered afterwards could hold few admitted rows while more sat just past it, and
  the page came back short although matches existed. The reader re-reads the window
  with a bounded geometric overfetch until it holds enough admitted rows, the ranking
  is exhausted, or its tail falls below the similarity threshold. Unfiltered searches
  read their window once, as before.

- **#1512**: Word, PowerPoint, and CSV files get the same sidecar Markdown note a
  PDF gets. `bm import document <path>` indexes the project, extracts the file,
  and writes `<file>.<ext>.md` next to it plus a run note under
  `document-ingestion-runs/`, all through the existing parser-neutral document
  contract. Office formats run through Microsoft's `markitdown` converters
  (`basic-memory[documents]`) inside the same killable, byte-capped worker
  process as pdf-inspector; CSV renders a bounded stdlib preview with strict
  UTF-8. Re-running is a no-op while the source is unchanged, and the command
  refuses to overwrite a hand-written or enriched note at the sidecar path.
  PDF keeps pdf-inspector and works through the same command.

- **#610**: The manual's SYNOPSIS blocks are now generated from the tool registry.
  `just man-regen` renders the MCP call on every section-3 page from the schema
  clients actually receive (required parameters first, then defaults, in schema
  order) and a test holds the shipped blocks byte-equal to the rendering -- change
  a tool signature without regenerating and CI points at the fix. Those pages
  declare `generated: registry`; curated sections stay hand-owned. The manual also
  gains `basic-memory-diagnostics(3)`, closing the one gap between the section-3
  corpus and the tool registry.

- Notes are readable as MCP resources. Every `memory://` URL Basic Memory hands out
  now answers the standard `resources/read`: `memory://<project>/<path>` returns the
  note's raw markdown, frontmatter included, with the identifier accepted as a
  permalink, title, or file path. Unknown notes point at `search_notes`; binary files
  point at `read_content`. `memory://man/...` keeps answering as the manual and
  `memory://<workspace>/<project>/info` as project info, whichever template the
  server matches first.

- **#610**: The manual ships in the package and is served over MCP. The 21 section-3
  pages (one per MCP tool -- `search-notes(3)`, `write-note(3)`, ...) now live in
  `src/basic_memory/man/man3/` as canonical, portable notes. The MCP server exposes
  them as resources: `memory://man` is the index and `memory://man/<page>` is a page,
  with every page also listed as a concrete resource so clients that browse
  `resources/list` see each one with its summary. Page references parse the way people
  and models actually write them -- `search-notes(3)`, `3/search-notes`,
  `search_notes`, `man3/search-notes.md` -- and the server instructions point agents at
  a tool's page before first use. `bm man <topic>` prints a page as Markdown and
  `bm man list` is apropos; `bm man install` is unchanged.

- **#1259**: `write_note` now tells the caller when a freshly created note looks like
  notes that already exist. On a server with semantic search enabled, a create probes
  the vector index with the new note's title and opening content and appends a
  "Similar existing notes" section listing the closest matches, phrased as a question
  -- did you mean to write to one of these? -- with the ways out spelled out: merge
  into the existing note with `edit_note` and delete the new one, link the two with a
  relation, or ignore it. JSON output carries the same list as `similar_notes`. No
  similarity scores are shown and nothing is overwritten on the caller's behalf: on the
  default embedding model a near-duplicate and a merely related note score in the same
  band, so the decision stays with the agent, which has the context the score does not.

- **#1398**: POSIX-style read tools. MCP gains `cat`, `grep`, `ls`, `find`, `tail`, and
  `man` next to the rich tools, and the CLI gains the same verbs (`bm cat`, `bm head`,
  `bm grep`, `bm ls`, `bm find`, `bm tail`, `bm tree`) over one shared translation
  layer. Notes are indexed by heading, so `cat` can read one section, a line range, or a
  token budget instead of the whole note. Projects act as mount points: `ls /` lists
  them, and a path whose first segment names a project routes there, so the paths the
  tools return can be passed straight back. `find` takes metadata predicates
  (`status=active`, `confidence>0.6`) and a `--fields` projection of frontmatter values.
  **This ships an Alembic migration** adding the `note_section` table.

- **#1501**: `read_note` accepts `start_line` / `end_line` and returns numbered lines
  with the next range to read, and `grep(context_lines=N)` returns merged
  match windows instead of whole notes, with `max_matches` bounding the lines per note.
  The CLI equivalents are `bm grep "retry" -C 3` and `bm tool read-note NAME
  --start-line 120 --end-line 180`.

- **#686**: `search_notes(compact=True)` and `build_context(compact=True)` return
  identifiers, metadata, relation targets, and pagination without note content, so an
  agent can pick what to read before paying for the bodies. `bm tool search-notes` and
  `bm tool build-context` take `--compact`. Default responses are unchanged.

- **#1426**: Observations can say when a claim holds (SPEC-82). An authored qualifier
  such as `- [decision] @effective:2026-06-10 The cache layer will use Redis.`, a range
  (`@effective[2026-06-10,2026-07-27)`), or a quoted multi-word date (`@occurred:"June
  10, 2026"`) is indexed as valid time; the kinds are `effective`, `valid` (the
  default), `occurred`, `due`, and `mentioned`. `search_notes` gains `valid_at`,
  `valid_overlaps`, and `time_kind` filters, and a malformed filter is refused instead
  of ignored. Searches without them rank as before. A qualifier that does not parse
  stays in the observation text. **This ships an Alembic migration** adding the time
  index table.

- **#1246**: Ordinary Markdown links to files in the project
  (`[Guide](../guides/Guide.md)`, reference-style links, `/`-rooted paths) become
  `links_to` relations, the way wikilinks do. External URLs, images, code, fragment-only
  links, and paths outside the project are ignored, and the authored Markdown is not
  rewritten. (PR #1514; see the #1514 fix below for how the paths resolve.)

- **#1422**: Wiki projection. `bm wiki status`, `bm wiki validate`, and `bm wiki
  rebuild` (with `init` and `update` as aliases) generate root and per-folder `index.md`
  and `log.md` navigation pages for a local project, with `--project`, `--all`,
  `--json`, and `--dry-run`. The projector is deterministic, so local and cloud produce
  the same bytes; each `log.md` keeps the 25 most recent changes. It never overwrites a
  hand-written `index.md` or `log.md` (those are reported as conflicts), links empty
  folders from their parents, and does not recreate pages for a deleted folder. The
  change order comes from a new per-project accepted-change journal. **This ships an
  Alembic migration** (#1381, #1382, #1396, #1433, #1434, #1436, #1484).

- **#1006**: PDF ingestion. `basic-memory[pdf]` adds a pdf-inspector extraction adapter
  that runs in a bounded worker process and turns a PDF into an extracted-text sidecar
  note plus a `type: document_ingestion_run` provenance note, under the same
  parser-neutral contract local and cloud share (#1178, #1377). Generated document
  bodies are searchable but cannot mint observations or relations from extracted text.

- **#1366**: Document observations can cite the PDF page they came from. The
  enrichment contract (`enrich_document_markdown`) writes OKF-compatible `sources` entries and Markdown footnotes pointing at
  `file.pdf#page=N`, with an optional printed page label, and the page is checked
  against the extraction's page count. Provenance also keeps the extraction's page map,
  so a span of the raw text can be traced to its pages without re-parsing the PDF
  (#1490, #1519).

- New extracted-text sidecars use `type: extracted_text`. Sidecars written earlier keep
  `type: document`; both are accepted, the stored value is preserved, and old sidecars
  still match their run notes and are reused on re-import. The per-page page map now
  lives only on the ingestion-run note (`document-ingestion-runs/<run_id>.md`), and the
  sidecar keeps a summary without it, so a 424-page PDF's sidecar frontmatter drops from
  about 23 KB to about 1 KB.

- **#1744**: An extracted-text sidecar is linked to its source file by a `derived_from`
  relation, projected from the validated `source.entity_external_id` in its frontmatter.
  The relation exists even while the sidecar's raw body semantics are disabled, and it
  does not change the extracted text or its page offsets.

- Non-Markdown files (PDFs, images, Office documents) store `content_type` and `format`
  in their entity metadata at index time, and directory listings expose `format`. MIME
  types for every supported or extracted extension (docx, pptx, xlsx, webp, canvas, ...)
  are pinned before falling back to `mimetypes`, so slim images without
  `/etc/mime.types` no longer record Office files as `text/plain`. Metadata filters
  still match Markdown notes only.

- **#993**: `locked: true` in a note's frontmatter makes it read-only to the note API.
  Edits, overwrites, deletes, and directory deletes that include it are refused with
  HTTP 423, and no API call can unlock it. Direct filesystem edits and deletes still
  win, and imports are not bound by the lock. See `docs/LOCKED_NOTES.md`.

- **#1254**: `bm prune` removes index entries for files that the current `.bmignore` or
  `.gitignore` now excludes. It lists the entries first, takes `--dry-run` and `--yes`,
  and points cloud projects at `bm cloud prune`. Indexing does not do this on its own
  because an upgrade that changed the ignore defaults would otherwise drop notes.

- **#1414**: `bm project add` indexes a local project before returning (`--no-wait` opts
  out), and `bm project index NAME` reindexes one. `bm status --json` reports readiness
  per stage (files, relations, embeddings) with a phase that tells a never-indexed
  project from an idle one, and `bm status --wait` now waits until every stage settles
  or `--timeout` passes. **This ships an Alembic migration** backfilling
  `last_indexed_at`.

- **#1294**: Full-text search finds words inside unsegmented scripts (Chinese, Japanese,
  Korean, Thai, Lao, Tibetan, Myanmar, Khmer) on SQLite and Postgres, by indexing
  character unigrams and bigrams alongside the existing word index. **This ships an
  Alembic migration**; existing notes gain this recall after a reindex.

- **#1336**: The `openai` embedding provider honors `semantic_embedding_api_base` and
  `semantic_embedding_api_key`, so it can point at any OpenAI-compatible endpoint
  (llama.cpp, vLLM, TEI, LM Studio, Ollama) without the experimental litellm path.
  Thanks to @mikemikimike (#1365).

- **#610**: The manual's `## PARAMETERS` sections on section-3 pages are generated from
  the tool schemas (#1478), and the section-1 SYNOPSIS and OPTIONS blocks are generated
  from the Typer command tree (#1524, thanks to @FBISiri), with drift tests for both.

- **#1455**: Search results carry `content_length` and `content_truncated`, metadata
  fields keep their JSON types (numbers, booleans, lists), and `bm ls --plain` and `bm
  find --plain` report further pages on stderr so stdout stays pipe-clean (#1456,
  #1457).

- `bm install codex`, `bm install claude-code`, `bm install tau`, and `bm install pi`
  install the Basic Memory plugin or package for that host, with `--dry-run` and
  `--yes`. Codex and Claude Code installs delegate to the host's own plugin CLI, and
  `claude-code` takes `--scope user|project|local`; Tau and Pi copy the packaged
  resources and keep existing config. None of them touch the Basic Memory database
  (#1497, #1498, #1493, #1492).

- **#1487**: Tau integration. Tau sessions recall the active branch's latest checkpoint,
  tasks, and decisions at startup, capture knowledge as work settles, and write an
  awaited checkpoint before compaction. Coding sessions are keyed by repository identity
  and write shared Coding Session, Session, Task, and Decision schemas that the Claude
  Code and Codex packages also use (#1489, #1493).

- **#1488**: Pi integration. The `@basicmemory/pi-basic-memory` package adds
  `/bm-status`, `/bm-recall`, `/bm-capture`, and `bm_recall` / `bm_capture` tools, over
  either the `bm` CLI or `pi-mcp-adapter`, configured per project in
  `.pi/basic-memory.json`. Automatic recall and capture run only in a trusted workspace
  (`BASIC_MEMORY_PI_TRUST_WORKSPACE=1`), and `/bm-status` reports whether they are on,
  off, or blocked and why (#1492, #1509).

- OpenClaw's `write_note` accepts `metadata`, `tags`, and `note_type`, and `edit_note`
  accepts `metadata`, matching the core MCP tools. Thanks to @lastguru-net (#1474).

- The manual gains `comark(7)`, a quick reference for the Comark `::bm-*` components
  notes can embed (`bm man comark`, `memory://man/comark(7)`), and a new `memory-comark`
  skill teaches agents to author them: the component vocabulary, directive and body
  rules, live query pipelines, how to check numbers they cannot see rendered, and the
  coded errors a broken component shows. Component problems never block a write. The
  skill is registered in the OpenClaw manifest.

- Skills: `memory-reflect` and `memory-defrag` work on a project's notes instead of
  `MEMORY.md`. Reflect folds recent activity into the notes each topic belongs in,
  writes a dated reflection note, and resumes from its last one. Defrag writes a plan
  note, applies what loses nothing, and merges or deletes only when told to. Both pass
  `expected_checksum` on every edit. The note-writing skills date facts with temporal
  qualifiers (`@effective`, `@due`, ...). The wheel ships the distributed skills under
  `basic_memory/data/skills`, so hosts that load skills from the installed package can
  use them.

- New `memory-okf` skill: makes a project ready for OKF export with the note tools. It
  finds non-`.md` notes, notes at the Wiki's reserved `index.md`/`log.md` names and
  reserved export frontmatter, then fixes them with `move_note` and guarded writes.

- New `memory-agents` skill: write, run and check Basic Memory Cloud agents (notes with
  `type: agent`), including their frontmatter, watch triggers, run logs and skip
  reasons.

### Bug Fixes

- Fixes from the v0.24.0 release live run:
  - `build_context` refuses a `memory://` title URL that names more than one note, as
    `read_note` does, instead of building context for one of them. Pass the permalink.
  - `build_context` related results report `created_at` with a timezone offset, like
    primary results.
  - `delete_project(delete_notes=True)` on a local project reports that the files were
    deleted, instead of "did not report a completion status".
  - `write_note`'s "Similar existing notes" advisory skips notes the new note already
    links to.
  - `view_note` sets the note off with `<note>` markers instead of `---`, which ran into
    the note's own frontmatter fence, and its instructions are no longer indented.
  - Vector and hybrid searches report `total` as the results seen through the current
    page, still with `total_is_exact: false`, instead of `0`.
  - `tail` rows carry `updated_at`, the time they are ordered by, and `bm tail` shows it.
  - `bm reindex --help` no longer says `--embeddings` requires semantic search (#1696).
  - Tool docs, the manual and the `list_memory_projects` footer no longer promise a
    "session's active project". MCP requests carry no session state under the current
    protocol, so a call without `project` always uses the default project, locally and
    in the cloud. `write_note` and `edit_note` end with `[Project: 'name']` instead of
    `[Session: Using project 'name']`, and say when no project was given and the
    default was used.

- **#1726**: `bm reindex --embeddings` now finishes oversized notes before it reports
  success. Vector sync embeds at most 256 chunks of one note per pass and defers the
  rest, and the explicit reindex ran a single pass, then printed "Embeddings complete"
  and forced its progress bar to 100% with those chunks still missing from semantic
  search. A `--full` rerun cleared vectors and repeated the same first shard. The
  reindex now re-runs deferred notes until none remain, clearing vectors only once for
  `--full`. If a pass stops making progress, it reports how many notes still have
  pending chunks, says how to continue, and exits non-zero. Reported by @beru-ant-king;
  @lastguru-net independently reached the same fix in #1730.
- **#1732**: An API edit no longer leaves a note's observations and relations without
  vectors. The accept path publishes only the note body as a temporary search row,
  and the observation and relation rows appear when the file is written and indexed
  in the background. The route also scheduled its own embed, which often ran first,
  embedded the body alone, and left nothing to embed the rest. A background index
  pass did not repair it, because the file looked unchanged. Now the materialization
  job embeds the note once, right after it indexes the written file, as cloud's
  materialize job already did. Routes no longer schedule vector sync for note writes,
  edits or moves. Embeds run in a separate bounded pool keyed by note, so a slow
  embedding provider no longer holds up other notes' file writes; one note's embeds
  still run in write order. Reported by @beru-ant-king with a reproducer.
- **#1691**: Editing a note no longer re-embeds all of its observations and relations.
  Vector chunks were keyed by the search row id they were cut from, and every rewrite
  recreates those rows with new ids, so nothing matched the previous manifest: about 86
  chunks per edit on large ledger notes. Chunks are now keyed by a hash of their text,
  so unchanged text keeps its embedding. **This ships an Alembic migration** that
  re-keys existing chunks in place; nothing is re-embedded by it.
- **#1720**: CLI output prints project names, paths, and error messages as typed.
  Rich used to read bracketed text in them as markup: `proj [x]` printed as `proj `,
  `[bold]` restyled the line, and a value containing a closing tag such as `a[/b]c`
  crashed the command with `MarkupError`. The deprecated `bm cloud sync`, `bisync` and
  `bisync-reset` now print only their own deprecation notice, without Click's extra
  "DeprecationWarning: The command ... is deprecated." line.

- **#1718**: `write_note`'s "Similar existing notes" advisory no longer suggests notes
  on unrelated topics. It used search's relevance floor (0.55), which the nearest
  neighbor of almost any note clears on the default model. On the default model it now
  lists only notes scoring 0.70 or higher: rewrites of an existing note scored 0.77 to
  0.93, and unrelated neighbors at most 0.67. Other embedding models keep
  `semantic_min_similarity`, since their scores sit on a different scale. Hybrid
  search's handling of gibberish queries is unchanged; the measurements showed no
  threshold that separates it from real matches.
- **#1716**: A note's `created_at` no longer resets on every edit, move or reindex.
  Without a frontmatter `created`, the parser falls back to the file's ctime, which each
  atomic rewrite or rename moves, and reindexing an existing note copied that time into
  the row. Now an existing row keeps its creation time, and only a declared frontmatter
  `created` changes it. A brand-new file still takes its file time.

- **#1717**: `build_context` text output names the source of relations the primary note
  does not own. An incoming `relates_to` used to be listed bare under its target, so it
  read as a self-link; it now reads `- [[Brewing Notes]] relates_to [[Bean Origins]]`.
  Relations the note owns keep the bare form, and JSON output is unchanged.

- **#1720**: `edit_note` `insert_after_section` no longer puts a blank line between an
  inserted list item and the section's list, which split one list in two. The item joins
  the list directly, below any blank line under the heading. A paragraph inserted above
  a paragraph still gets the blank line that keeps them apart.

- **#1595**: `basic_memory_diagnostics` lists the `BASIC_MEMORY_*` environment
  variables that override `config.json`, redacted the same way as the file dump. It
  used to print only the file, which can disagree with what the server is using. Other
  `BASIC_MEMORY_*` variables are listed by name only. Env names now match config fields
  in any letter case, as pydantic-settings reads them: a lowercase
  `basic_memory_log_level` used to lose to the file value, or, when the file lacked the
  key, take effect and then get written into `config.json`.

- **#1593**: The CLI's list of commands that skip startup initialization no longer
  names `sync` and `watch`, which are not commands. A test now keeps the list to
  registered commands. Thanks to @FBISiri.

- **#1651**: A document import's ingestion-run note no longer says "exact storage
  materialization is pending", which read as a live status long after processing
  finished. New run notes say what they record and link the original file and its
  extracted-text note. Existing run notes keep their old text.

- **#1653**: The `write_note` documentation now says what `overwrite=True` does to
  frontmatter: the body is replaced, keys the write sets replace the old values, and
  keys only the existing note has are kept. Existing frontmatter that cannot be parsed
  is discarded. Behavior is unchanged.

- `bm tool edit-note --help` lists all six edit operations and documents `--section` for
  `replace_section`, `insert_before_section` and `insert_after_section`. Thanks to
  @xhkzdepartedream (#1708).

- **#1604**: `bm cloud push` and `bm cloud pull` on Team workspaces are much faster.
  The project is listed with one `Depth: infinity` PROPFIND instead of one request per
  directory, and eight files transfer at once. File bodies stream to and from disk, so
  memory does not grow with file size. This needs a cloud service that answers
  recursive listings; against an older one, or a project too large for one listing,
  the command stops with a message naming the cause.

- **#1654**: A Markdown file kept in step by a one-way sync tool (rclone sync, a backup
  script) is no longer re-indexed and rewritten forever. Indexing writes a `permalink`
  (and `title` and `type` with `ensure_frontmatter_on_sync`) into a file that arrived
  without them. The sync tool then copied its original back, which read as a change.
  The entity now also records the checksum the file arrived with (a new
  `entity.sync_checksum` column, added by a migration), and a file matching either
  checksum counts as already indexed. Frontmatter is still written. #1655 applies the
  same check to single-file indexing, using the checksum storage reports.

- **#1667**: Moving a directory moves its notes the same way `move_note` does. The
  directory move used the old storage-first path, which moved the file and the entity
  row but left the note's accepted content at its old path and revision. Each note now
  moves as an accepted note move. Regular files still move their bytes, and per-file
  failures are reported as before (#1670).

- **#1641**: A failed `delete_note` or `move_note` is reported as an MCP tool error. A
  refusal, for example from a read-only API key, came back as an ordinary result whose
  text said "Delete Failed" or "Move Failed", so clients read it as success.
  `delete_note` still returns `False` for a note that does not exist.

- **#1683**: `read_content` never returns another file for a path that does not exist.
  It resolved through the fuzzy fallback, which matched any note sharing a word with the
  path (`disk/nope.txt` returned a note in `disk/`). It now resolves only exact paths,
  permalinks, titles and ids, and a miss is "Resource not found".

- **#1683**: `NOT` excludes a term found anywhere in the note. `coffee NOT pour` returned
  a note whose title has "coffee" and whose body has "pour": SQLite evaluated `NOT` in each
  column separately, and the vector half of hybrid search ignores Boolean operators. A
  search that uses `AND`, `OR` or `NOT` without an explicit `search_type` now runs as
  full-text.

- **#1683**: `read_note` with JSON output (and `cat`) returns `checksum`, the revision
  `write_note`'s `expected_checksum` compares, so an agent can overwrite only the
  revision it read.

- **#1685**: `grep` matches keywords by default, so a pattern found in no note returns
  no results. It ranked by meaning whenever semantic search was on, and nearest-neighbour
  ranking always returns something: `grep("Ethio.ia")` listed unrelated notes. Pass
  `semantic=True` (`bm grep --semantic`) to rank by meaning. This replaces the `literal`
  parameter and the `-F` flag, and `context_lines` (`-C`) no longer needs either.

- **#1681**: On Postgres, saving a note twice in quick succession no longer answers 500.
  Two refreshes of the same note's search rows could deadlock or collide on
  `search_index_pkey`, and the loser failed the save even though search rows are derived
  state. A refresh that loses that race now logs a warning and leaves the winner's rows
  for the next refresh. The save's search row is written after its accept commits rather
  than inside it, so a failed refresh can no longer roll back the note. Thanks to

- **#1686**: The file watcher logs a warning when a new directory cannot be read. On
  Linux, notify drops the error when it cannot watch a new directory, so files written
  into it were never indexed and nothing said why. The warning names the directory and
  says to run `bm project index <name>` once its permissions are fixed. Thanks to
  @sammywachtel.

- **#1676**: `search_notes` accepts the metadata filter shapes agents actually write.
  Bare operator names (`gte`, `in`) work as aliases for `$gte` and `$in`, one field can
  take several operators (`{"$gte": a, "$lte": b}`), and `$contains` (array contains) and
  `$exists` are new. An unknown operator's error now lists the valid ones. A rejected
  filter no longer leaves its count query running after the request returns: search and
  count run in one task group, so a failure cancels the other (#1675).

- **#1657**: A full-text query that mixes a punctuated word with other words finds notes
  that contain all of them. `IT-644 cacheability` returned nothing: one punctuated word
  made SQLite quote the whole query as a single exact phrase, which only matches when the
  words are adjacent. Now only the punctuated word is quoted, and every word must match in
  any order: `"IT-644"* AND cacheability*`. Thanks to @dougvann.

- **#1701**: Environment overrides are no longer written into `config.json`. Any config
  save (a project add, a migration, first run) wrote the merged settings, so a one-off
  `BASIC_MEMORY_*` variable became permanent. A save now keeps the file's own value for
  every env-overridden setting. Commands that name a setting still save it: `bm config
  set/unset`, `bm cloud api-key save`, `bm cloud workspace set-default`, `bm cloud
  logout`, `bm cloud promo` and `bm project default` (#1631, #1598).

- **#1699**: A case-only rename (`config.md` to `Config.md`) on a case-insensitive
  filesystem no longer leaves a permanent ghost note. The index pass's delete check now
  matches the exact spelling against the directory listing, so the next pass removes the
  stale entry (#1627).

- **#1700**: In a local project, a note too large to embed in one pass finishes embedding
  on later index passes without a manual `bm reindex`; #1691 already stopped unchanged
  observations from being re-embedded (#1605). The hosted runtime does not resume these
  notes yet.

- **#1698**: Appending `---` or `===` after a paragraph with `edit_note` no longer turns the
  paragraph into a heading. When an append or prepend would form a setext heading over
  existing text, a blank line separates them; every other join, including list items and
  observations, is unchanged (#1585).

- **#1705**: Note-tool fixes from the live run (#1634):
  - A line read that starts past the end of a note is an error ("start_line 500 is past
    the end of the document (17 lines)") instead of "Lines 500-17".
  - A link that climbs out of the project is no longer stored as an unresolved relation.
  - A `write_note` conflict after a move names the note that actually owns the path; the
    `already_exists` outcome gains `external_id` and `permalink`.
  - `recent_activity` describes its scope accurately, and an empty result from any tool
    returns an explicit `[]` text block.

- **#1704**: CLI polish from the live run (#1635). `bm project add` and `bm project index`
  show embedding progress. `bm config set default_project` rejects an unknown project
  and accepts display names. `bm project index --help` shows user-facing text, the
  `.bmignore` path in help points at the real config directory, and a refused OKF export
  no longer prints a misleading summary.

- **#1663**: An unhandled API error no longer stalls the server for seconds while it is
  logged, and logs no longer contain the values of local variables from tracebacks.
  Loguru's `diagnose` mode called `repr()` on every frame's locals, and each ASGI frame
  holds the whole request scope. The file, stdout and Logfire sinks still log the full
  traceback without those values. Test mode keeps them. Thanks to @sammywachtel (#1679).

- **#1643**: Project status is served over `GET /v2/projects/{id}/status`. It was a
  POST, so a read-only API key got "This API key is read-only" on any empty search,
  because the empty-result guidance checks project status. `POST` remains as a hidden,
  deprecated alias for older clients. When workspace discovery fails in every
  workspace, the error gives each workspace's reason, such as a reached spending limit.

- **#1645**: An empty search no longer says a project "has never been indexed" when it
  has indexed notes. Readiness required a completed full index pass, which a project
  indexed note by note (every project created in Basic Memory Cloud) never records. A
  project with files and no indexed notes still gets the "index first" guidance.

- **#1656**: On Postgres, vector storage is created when the database is initialized,
  never while serving. Each embedding job ran `CREATE INDEX IF NOT EXISTS` on first use,
  which locks the table, so concurrent chunk and embedding writes queued behind it and
  timed out. Initializing an already-initialized database reads the catalog and takes no
  locks.

- **#1659**: On Postgres, two processes initializing the same new database no longer
  race on `CREATE EXTENSION vector` and fail with a unique violation. Vector storage DDL
  takes a transaction advisory lock and rechecks the catalog inside it. Extension
  availability is checked directly, so a real error is no longer reported as "pgvector
  extension is unavailable".

- **#1586**: `write_note` and `edit_note` report the note's real checksum instead of
  `checksum: unknown`. The typed client parsed a response model without checksum
  fields, and file materialization runs after the response is built, so neither value
  reached the tool. The tools now report the checksum recorded when the write was
  accepted, which is the value checksum-guarded edits compare against. Thanks to
  @tonydzi for the report and fix (#1617, landed as #1619).

- **#1624**: A local project whose name is not already its permalink (`My Research`,
  `Gamma-Mixed`) is indexed at startup and watched again. Startup rewrites config keys to
  permalinks, but the database keeps the display name, and config was then looked up by
  that name with an exact match. The project was skipped as "not locally indexable" and
  treated as cloud-routed. Config entries are now matched by permalink.

- **#1632**: On an install with no cloud credentials, an unknown or deleted project name
  reports "project not found" instead of "Cloud routing requested but no credentials
  found". Unknown names still route to cloud when cloud is available.

- **#1628**: The MCP `man` tool no longer asks a local install for cloud credentials.
  Without a `manual` project, an unbundled page returns "No manual entry for ...", and
  query mode says it needs that project.

- **#1626**: `build_context` resolves a `memory://` title URL to that note, and returns
  nothing for a URL that names no note. The routed URL carries the project prefix
  (`main/Cache Layer Design`), which the title and file-path lookups never matched. Titles
  therefore resolved only through a fuzzy search that often picked a note linking to the
  target, and a miss returned whatever ranked first. The resolver now tries the exact
  lookups on the remainder before any fuzzy match, and `build_context` no longer fuzzy
  matches at all.

- **#1625**: `bm wiki` projects local projects that have had API or MCP writes. The
  projector waits until every accepted change is materialized, and the local runtime
  never recorded that, so a single write left the wiki `partial` for good. Local writes
  and deletes now mark their journal rows once the file work settles, as cloud does.

- **#1629**: `read_content`, `cat` and `read_note` on `notes/foo.txt` return that file,
  not the same-stem `notes/foo.md`. An identifier with a non-Markdown extension now
  matches its exact file path before the extension-less permalink candidates.

- **#1630**: When `BASIC_MEMORY_MCP_PROJECT` differs from the project name only in case
  (`ALPHA` for `alpha`), `search_notes(search_all_projects=True)` and `projects=[...]`
  find the project again, and `projects=["BETA"]` matches `beta`. Search scoping now
  compares project names by permalink, as routing does.

- **#1633**: Tool descriptions, docstrings and error guidance now pass every argument
  after the first by keyword in their example calls. Several showed the old project-first
  positional order (`read_note("qa", "notes/x")` reads a note named `qa` from project
  `notes/x`), a retired `list_projects()` tool, or a `kind=` parameter that `search_notes`
  does not have. A test now checks every example against the registered tool signatures.

- **#1549**: A note whose frontmatter sets a permalink that is not already a slug
  (`s/2026/09/ses_AbCdEfGhIj`) is reachable by `memory://` URL again, in `build_context`
  and `read_note`. The stored permalink is kept verbatim, but the resolver stripped the
  routed project prefix only from the slug form of the URL (`ses-ab-cd-ef-gh-ij`), so
  `build_context` returned an empty result and `read_note` found nothing. The resolver
  now tries the caller's own spelling of the path before its slug.
- **#1621**: A failed search refresh no longer removes a note from search. Refreshing an
  entity deleted its old search rows in one committed transaction and wrote the
  replacement rows (and, on Postgres, their full-text chunks) in another, so a timeout
  while writing the replacement left an existing note with no search rows, and nothing
  rebuilt them until the note was edited or the project re-indexed. The delete and the
  replacement now commit together: a failure keeps the previous rows, and a failed first
  index leaves nothing partial behind to retry against.

- **#1598**: Under `BASIC_MEMORY_PROJECT_ROOT`, a project name whose permalink contains
  `/` (such as `Research/2026`) is refused, so every project under a shared root stays a
  single top-level directory. Cloud stores and purges projects by that top-level prefix,
  and a nested name could overlap another project's files. The rule lives in
  `project_permalink`, which cloud calls when it creates projects.

- **#1606**: Deleting a non-Markdown file (an image, a PDF) now removes it from storage.
  The delete runner compared the accepted checksum with a SHA-256 of the stored bytes,
  but an accepted checksum is not always a content hash (cloud records ETags), so the
  delete was skipped and the next reindex brought the file back. Storage now owns the
  compare-and-delete through `delete_file_if_matches`. This changes the
  `NoteFileDeleteStorage` protocol.

- **#1601**: Wiki-projected `index.md` files no longer carry `bm_parse_semantics: false`,
  so the wikilinks they list become graph relations. `log.md` stays graph-silent.

- **#1603**: Model-facing text (tool descriptions, server instructions, prompts, skills)
  was audited against the real tool contracts. Suggested calls use keyword arguments
  (a positional `delete_note` example would have deleted a note named after the
  project), skills use real parameter names and operations, and under-described tools
  such as `search_notes`, `grep`, `edit_note` and `move_note` now send their full
  contract to clients. Prompts no longer push agents to create notes unprompted.

- **#1581**: The sqlite-vec stale-vector cleanup no longer stalls on large vaults. Its
  DELETE compared each chunk's `source_hash` against the outer vector row, which made
  the subquery correlated, so SQLite re-ran it once per vector: quadratic work that
  held the write lock long enough for concurrent writers to fail with `database is
  locked`. The subquery now joins the vector row by rowid, and the cleanup deletes the
  same rows in one pass. Thanks to @mikemikimike for the report and fix (#1584).

- **#1609**: `read_note` on a Markdown file path that does not exist (`notes/x.md`)
  returns the ordinary not-found response again. Strict resolution already checks
  file path, permalink, and exact title, so a miss there confirms absence, and the
  tool no longer falls back to title and text search for an explicit path. That
  fallback was what surfaced the problem: in a project with no recorded full index
  pass, which is common for hosted projects whose notes read fine, an empty search
  answers with the "Project Index Required" guidance, and JSON reads raised it as
  `Fallback search failed: # Project Index Required` instead of `NOTE_NOT_FOUND`.
  Title and free-text identifiers keep the search fallback and the guidance.

- **#1607**: `move_note` applies its cross-project guard to directory moves as well as
  file moves. The guard ran only after the directory branch had returned, so
  `work/moved` was refused for a note and accepted for a directory. The guard also
  no longer rejects a destination whose first folder is named after another project
  when that folder already holds notes in the current project: a knowledge base
  organised by domain has such folders, and an existing local folder is evidence of a
  same-project move. A first folder named after another project that does not exist
  locally is still rejected.

- **#1514**: Markdown path links resolve against the note's own path at resolution
  time, the way wikilinks do, instead of at parse time from the file's location
  on disk. The parser had derived the note's project path with `relative_to` on the
  filesystem path, which raised for content parsed from anywhere outside the project
  root (a hosted note read from object storage, for one) and gave a wrong base for
  any other temporary location. The graph now stores the path as authored
  (`../guides/Guide.md`, `./same.md`, `/root.md`); both resolvers turn it into a
  project path from the source note, and background resolution keys path targets
  by their source note. Wikilinks spelled `[[../x.md]]` or `[[./x.md]]` resolve
  by the same rule.

- **#1558**: `search_notes(search_all_projects=True)` and `projects=[...]` rank merged
  full-text hits by score strength instead of raw value. SQLite bm25 scores are
  negative with lower meaning better, so sorting raw values put the weakest hit first
  and cut every page from the wrong end of the ranking; page two repeated page one.
  Every hit on a page that spans projects now carries `project` (JSON) or a
  `- project:` line (text), so the next call can be routed to the right project.

- **#1557**: A vector or hybrid search with reranking enabled retrieves once per request.
  A page reaching past the fixed reranked prefix used to run a second full retrieval
  (query embedding, vector query, and for hybrid a second FTS pass) only to rebuild
  that prefix. The prefix is now read from the request's own window at the fixed
  window's chunk bound, on the project route and the scoped `QUERY /v2/search/` route
  alike, so every page still reranks the same rows with the same passages. Hybrid
  tail rows are ordered by where each row first entered either ranking, counting
  vector chunks before they collapse into rows, so a deep page cannot move a row
  across one already returned. SQLite full-text results break score ties by row id,
  as Postgres already did, so a smaller window is always a prefix of a larger one.
  The `stable_pool_refetched` field is gone from the internal search trace.

- **#1458**: A note whose file stem equals its project's name is now readable by its bare
  identifier. `split_project_permalink_prefix` matches a leading path segment against a
  project's permalink via `generate_permalink`, which drops file extensions -- so a single
  segment like `moby-dick.txt` in project `moby-dick` collapsed to the project's own
  permalink with an empty remainder, and `cat`/`find` refused it as "names a project, not a
  note" instead of resolving the note. A prefix claim that would leave no remainder now
  requires the raw segment to spell the permalink exactly, extension included; a claim that
  still has a remainder after it is unaffected, since project names never carry a real
  extension in that position.

- **#1437**: An observation and a relation can no longer collide in the search index.
  A relation's permalink is `from/type/to` with the type authored by the user, so a
  note that says `- [decision] redis` and `- observations [[decision/redis]]` gives
  both rows the identical address; Postgres raised an `IntegrityError` on write, and
  SQLite -- whose FTS5 table has no unique index to object -- kept both under one
  address, then dropped one of them on the next single-row index pass. Nothing
  surfaced either way. The search index's uniqueness now includes
  the row kind, which the table's own primary key already carried, so the two rows
  stay separately addressable. **This ships an Alembic migration** replacing
  `uix_search_index_permalink_project` with `uix_search_index_permalink_type_project`
  on Postgres; no permalink changes and no data is dropped on upgrade, and SQLite's
  FTS5 index needs no schema change.

- The `memory://{workspace}/{project}/info` resource is now actually readable over
  `resources/read`: it returned a Pydantic model, which the resource runtime rejects
  (`contents must be str, bytes, or list[ResourceContent]`), so every served read
  failed. It returns the validated response as JSON text now. Found by the new
  note-resource tests, which read through a real client session instead of calling
  the handler directly.

- **#1344**: Deleting a note no longer erases the relations pointing at it. The
  `relation.to_id` foreign key is now `ON DELETE SET NULL` rather than
  `ON DELETE CASCADE`, and `Entity.incoming_relations` no longer cascades deletes
  through the ORM. Deleting a target leaves its inbound relations in the unresolved
  state the indexer already produces for a link to a note that does not exist yet --
  `to_id` null, `to_name` holding the source's original link text -- so a
  broken-link report stops coming back clean over a vault full of them, and
  recreating the target re-links the references through the existing
  forward-reference pass. `from_id` keeps `CASCADE`: an entity does own the
  relations it declares. Rows already lost to the old behavior stay lost; re-index
  the affected notes to bring them back as unresolved.

- **#1451**: A markdown file whose leading `---` block is not a YAML mapping (a letterhead between
  horizontal rules) is now indexed as plain markdown instead of being dropped. The parser
  already treated such a block as body; the indexer separately saw fences, tried to write
  a permalink into them, hit the "refusing to update malformed frontmatter" guard, and
  excluded the file while readiness reported idle. The guard stands: the file is never
  rewritten, and `remove_frontmatter` no longer strips such a block from search content.
  Frontmatter is now classified once, by the parser, as present, absent, or
  malformed, and only the first two are ever written to.

- **#1334**: A fresh install that runs a CLI command first (`bm status`, `bm project
  add`) no longer fails with "Project not found" for the seeded `main` project; config
  projects are reconciled into the database on first use.

- **#1340**: `bm project remove` on a cloud project also removes its local routing
  entry, so the name can be added again and no stub appears in `project list`.

- **#1441**: `bm project add --cloud` creates the local sync directory before saving
  config, so a bad path leaves config unchanged; rerunning adopts the remote project
  already created.

- **#1333**: `bm schema validate` and other commands exit on Python 3.12 and 3.13
  instead of hanging after printing their result. Thanks to @WebKingdom for the
  diagnosis (#1346).

- **#1338**: Every uv install path the project controls (`bm hook install`, `bm update`,
  the Hermes and OpenClaw bootstraps, `server.json`, README snippets) passes
  `--prerelease=allow`, which the v0.23.x FastMCP beta pin required. Development builds
  are no longer published to PyPI, because that flag made them outrank the stable
  release.

- **#1506**: Core, the Codex hooks, and the Claude Code hooks move from the FastMCP
  4.0.0b1 pre-release to stable FastMCP 4.0.3. Installed Codex hooks had exited before
  running because uv could not resolve the beta.

- **#1339**: The Hermes plugin manifest declares `manifest_version: 1`, which the
  current Hermes installer accepts.

- **#1341**: The Hermes and OpenClaw tool descriptions and prompts tell agents to call
  the write tool in the same turn when asked to remember something, never to claim a
  save without a tool result, and to quote the returned permalink.

- **#1332**: A `[[wikilink]]` inside inline code no longer creates a relation. Thanks to
  @yaodong-shen (#1337).

- **#1359**: Quoted Postgres searches such as `"incident response" OR "database
  recovery"` no longer raise a `to_tsquery` syntax error that aborted the transaction;
  quoted groups are searched as grouped terms and unmatched quotes are recovered.

- **#1281**: Case-only renames (`config.md` to `Config.md`) stick on case-insensitive
  filesystems instead of being reverted by the next scan.

- **#1351**: Deleting a note through the API or MCP refreshes the search rows of notes
  that linked to it, so relation search no longer returns the deleted note.

- **#1335**: The entity-body vector is no longer split into one chunk per bullet. It
  splits on headings and the size budget, and oversized sections break at line
  boundaries. Per-fact vectors still come from the observation and relation rows.

- **#1432**: MCP identifiers and `memory://` URLs resolve against the session's own
  projects, so a bare prefix no longer routes to another workspace and multi-segment
  project names are reachable. `find --meta` results round-trip as inputs (#1435,
  #1428).

- **#1431**: A filtered vector or hybrid search no longer drops matches that fell
  outside the first 50,000 rows of the filter's match set, which had hidden the newest
  notes.

- **#1388**: `BASIC_MEMORY_MCP_PROJECT` matches projects case-insensitively by
  permalink, so startup indexing and watching pick up a mixed-case name.

- `edit_note(metadata={"type": ...})` changes an existing note's type, and append or
  prepend that creates a note honors the requested type (#1472).

- `bm hook` installs and reads Claude Code hooks in the profile named by
  `CLAUDE_CONFIG_DIR` instead of always `~/.claude` (#1473).

- **#1430**: On Windows, file-backed SQLite uses a bounded five-connection pool instead
  of `NullPool`, which failed concurrent writes with `database is locked`.

- Moving a PDF or other non-Markdown file preserves its bytes; the move had tried to add
  frontmatter to it (#1485).

- **#1378**: MCP API calls retry an HTTP 429 that carries a valid `Retry-After`, up to
  three attempts within a 30-second budget. Non-replayable request bodies are not
  retried.

- `bm cloud pull` and `bm cloud push` over WebDAV (Team workspaces) wait out rate limits
  using `Retry-After` instead of aborting the transfer on the first 429 (#1532).

- **#1479**: `write_note` decides between create, update, and conflict in one typed
  operation instead of matching exception text. A write to a vacant path whose permalink
  belongs to a moved note returns `NOTE_PATH_CONFLICT` with the note's current path, and
  locked-note refusals are reported as such.

- **#1538**: A Markdown note indexed as a plain resource is repaired by the next scan.
  Thanks to @wangzhengzhuo05 (#1542).

- **#1539**: `.bmignore` and `.gitignore` patterns honor escaped hashes (`\#*#`) and
  escaped or leading whitespace. Thanks to @wangzhengzhuo05 (#1540).

- **#1537**: Emacs `#note.md#` autosave files are not indexed.

- **#1534**: `search_notes` and `recent_activity` on a project that has never been
  indexed return "Project Index Required" guidance instead of an empty result. Thanks to
  @wangzhengzhuo05 (#1535).

- **#1533**: An empty search for an unspaced CJK compound returns a `query_hint`
  suggesting a shorter word or spaces between words.

- **#1390**: Relation search refresh cleanup deletes markers in batches of 500, so a
  backlog larger than asyncpg's 32,767-parameter limit no longer fails relation
  resolution.

- Indexing converges under production load: a note rewritten faster than it indexes
  settles on the newer accepted write, a MIME-marked `.md` path with no note basename
  stays a resource, and a relation refresh for an entity whose content is gone no longer
  crash-loops (#1374). A file deleted between the existence probe and the checksum read
  is treated as absent instead of failing materialization (#1383).

- **#1714**: Wiki projector pages are no longer embedded. A page counts as
  projector-owned while its current accepted revision came from the projector
  (`note_content.last_source`), not by file name. Vector sync deletes such a page's
  vectors, embeds nothing, and reports it as skipped. Full-text rows and relations
  are unchanged, so generated `index.md` links still feed the graph. A hand-written
  `index.md` is embedded as before, and a generated page someone edits is embedded on
  its next sync. In Cloud, the embedding jobs queued for projector writes become cheap
  deletes.

- **#1275**: On macOS, file paths are normalized to NFC where they enter the index.
  macOS resolves NFC and NFD spellings to one file but reports whichever is on disk,
  and Syncthing keeps NFD names, so a flipped name could create a `-1` twin and make
  `edit_note` fail on the permalink constraint. Migration 0042 merges existing twins
  (macOS only). Linux and Windows keep byte-exact paths. **#1801**: the migration no
  longer fails with `no such module: vec0` when a vector table exists.

- **#1775**: `edit_note` append/prepend that creates a missing note from a
  project-qualified identifier no longer nests it under a folder named after the
  project. The server decides where the note goes from the folders that already hold
  notes (indexed, accepted or on storage), refuses an identifier that two folders could
  match with `AMBIGUOUS_NOTE_PATH`, and refuses any reading outside the project before
  looking at a folder.

- **#1769**: A full-document `PUT` of a note (Cloud's web editor) deletes frontmatter
  keys the request leaves out, instead of keeping them from the stored note.
  `write_note(overwrite=True)` still merges frontmatter.

- **#1781**: A new note without a frontmatter `created` keeps the file's creation time
  instead of the time of the index run. Thanks to @ningyixi.

- **#1778**: In a hosted session that can reach several workspaces, a POSIX refusal for
  a path naming a project in another workspace names that workspace and the spelling
  that reaches it, and `ls /` lists the accessible workspace slugs. A discovery failure
  no longer turns `ls /` or a refusal into an error. Local sessions make no new
  control-plane calls.

- `move_note` can rename a `.markdown` note to `.md`. Other extension changes are still
  refused.

- `write_note`'s similar-notes advisory skips notes with `generated:` in their
  frontmatter (Wiki indexes and logs, agent run logs).

- **#1789**: A Wiki run reports source folders that differ only by letter case or
  Unicode normalization (`customers/CPC` and `customers/cpc`) instead of failing the
  whole run every time.

- **#1790**: `bm import chatgpt` imports conversations that have no title, naming them
  `Untitled conversation <id prefix>`, instead of failing the import with `KeyError`.

- **#1788**: Editing a note with many vector chunks updates the reused chunks' metadata
  in set-based batches instead of one statement per chunk.

- **#1762**: Read-cache invalidation deletes the entries it retires instead of leaving
  them in Redis until their TTL. **#1761**: Read-cache hits are no longer recorded as
  error spans.

- The Hermes plugin masks credentials on its capture path, including bearer tokens and
  quoted field names.

- Skill tooling reads and writes skill files as UTF-8 with LF line endings, which fixes
  the Windows unit job.

### Internal

- FastMCP 4.0.3 → 4.1.3 and mcp 2.0.0 → 2.3.0, including the Claude Code and Codex
  hook pins. FastMCP now applies its Host/Origin guard to the SSE transport, so
  `basic-memory mcp --transport sse` uses it instead of installing its own copy.
  Streamable HTTP sessions now expire after 30 idle minutes (the MCP SDK default);
  clients start a new one.

- **#1672**: Indexing and embedding results report the work they did. `FileIndexResult`,
  `IndexedEntity` and `SyncedMarkdownFile` carry `indexed_bytes`, the stored bytes read
  and parsed (zero for a file that was already current). Embedding results carry
  `chunks_embedded`, the chunks actually sent to the embedder, and
  `sync_entity_vectors` returns a `VectorSyncBatchResult`. How indexing and embedding
  run is unchanged.

- **#1660, #1671, #1673**: A note's storage echo is recognized instead of re-indexed.
  Materialization records the written object's storage checksum, storage and content
  checksums are compared only with their own kind, and an object whose content matches
  the note's accepted content counts as current even before its storage checksum is
  recorded. Index-file results carry the content checksum, so a live update for an
  accepted write matches its existing activity. Locally both checksums are the same
  sha256, so this only changes behavior where storage reports its own checksum (S3).

- **#1661**: The accept transaction writes the pending relation-publication marker, so
  an accepted note is never visible without it, and a successful publication leaves
  exactly one unit of refresh work. A PUT that renames a note carries the previous path
  into materialization, as an explicit move does. The accepted-note runner tests run
  against a real database (#1668).

- **#1658**: Alembic revisions after `z9a0b1c2d3e4` are named by sequential schema
  version (`0040`, `0041`, ...). `migrations.schema_version()` reports a revision's
  number and `migrations.next_revision_id()` assigns the next one.

- **#1669**: CI balances the Postgres test shards by recorded durations and runs the
  Windows jobs only on `main`.

- **#1613**: Note object metadata keeps an origin for `agent` and `mcp_client` actors,
  not only MCP clients, so cloud can attribute API-key writes to the key's name.
  `system` writers still carry no named origin.

- **#1602**: Hot paths emit far fewer Logfire spans and INFO logs: per-sub-step read-cache
  and indexing spans collapse to one span per operation, and per-item INFO logs move to
  DEBUG. Counters and error logs are unchanged.

- **#1558**: Search filter compilation now runs over an explicit `ProjectScope` instead of
  a repository-bound `project_id`. FTS term preparation and filter compilation moved out
  of the SQLite and Postgres repositories into `sqlite_search_query` and
  `postgres_search_query` as pure functions returning a `CompiledFilter`, and the filters
  both backends share (scope, permalink, directory, item type, category, note type,
  `after_date`, valid time, candidate keys) are compiled once in `search_filters`. The
  note-type and valid-time predicates match search rows on their full
  `(project_id, ...)` identity. Project repositories call the compilers with a scope of
  one; no query behavior changes. First step of the shared single/multi-project reader.

- **#1558**: Full-text execution leaves the project repositories. `SQLiteFts` and
  `PostgresFts` run a compiled statement for any `ProjectScope` and own their engine's
  failure semantics (FTS5 syntax errors answer empty, Postgres retries a malformed strict
  tsquery relaxed inside a savepoint). `SearchRepositoryBase.search` and `count` are
  concrete: shared vector/hybrid dispatch, then the engine's `FtsBackend`. The base read
  path binds every statement to the repository's scope (manifest hydration, candidate row
  fetch, readiness and drop classification). `PreparedSearchQuery` moves to the repository
  layer with defaults, and the filter helpers both backends share move from the base into
  `search_filters`. No query behavior changes.

- **#1558**: Retrieval leaves `SearchRepositoryBase`. `SearchReader` runs one prepared
  query over one `ProjectScope` in whichever mode it asks for, and `SemanticSearch` owns
  vector and hybrid retrieval (adapter lookup, manifest hydration, the structured filter
  pass, score fusion, reranking, pagination) over a `VectorRetrieval` that is present or
  absent rather than probed with `hasattr`. The repository keeps what only it knows
  (whether semantic search is enabled and its vector tables exist) and builds a reader
  per call from its current state. Hydrated chunks are a typed `HydratedChunk`, which
  retires the `best_distance` compatibility branch and the per-backend
  `_distance_to_similarity` hooks the adapters had already replaced. Test doubles
  construct the pipeline directly instead of subclassing the repository. No query
  behavior changes.

- **#1558**: Vector adapters are bound to the database, not to a project. `VectorIndexScope`
  is the database namespace plus embedding schema; every write names the project it
  touches (`upsert(project_id, ...)`, `delete(project_id, ...)`,
  `delete_entity(project_id, ...)`, `delete_orphans(project_id, ...)`) and `search` takes
  a `ProjectScope`, so one sqlite-vec or pgvector adapter answers a query across any set
  of projects with one statement. Milvus keeps a collection per project and searches the
  collections in scope. `SemanticSearch` passes its scope through, so a project
  repository's vector search is unchanged. No query behavior changes.

- **#1556**: A hybrid hit found only by full-text search returns `matched_chunk: null`
  and relies on the bounded `content` preview, instead of copying the whole note into
  `matched_chunk`; vector-matched passages are unchanged. Search stages (hybrid FTS,
  query embedding, vector lookup, hydration, fusion, reranking, cache) get their own
  trace spans.

- **#1555**: The local FastEmbed reranker scores candidates in batches of eight with the
  ONNX CPU memory arena disabled, so hybrid searches stop leaving inference buffers
  resident after the request.

- **#1446**: The first `bm status` on a never-indexed project no longer reads every file
  to hash it.

- **#1454**: `QUERY /v2/projects/{project_id}/knowledge/entities/batch` returns accepted
  Markdown for up to 25 notes in one query, for hosted search hydration, and the search
  read cache now keeps entries for 30 minutes instead of 30 seconds.

- **#1347**: The portable batch indexer applies the caller's metadata concurrency limit
  to the search-index refresh phase too, so cloud batch jobs stay within their database
  connection budget.

- Extension seams for cloud: a subclass can write inside the accept transaction (#1483),
  completed schema validation has an overridable observer that reports the resolved
  schema identity (#1491, #1494), and `agent_runtime` is an accepted note source so
  managed-agent writes materialize (#1505).

- **#1400**: The benchmarks package gains BEAM and xAFS dataset adapters and an
  agent-task harness that compares the rich and POSIX tool surfaces, with resumable
  scoring, configurable model endpoints, and secret redaction in saved errors. A
  multilingual embedding benchmark covers chunk boundaries and model-cache measurement.

- **#1791** (#1793, #1794, #1795, #1802): Postgres search is faster on large projects.
  The admitted-chunk count reads the chunk manifest alone, FTS text conditions run only
  on GIN candidates, chunk candidates come from the GIN index, and multiword queries
  collect each operand's matches through GIN once.

- **#1779**: A dev-mode `.envrc` keeps a development checkout's Basic Memory config
  separate from the installed one.


## v0.23.2 (2026-08-25)

Patch release fixing case-duplicate folder creation.

### Bug Fixes

- **#1326**: `write_note` and `move_note` no longer create case-duplicate
  folders (`schemas/` beside an existing `Schemas/`). When a requested
  directory is not an existing folder but matches exactly one existing folder
  case-insensitively, the note lands in the existing folder — nested paths
  resolve per segment; unknown folders are still created as given, and
  existing case-variant siblings keep today's exact behavior. Folders are
  resolved from the indexed database paths, so local and cloud runtimes
  behave identically, and content-only note updates skip resolution entirely.
  `move_note` reports the actual landing path on a case-corrected move
  instead of a false failure, while a basename divergence still fails
  honestly.

## v0.23.1 (2026-08-25)

Fast-follow patch to v0.23.0 focused on PostgreSQL search parity and a
search-destroying reindex bug. Postgres now indexes complete note bodies for
full-text search (previously only titles and capped content stems, unlike
SQLite), and the per-project search reindex no longer wipes every other
project's search rows in the same database. Also adds a `#bm:links_to`
directive for disambiguating prose wiki-links, and hardens `bm update` output
after in-place upgrades.

### Features

- Added the `#bm:links_to` directive: ending a list item with `#bm:links_to`
  forces the reference to the implicit `links_to` relation, so a single-token
  prose prefix (`- Mother [[Alice]] #bm:links_to`) is not parsed as an
  explicit relation type. The directive stays in the source file but is
  stripped from indexed observation and relation content.

### Bug Fixes

- PostgreSQL full-text search now covers complete note bodies. Note content is
  indexed as bounded, overlapping chunks in a new `search_index_fts_chunks`
  table (a migration backfills existing notes), so deep content matches on
  Postgres the way it always has on SQLite FTS5. The work includes correct
  Boolean AND/NOT semantics across chunk boundaries, apostrophe and
  punctuated-operand handling (`can't`, `v0.13.0b2`, `auth-service`),
  metadata-filter composition, 100+ operand queries, and candidate
  preselection so both GIN indexes stay in play.
- The per-project search reindex (`POST /search/reindex`) no longer drops the
  shared `search_index` table. Dropping it destroyed every project's search
  rows in the same database — and on Postgres nothing outside migrations
  recreates the table, so cloud tenants lost search entirely until manual
  repair. The rebuild now deletes only the reindexed project's rows (chunk
  rows cascade), and the chunks migration recreates a missing `search_index`
  so databases hit by the old behavior migrate cleanly.
- **#1316**: `bm update` status output no longer crashes after an in-place
  upgrade removes the running install's files: rich's deferred Unicode width
  table is preloaded before upgrading, and status lines fall back to plain
  output instead of failing a completed update.
- **#1323**: `bm doctor` no longer fails when `BASIC_MEMORY_PROJECT_ROOT`
  points at an existing project's directory. Doctor now asks the server for a
  disposable `doctor-*` project under the configured root — the only
  sanctioned exception to the nested-project guard — and cleanup deletes the
  project's directory along with its registration.
- `bm doctor` waits for deferred note materialization before verifying the
  API-written file, matching the accepted-write contract instead of racing it.

## v0.23.0 (2026-08-23)

Semantic search grows up and concurrent writes stop deadlocking. Search gains
opt-in cross-encoder reranking, pluggable vector indexes with a first-party
Milvus adapter, and a batch of embedding-correctness fixes; the indexing and
persistence path is rebuilt around generation-versioned, compare-and-swap
writes so concurrent multi-agent workloads can no longer deadlock or lose
observations and relations. Day-to-day operation gets a real front door with
`bm config`, Rich `bm tool` output, a diagnostics tool, an honest reindex,
and a retrieval inspector — `bm inspect chunks` shows a note exactly as the
index sees it and `bm inspect query` traces how a search ranked its results;
`bm hook` brings harness lifecycle capture into the package; and cloud adds
`bm cloud share`, `bm cloud prune`, an optional Redis read cache, and Team
workspace `bm cloud push`/`pull` over permissioned WebDAV. Five database
migrations run automatically on first start, including a one-time repair
that dedupes duplicate observation rows and purges their stale full-text
search entries.

### Breaking Changes

- **#1111**: The `canvas` MCP tool is removed, along with the API resource
  write endpoints that backed it (**#1106**). Obsidian canvas generation is
  no longer available.
- **#1145**: The `cloud_info` and `release_notes` MCP tools are removed.
- **#1121**: Pre-v0.18.0 legacy HTTP API routes are dropped (**#1116**).
  Old clients still calling them now get 404s.
- **#1035**: The ChatGPT-compatibility `search`/`fetch` tools now refuse
  non-OpenAI MCP clients with a clear rejection; other clients should use
  `search_notes`/`read_note` instead.
- **#1061**: One-way `bm cloud sync` now deletes newly-`.bmignore`d files
  from the cloud instead of leaving them there forever (**#1032**).
  Intentional, but destructive relative to prior behavior — review your
  `.bmignore` before the first mirror after upgrading.
- **#1002**: `bm status` is redesigned around project index status; scripts
  that scraped the old sync-report output will break. As part of this, the
  config keys `sync_delay`/`sync_changes` are renamed
  `index_delay`/`index_changes` — legacy config.json keys and
  `BASIC_MEMORY_SYNC_*` env vars are auto-migrated, no action needed.
- The `sync_thread_pool_size` and `sync_max_concurrent_files` config keys
  are removed with no alias and are silently ignored if present; the closest
  replacement knob is the new `materialization_workers` setting.
- **#1240**: `bm reindex --embeddings` now exits nonzero when entities fail
  to embed, surfaces the failures, and reports which index identity it wrote
  (**#1237**). Wrappers that relied on unconditional exit 0 must handle real
  failures.
- **#1063**: `edit_note`'s `replace_section` is heading-level-aware and now
  replaces nested subsections by default instead of silently preserving
  content past the next heading; pass `replace_subsections=false` for the
  shallow behavior (**#1012**).
- **#1082**: `list_directory` results are bounded and paginated (**#1048**).
  Consumers expecting one exhaustive listing must page.
- **#1198**: The MCP server now runs on FastMCP 4.0.0b1 and MCP SDK v2 — a
  beta framework release. Downstream embedders pinning FastMCP 3.x must
  upgrade together.

### Features

- **#1143**: Opt-in cross-encoder reranking of vector/hybrid search
  candidates (**#950**, **#618**, **#666**): `reranker_enabled` (default off) with a
  local FastEmbed ONNX reranker or LiteLLM API rerankers (Cohere, Jina,
  Voyage), plus candidates, timeout, char-cap, and API tuning knobs.
- **#1141**: Pluggable semantic vector indexes on Postgres (SPEC-81):
  `semantic_vector_index` selects `pgvector` (default) or `milvus`, and a
  new index identity/readiness manifest lets vector search tell "no ready
  index" from "no results". SQLite keeps sqlite-vec. After switching
  backends, run `bm reindex --embeddings`.
- **#1158**: First-party Milvus, Milvus Lite, and Zilliz Cloud vector index
  adapter via `pip install basic-memory[milvus]`; existing collections
  reload after restart (**#1185**), with identical rankings verified across
  sqlite-vec, pgvector, and Milvus Lite.
- **#1043**: LiteLLM embeddings accept a custom `api_base` and direct
  `api_key` for OpenAI-compatible and self-hosted servers (**#1005**), and
  literal document/query prefixes support prefix-sensitive asymmetric
  models (**#1044**, **#1008**).
- **#1249 / #1250**: New retrieval inspector (**#1155**). `bm inspect
  chunks <note>` shows a note exactly as the index sees it — its search
  rows, the vector chunks each row produced, and per-chunk
  ready/pending/stale/orphaned status — separating chunking problems from
  freshness problems in one command. `bm inspect query "<query>"` captures
  an opt-in execution trace from the same search call that returns the
  results: FTS and vector candidates, fusion, filtering, reranking, and the
  final page window, with stable JSON output and `--show-misses` for
  rejected candidates. Ordinary search behavior and responses are
  unchanged.
- **#1088**: New `bm config` command group: `list` (effective values with
  env overrides marked), `get`, `set` (validated through the config model),
  and `unset` (**#991**).
- **#967**: Interactive `bm tool` commands render Rich panels, tables, and
  trees on a TTY, with a `cli_output_style` setting and per-invocation
  `--plain`/`--json` overrides; piped output stays machine-readable
  (**#678**).
- **#963**: New `basic_memory_diagnostics` MCP tool reports version and
  system info for bug reports (**#187**).
- **#1018**: The local Postgres backend is usable end to end: migrations,
  connection pooling, and default-project resolution.
- SQLite write-path tuning is exposed via new `sqlite_synchronous`,
  `sqlite_mmap_size`, `sqlite_wal_autocheckpoint`, and `sqlite_page_size`
  settings.
- **#1100**: `created`/`modified` frontmatter timestamps are honored as note
  timestamps (**#238**). Recency ordering can change after the first
  re-sync for notes carrying historical dates.
- **#1079**: Notes written through the API/MCP persist their observations
  and relations immediately instead of waiting for the next file re-index
  (**#1076**).
- **#1227 / #1220 / #1228**: Persistence is generation-versioned with
  compare-and-swap publication — a stale indexing pass can never clobber or
  deadlock against a newer write, so observations and relations stay intact
  under concurrent agent write load (**#1224**, **#1213**, **#1214**).
- **#1204 / #1132 / #1131**: Relation resolution and vector prepare work are
  batched instead of serial, and a new `materialization_workers` setting
  (default 4) bounds concurrent write materializations.
- **#1165**: Relation-derived search refreshes are durable, retryable work
  items (**#1163**), pending relations refresh from accepted content
  (**#1161**, **#1159**), and forward references back-resolve when their
  target note is created, without a full reindex (**#1015**).
- **#1070**: Added the `bm hook` harness front door (SPEC-55, **#997**).
  Lifecycle verbs (`session-start`, `pre-compact`, `stop`) move plugin hook
  logic into the package behind per-harness stdin adapters. Default-on
  bounded envelope capture records lifecycle metadata into a local inbox
  WAL; `bm hook flush` archives it locally, `bm hook status` shows the
  surface, and `captureEvents: false` disables capture. `bm hook install` /
  `bm hook remove` wire hooks into user-level harness config for standalone
  users with ownership-tagged, surgical merging. The Claude Code and Codex
  plugin hooks are now zero-logic PEP 723 uv scripts invoking
  `basic-memory hook` in-process, with `BM_BIN` overriding the uv-managed
  environment for development.
- **#1119**: Plugins surface hook capture setup and health (**#1117**), and
  Claude Code hook config falls back to user-level `~/.claude` settings
  (**#924**).
- **#1123 / #1138 / #1142 / #1147**: Codex hooks and memory notes are
  reliable, checkpoints are authored and prompted after compaction, and
  checkpoints are directly resumable.
- **#1124 / #1126 / #1050**: New skills: `bm-writing` with coding setup,
  `bm-decide`/`bm-orient`, and the shared `memory-onboarding` skill; coding
  session profiles are queryable (**#1125**).
- **#965**: New `bm cloud share` command group: `create`, `list`, `update`,
  `revoke` (**#880**).
- **#1061**: New `bm cloud prune` removes `.bmignore`d files from the cloud
  on demand (**#1032**; see Breaking Changes for the one-way sync behavior
  change).
- **#1263**: Team-workspace `bm cloud push`/`pull` run over the service's
  permissioned WebDAV surface instead of tenant-wide storage credentials,
  so any member can sync the projects they have access to — previously only
  workspace owners could provision the required credentials and every other
  member got a 403 (**#1262**). Same flags and semantics: `--on-conflict`
  still defaults to `fail`, and transfers stay additive — nothing is ever
  deleted. Requires the updated cloud server, already deployed in
  production; the Personal rclone path is untouched.
- **#1168 / #1172**: Optional Redis read caching accelerates standalone MCP
  reads via the `basic-memory[redis]` extra (`redis_url`,
  `redis_max_connections`) (**#980**).
- **#1255**: Semantic note reads make the minimum number of API requests —
  exact-ID reads skip resolve and resource calls entirely — and ordinary
  read-cache entries live 300 seconds instead of 60.
- **#1062 / #1074**: Cloud project deletion errors are surfaced, with an
  optional notes purge and a visible deletion job (**#1033**, **#1034**).
- **#1145**: First-connect MCP onboarding: server instructions, empty-state
  guidance, and a `getting_started` prompt for new users.
- **#1090**: `edit_note` accepts a `metadata` param to update frontmatter
  fields (**#1011**).
- **#1075**: `move_note` returns the previous accepted path (**#1072**).
- **#1040 / #1101 / #1103**: `external_id` is exposed in `list_directory`,
  `recent_activity`, search results, and `search_notes` markdown output.
- **#1268**: `list_directory` accepts a `sort` parameter (`title_asc`,
  `title_desc`, `updated_asc`, `updated_desc`) with deterministic
  folders-first ordering applied before pagination (**#1267**); omitting it
  keeps the existing filename order.
- **#1031 / #1036 / #1037**: MCP tool annotations are directory-compliant,
  destructive hints are explicit, and `edit_note` exposes its operation
  enum.

### Bug Fixes

- **#1193 / #1202**: Two indexing deadlock families are eliminated:
  Entity/NoteContent lock-order inversions during materialization and
  Entity/Observation inversions between indexing and accepted writes
  (**#1187**, **#1199**, **#1209**).
- A one-time migration dedupes historical duplicate observation rows and
  purges their orphaned full-text search entries (companion to **#1228**).
- **#1247**: Incremental `bm reindex --search` purges stale search-index
  rows whose backing entity, observation, or relation is gone, so DB-only
  search divergence on unchanged files converges without a `--full` rebuild
  (**#1226**; the last loose end of the **#1214** repair).
- **#1152 / #1160**: Moves record a durable vacate marker, so a
  byte-identical copy at the old path indexes as a new note instead of
  being skipped as a lingering move source.
- **#1258**: A note accepted while a project scan is in flight can no
  longer be deleted as "externally removed" — destructive project-index
  deletes re-verify the database lineage and the path's current absence
  from storage at apply time (**#1256**).
- **#1016**: Direct on-disk edits picked up by the file watcher are now
  vector-embedded, so externally edited notes no longer go missing from
  semantic search until a reindex (closed by the vector-sync overhaul,
  **#1129**–**#1131**, **#1141**).
- **#1023**: FastEmbed embeddings are L2-normalized for non-bge models, so
  semantic search no longer silently degrades to FTS-only.
- **#1071**: SQLite full-text search covers complete note content —
  previously content beyond ~6000 characters was invisible (**#1065**) —
  and CJK terms work in the relaxed FTS fallback (**#1022**).
- **#1269**: Full-text query relaxation counts non-Latin tokens, so
  Cyrillic, Greek, Hebrew, Arabic, and other non-Latin queries relax to an
  OR retry instead of silently degrading hybrid search to vector-only
  ranking, and combining marks stay inside their word so Devanagari and
  Thai terms are not shredded into fragments (extends the CJK-only fix from
  **#1022**).
- **#1069**: Unknown semantic/hybrid result totals are explicit in
  structured search responses (**#1068**).
- **#1190**: `bm reindex --embeddings` warns when the project has no synced
  entities instead of silently no-opping (**#1184**).
- **#1196**: A legacy pgvector embeddings schema no longer breaks
  `bm project info` (**#1195**).
- **#1151**: Ambiguous identifier resolution fails loudly instead of
  returning the wrong note (**#1148**), and project-scoped entity
  resolution is separated from cross-project wikilink resolution
  (**#1192**, **#1170**).
- **#1272**: Root-level wikilinks written as filename stems resolve via the
  `.md` file-path fallback, and a forgiving underscore/hyphen/case alias
  resolves links in directly edited vaults — tried only after every exact
  identity, and failing closed when two files collide on the same alias
  (**#1253**).
- **#1189**: Note-type filters are case-canonicalized, so `Person` and
  `person` match the same population (**#1180**).
- **#1081**: `write_note` rejects filename-convention twins (kebab-case vs
  Title Case) instead of creating duplicate notes (**#1077**).
- **#1073**: `edit_note` with a `memory://` URL routes to the target
  project instead of creating phantom notes (**#1066**), and scoped
  `memory://` URL paths are preserved (**#1092**).
- **#1299**: `build_context` bounds its traversal requests — primary pages
  cap at 50 results, related context at 100 per page, and negative
  `max_related` is rejected instead of acting as an unbounded SQL limit —
  so a traversal call can no longer become a multi-megabyte vault export
  (**#1296**). Callers paginate or follow returned `memory://` links.
- **#1285**: Glob-filtered directory listings traverse subdirectories
  again: `file_name_glob` filters results instead of accidentally pruning
  recursion, so `*.md` with depth 2 finds files inside subdirectories.
- **#1188**: Sync preserves malformed frontmatter instead of prepending a
  second frontmatter block that shadows `name`/`description` (**#1171**).
- **#1239**: Timestamp-prefixed transcript lines and checkbox markers
  (`[x]`, `[/]`, `[>]`, `[?]`) no longer mint junk observation categories
  (**#1219**, **#1241**).
- **#1271**: Transcript timestamp ranges like `[24:33.098 - 24:41.260]` no
  longer mint junk observation categories either — the remaining
  range-shaped case from **#1239** (**#1270**).
- **#1291**: Prose bullets no longer mint typed relations: a sentence like
  `- Added [[Target]] to the roster` filed a relation *type* called `Added`
  and silently dropped the rest of the line, including any further links in
  it. An explicit relation now ends at its target or its `(context)`;
  anything else keeps every wikilink as a plain `links_to` edge (**#1260**).
- **#1060**: `schema_validate` with no arguments validates all
  schema-covered types instead of type "unknown" (**#1013**), and invalid
  schema-validation modes are rejected instead of silently degrading to
  warn (**#1223**, **#1222**).
- **#1085**: Re-adding a retained cloud project reindexes its existing
  notes (**#1084**).
- **#1010**: `bm project list` shows configured cloud-mode projects even
  when uncredentialed (**#1003**), and deleting the default project
  auto-reassigns the default instead of refusing (**#1139**).
- **#1273**: Re-selecting the project that is already the default no longer
  clears the default flag — a state that broke project discovery and every
  project-scoped MCP tool until a default was set again.
- **#1290**: ChatGPT import no longer crashes on conversations missing
  `create_time` — timestamps fall back to `update_time`, then the earliest
  message time, so the whole archive imports (**#1276**); undecodable
  import uploads return a 400 with the parse error instead of a 500.
- **#1298**: The update check no longer reports "up to date" when the
  Homebrew probe fails, no longer auto-runs `brew upgrade` for an update
  inferred from PyPI metadata, and names the actual Homebrew target
  version it will install.
- **#1300 / #1302**: The multilingual-E5 prefix contract is documented —
  asymmetric FastEmbed models need `semantic_embedding_query_prefix` /
  `semantic_embedding_document_prefix`, which already drive reindex through
  the embedding identity — along with custom-model selection, the installed
  FastEmbed catalog, and dimensions (**#1264**).
- **#1058 / #1094**: `bm doctor` never prints a blank failure message, and
  migrations adapt to existing event loops (**#1027**).
- **#1080**: Loading config no longer recreates an empty `~/basic-memory`
  directory as a side effect (**#1029**).
- **#1057**: Large projects no longer crash reindex on SQLite's
  bound-parameter limit (**#1045**).
- **#1218 / #1216**: Windows: the MCP server no longer dies at startup on a
  log-cleanup race (**#1211**), note content no longer crashes log
  formatting during index retries (**#1212**), the watch service no longer
  crashes on mapped network drives (**#1047**), and a PermissionError
  during project scan no longer triggers mass index deletion (**#1007**).
- **#1059 / #1179**: Hermes: `bm mcp` child processes no longer leak
  (**#1017**), and bm subprocesses no longer inherit Hermes's Python
  environment (**#1093**).
- **#1274**: Hermes: commands and skills register through Hermes's own
  registration APIs instead of private PluginManager writes, preserving the
  lifecycle ownership that cleans them up on provider unload (**#1257**);
  the slash-command monkeypatch docs are split by Hermes version so modern
  installs skip the legacy collector workaround (**#1278**), and the install
  docs require a Hermes release with managed manifest-v2 installation
  instead of the nonexistent `--path` option (**#1280**, **#1303**).

### Maintenance

- **#1113 / #1114**: Dependency injection is consolidated behind the v2
  composition roots (**#1109**).
- **#1122 / #1133–#1136 / #1229**: The largest service god-files are split
  into focused modules (**#1108**).
- Removed the hook-specific redaction subsystem, its `detect-secrets`
  dependency, and the retired lifecycle projector compatibility module.
- Kept Milvus as a first-party optional vector backend while removing the
  unused Python entry-point registry for separately packaged vector
  adapters.
- **#1292 / #1293**: The dev-release pipeline publishes again via PyPI
  trusted publishing — its version gate imported a hardcoded module version
  and had silently skipped every dev publish since the 0.22.1 bump.
- **#1304 / #1307**: The concurrent-write convergence benchmark is ported
  into the canonical `/benchmarks` package, and the read-load benchmark
  runs against the current MCP SDK's typed result fields.

## v0.22.1 (2026-06-12)

Follow-up patch to v0.22.0. Fixes project and default-project resolution on
fresh installs, MCP workspace routing, sync project selection, and CLI startup
latency, plus a few MCP parity additions.

### Features

- Added a `workspace` parameter to `write_note` for parity with `edit_note`.
- **#826**: Added `title` and `tags` annotations to all MCP tool decorators
  (phase 1).
- **#930**: `search_notes` now comma-splits `note_types`, `entity_types`, and
  `categories`.
- **#971**: Added the manual-pages flow — manpage seed schema, flow docs, and
  verification fixes.

### Bug Fixes

- Fresh installs no longer fail when the projects table is empty: resolve now
  points them at project setup, the first project is promoted to default when
  the config default is missing from the database, the promoted default state
  is returned from the project-create API, and a default can be set when none
  is currently set. An existing database default is preserved when repairing a
  missing config default.
- **#949**: Sync skips projects without an absolute local path and excludes
  orphan DB projects that are absent from config.
- **#952 / #981**: Resolved workspace display names and tenant ids in qualified
  project routes, closing out the manual verification findings.
- `note_types`/`entity_types`/`categories` are normalized on the direct-call
  path, with non-string list elements rejected.
- Vector-search hydration keys on `(type, id)` to prevent id collisions.
- `file_utils` requires line-anchored frontmatter fences.
- CLI startup is faster: FastAPI and app imports are deferred out of CLI
  startup, and rich/typer modules are preloaded before an in-place upgrade.
- `config.json` is written atomically.
- In-memory SQLite sessions are serialized so concurrent rollbacks cannot
  destroy writes.

### Maintenance

- Release recipes route through PRs and wait for the release PR merge to land
  before tagging; the release runbook is refreshed and stripped of
  user-specific absolute paths.

## v0.22.0 (2026-06-11)

Team-safe cloud sync. New additive `bm cloud push` and `bm cloud pull`
commands work safely on shared Team workspaces, while the destructive mirror
commands are gated to Personal workspaces. Also: a large batch of MCP tool
fixes, search improvements, and embedding reliability work.

### Features

- **#917**: Added Team-safe `bm cloud push` / `bm cloud pull`. Both are
  additive (they never delete on the destination) and abort on conflicts by
  default, git-style, with `--on-conflict {fail|keep-local|keep-cloud|keep-both}`.
  The destructive `bm cloud sync` / `bm cloud bisync` mirrors are now gated
  to Personal workspaces.
- **#920**: Team push/pull uses per-workspace rclone remotes, so remotes and
  credentials stay scoped to each workspace.
- **#908**: Search supports an observation category filter.
- **#809**: Added an experimental LiteLLM embedding provider for semantic
  search (marked experimental, see **#899**).
- **#907**: `bm tool write-note` accepts `--type`.
- **#906**: `bm status` accepts `--wait` and `--timeout`.
- Added the `bm tool delete-note` command.
- **#905**: Improved workspace and cloud bisync command discoverability.

### Bug Fixes

- **#931 / #946**: Truncated observation permalinks are disambiguated to
  prevent search-index collisions, and `build_context` resolves observations
  by the same permalink the search index uses (**#909**, **#929**).
- **#934**: `edit_note` recovers when the file exists on disk but is not yet
  indexed (**#581**).
- **#911 / #932 / #941**: Comma-separated tags are split consistently in
  `parse_tags` and the `search_notes` tags parameter, with input normalized
  for direct callers (**#910**).
- **#933**: `read_note` accepts `page`/`page_size` for parity with sibling
  tools (**#883**).
- **#914 / #904 / #916**: `move_note` resolves `memory://` URLs, stops
  falsely rejecting same-project moves as cross-project, no longer reports
  false success across project boundaries, and mismatch guidance points at
  the landing path.
- **#915**: Navigation pagination is validated, and `recent_activity` shows
  the correct project.
- **#913**: `bm tool` commands align with MCP behavior (error exit codes,
  overwrite handling, category support, defaults).
- **#923**: `bm cloud setup` no longer overwrites an existing rclone remote
  (**#922**).
- **#912**: The `note_types` search filter is case-insensitive.
- `build_context` allows cross-project context traversal, `write_note`
  resolves overwrite conflicts, and sync uses strict deferred relation
  resolution.
- Embedding reliability: FastEmbed vectors are L2-normalized (**#843**),
  corrupt FastEmbed model caches self-heal (**#900**), a single embedding
  provider is reused per process (**#903**), `sqlite-vec` loads for the
  embedding-status query (**#901**), and engine disposal no longer crashes
  on the Postgres backend (**#902**).

### Maintenance

- Leaner, faster CI: testmon-selected branch builds, sharded Postgres jobs,
  and faster default test fixtures (**#928**, **#938**, **#945**).
- Documented personal-vs-team cloud sync semantics (**#947**, closes
  **#851**).
- Fixed npx skill install docs (**#927**).
- Added `glama.json` to claim the Glama MCP directory listing (**#953**).

## v0.21.6 (2026-06-04)

Monorepo consolidation plus a redesigned Claude Code plugin. The satellite
repositories now live in the main `basic-memory` tree, and the plugin is
rebuilt as a memory bridge with a guided setup interview, capture skills, and
team workspaces. Codex, Hermes, and OpenClaw integration packages ship
alongside it.

### Core

- Consolidated the Basic Memory satellite repositories into the main
  `basic-memory` tree as the canonical source, discovery, documentation,
  issue, and release home.
- Added root marketplace/package validation for the consolidated repository
  layout.
- Added root and package-local justfile targets so Claude Code, Codex, skills,
  Hermes, and OpenClaw builds can be verified from the monorepo.
- Removed the legacy `ui/` directory.

### API

- Entity resolution now exposes the owning project on resolved entities so
  callers can route follow-up reads to the correct workspace/project.

### CLI

- Added an "auto BM" GitHub CI workflow that captures notes from CI runs.
- Exposed project sync-support metadata and surfaced copyable workspace
  identifiers in project listings.
- `cloud login` now surfaces non-subscription errors instead of masking them.
- Team workspaces block `rclone sync`, with the team-workspace guard limited
  to `bisync`.

### Claude Code

- Rebuilt the Claude Code plugin as a memory bridge with SessionStart and
  PreCompact hooks, a bundled output style, and seeded note schemas.
- Added the `/basic-memory:setup` bootstrap interview and the
  `/basic-memory:remember`, `/basic-memory:status`, and `/basic-memory:share`
  skills.
- Added team workspace support with attribution for shared writes.
- Prefixed plugin skills with `bm-` and installed the shared `memory-*` skills
  instead of duplicating them in the plugin.
- Hooks fall back to `uvx`/`uv` when no CLI binary is on PATH.

### Codex

- Added the Codex plugin under `plugins/codex/` with its native
  `.codex-plugin`, hooks, seeded schemas, and `bm-*` skills.

### Skills

- Added the shared Basic Memory `SKILL.md` collection under top-level
  `skills/` and ported useful retired plugin skills into the `memory-*` set.
- Fixed invalid picoschema enum YAML in the memory skills.

### Hermes

- Added the Hermes memory provider plugin under `integrations/hermes/` with
  its native Python module, `plugin.yaml`, skill, tests, docs, and release
  metadata.

### OpenClaw

- Added the OpenClaw plugin under `integrations/openclaw/` with its native
  npm/TypeScript package shape, tests, docs, and release metadata; skill
  bundling copies from the top-level `skills/` source.

## v0.21.5 (2026-05-26)

Workspace/project routing fixes for MCP, plus a SQLite vector reindex stability fix.

### Bug Fixes

- **#854**: MCP project listing now keeps duplicate cloud project rows distinct by
  workspace, so only the selected workspace row inherits local project state.
- **#853**: `write_note` returns workspace-qualified permalinks for cloud
  workspace writes, allowing follow-up `memory://` reads to route back to the
  correct workspace/project.
- **#852**: Full SQLite vector reindex now loads `sqlite-vec` before dropping
  `vec0` virtual tables, preventing reindex crashes.
- **#838**: Local ASGI database initialization is preloaded so MCP routing can
  safely enter local project contexts.

## v0.21.1 (2026-05-16)

CI-only release. No user-facing changes.

### Maintenance

- **#833**: Replace `mislav/bump-homebrew-formula-action` with an inline
  bash bump step. The action's `resolveRedirect` HEAD-requests
  `api.github.com /repos/.../tarball/<ref>` expecting HTTP 302; GitHub now
  returns 303 for authenticated requests on that endpoint, which broke
  the v0.21.0 Homebrew job and required a manual tap bump. The inline
  step does the same work (curl + sha256sum, clone tap, sed-bump
  `url`/`sha256`, commit, push) without any third-party dependency.

## v0.21.0 (2026-05-16)

Workspace-aware everywhere: every MCP tool and CLI command now routes through the
same workspace/project model, the search and sync paths are noticeably faster,
and a handful of long-standing parsing and routing footguns are gone.

### Breaking Changes

- Relation parsing no longer treats unquoted multi-word text before a wikilink as a
  custom relation type. Use single-token relation types like `relates_to [[Target]]`,
  or quote multi-word relation types like `"relates to" [[Target]]` or
  `'relates to' [[Target]]`.
  - Bare list wikilinks like `- [[Target]]` now index as `links_to`.
  - Prose list items like `- some other thing [[Target]]` now index as `links_to`.
  - To preserve existing multi-word relation types on re-sync, quote them before upgrading.
  - See **#824**.

### Features

- **#816**: `bm orphan` CLI command surfaces entities whose underlying markdown
  files are gone, with a flag to clean them out.
- **#789**: Create projects directly by cloud workspace slug from MCP
  (`create_memory_project(workspace=...)`).
- **#757**: Discover projects across every accessible cloud workspace in MCP's
  project list — no more per-workspace blind spots.
- **#766**: MCP tools accept training-data-friendly parameter aliases
  (`q`/`search`/`text` for `query`, etc.) so models reach for them naturally.
- **#776**: `bm db reset` refuses to run while a `basic-memory mcp` process is
  alive, so resets can no longer corrupt an open session.
- **#791**: Search responses include result totals so pagers can stop guessing.
- **#719**: Cloud `note_content` tenant schema primitive lands on the backend.
- **#715**: `bm project add` accepts a `--visibility` flag for cloud projects.

### Bug Fixes

#### Search and recent activity
- **#832**: SQLite project deletion now sweeps `search_index`,
  `search_vector_chunks`, and `search_vector_embeddings`, so a project that
  reuses a recycled auto-increment id can't inherit the previous tenant's content.
- **#812**: `recent_activity` orders and filters by `updated_at`, so edits bubble
  to the top instead of staying pinned to creation time.
- **#807**: Multi-project `search_notes` is opt-in (`search_all_projects=True`);
  default search stays scoped to the resolved project.
- **#785**: `recent_activity` caps responses and emits an explicit truncation
  footer instead of silently dropping rows.
- **#713**: Eliminated an N+1 query in search result hydration.

#### Workspace / project routing
- **#822**: `bm project list` now includes projects from every workspace, not
  just the current one.
- **#813**, **#808**, **#806**, **#803**, **#801**, **#795**, **#790**, **#778**,
  **#777**, **#722**, **#712**, **#704**: Workspace-qualified permalink routing
  is centralized and applied consistently across `edit_note`, `delete_project`,
  `build_context`, `memory://` URLs, factory-mode project listing, cloud uploads,
  and the API client.

#### Sync
- **#827**: `rclone bisync` filters from `.bmignore` are preserved across syncs.
- **#815**: Watch service ignores hidden paths relative to the watched project,
  not just relative to `$HOME`.
- **#814**: `scan` subprocesses no longer go through the shell, avoiding quoting
  issues with paths that contain special characters.
- **#759**: Watch service stays inside `--project` scope.
- **#746**: Canonical markdown is preserved during single-file sync.

#### Parsing
- **#796**: Picoschema modifier descriptions (`field?(modifier, description)`)
  parse correctly.
- **#769**: Obsidian callout blocks are skipped by the observation parser
  instead of being mis-extracted as observations.

#### CLI
- **#775**: `bm project set-cloud` / `set-local` cleans up local DB state for
  the affected project.
- **#773**: `bm cloud logout` clears `default_workspace`.
- **#780**: `bm cloud setup` hint points at `bm cloud sync-setup`.
- **#734**: `bm project info` shows cloud index freshness.
- **#718**: Private cloud projects display under their `display_name` instead of
  raw UUID.
- **#768**: `read_note` / `view_note` drop no-op pagination params from their
  signatures.

#### Stability
- **#774**: `sqlite-vec` failures during init degrade gracefully to keyword-only
  search instead of crashing startup.
- **#733**: Delete-vector and cloud-sync cleanup is now consistent.
- **#702**: Race conditions in concurrent `delete_entity` are resolved.
- **#724**: `external_id` is preserved when entities are re-upserted during a
  re-index.
- **#728**: Vector init no longer issues runtime `ALTER TABLE`.
- **#744**: `BASIC_MEMORY_CONFIG_DIR` is honored across remaining call sites.
- **#743**: FastEmbed cache lives under the data dir instead of `/tmp`.
- **#752**: Cloud projects report `source=cloud` in factory mode.
- Stripped null bytes from markdown content before DB insert.
- Allowed long `relation_type` values in API responses.

#### Installer
- **#772**: Docker-compose config volume mounts under the `appuser` home.
- **#695**: Bumped `brew outdated` timeout from 15s to 60s.

### Performance

- **#828**: CLI startup no longer pulls in the local ASGI FastAPI app when it
  isn't needed.
- **#751**, **#726**, **#717**, **#714**, single-file/batch indexing: marked
  speedups on the sync hot path; unchanged markdown is skipped entirely.
- **#731**, **#723**: Vector sync is faster on both backends, with tuned
  fastembed defaults.

### Maintenance

- **#825**: Dependency refresh + security hardening.
- Updated to `fastmcp` 3.3.1.
- **#754**: Removed in-house telemetry wrappers in favor of direct `logfire`
  usage.
- **#736**: `ty` is now the default typechecker.
- **#771**, **#770**, **#716**: New regression guards for vector-row cleanup,
  long relation types, and recent activity hydration.

## v0.20.3 (2026-03-26)

### Bug Fixes

- **#698**: CLI cloud commands now use API key when configured
  - `get_authenticated_headers()` only checked OAuth tokens, ignoring `config.cloud_api_key`
  - All CLI cloud commands (`upload`, `status`, `snapshot`, `restore`, etc.) failed for API-key-only users while MCP tools worked fine
  - Now mirrors the same credential priority as MCP: API key first, OAuth fallback
  - Fixes `bm cloud upload --project` returning "project does not exist" when authenticated with `bmc_*` API key

## v0.20.2 (2026-03-10)

### Bug Fixes

- Fix auto-update Homebrew detection: `brew outdated` exits 1 when a formula is outdated, not on error
  - Previously treated exit code 1 as a failure, causing "Automatic update check failed" instead of detecting the available update

## v0.20.1 (2026-03-10)

### Bug Fixes

- **#661**: Fix `bm project list` MCP column to show transport type (stdio/https) instead of DB presence
  - Renamed "MCP (stdio)" column to "MCP"
  - Shows actual routing mode: `stdio` for local, `https` for cloud projects
  - Clears local path display for cloud-mode projects
- **#662**: Invalidate config cache when file is modified by another process
  - Adds mtime-based cache validation to `ConfigManager.load_config()`
  - Long-lived processes (MCP stdio server) now detect external config changes
  - Fixes `bm project set-cloud` having no effect on running MCP server

## v0.20.0 (2026-03-10)

### Features

- **#643**: Default-on auto-update system and `bm update` command
  - Automatic background update checks for CLI installs (uv tool, Homebrew)
  - Install-source detection (homebrew, uv_tool, uvx, unknown) with uvx skip behavior
  - Periodic check gating via `auto_update_last_checked_at` + `update_check_interval` config
  - Manager-specific update flows: Homebrew (`brew upgrade`) and uv tool (`uv tool upgrade`)
  - Silent, non-blocking MCP behavior via daemon thread before server run
  - Manual commands: `bm update` (force check + apply) and `bm update --check` (check only)
  - New config fields: `auto_update`, `update_check_interval`, `auto_update_last_checked_at`

## v0.19.2 (2026-03-09)

### Bug Fixes

- **#657**: Coerce string params to list/dict in MCP tools
  - MCP clients that serialize `list`/`dict` arguments as JSON strings no longer fail Pydantic validation
  - Adds `BeforeValidator` coercion to `search_notes` (`entity_types`, `note_types`, `tags`, `metadata_filters`), `write_note` (`metadata`), and `canvas` (`nodes`, `edges`)
- **#655**: Handle SQLite and Windows semantic search regressions
  - Fix embedding status query for non-semantic SQLite databases
  - Windows-safe log file rotation with per-process log filenames
  - Robust `setup_logging` that handles all environments cleanly

## v0.19.1 (2026-03-08)

### Bug Fixes

- **#649**: Enforce strict entity resolution in destructive MCP tools (`edit_note`, `move_note`, `delete_note`)
  - Prevents fuzzy-match fallback from silently editing/moving/deleting the wrong note
  - DST-related timeframe validation fix (round instead of truncate days)

### Features

- **#648**: Add `insert_before_section` and `insert_after_section` edit operations
- Add `GET /knowledge/graph` endpoint for full graph visualization

### Dependencies

- Bump authlib from 1.6.6 to 1.6.7

## v0.19.0 (2026-03-07)

### Highlights

- **Semantic vector search** for SQLite and Postgres with FastEmbed embeddings
- **Schema system** for validating and inferring knowledge base structure
- **Per-project cloud routing** with API key authentication
- **Upgraded to FastMCP 3.0** with tool annotations
- **CLI overhaul** with JSON output, workspace awareness, and project dashboard

### Features

- **#550**: Add semantic vector search for SQLite and Postgres
  - FastEmbed-based embeddings with automatic backfill
  - Hybrid search combining full-text and vector similarity
  - Score-based fusion replacing RRF for better ranking
  - `min_similarity` override for tuning search precision
  - Semantic dependencies are now default, with optional extras fallback

- **#549**: Schema system for Basic Memory
  - `schema_infer` — infer schema from existing notes
  - `schema_validate` — validate notes against a schema definition
  - `schema_diff` — compare schemas across projects
  - Frontmatter validation support (#597)
  - Read schema definitions from file instead of stale DB metadata (#635)

- **#555**: Per-project local/cloud routing with API key auth
  - Individual projects route through cloud while others stay local
  - `basic-memory cloud set-key` and `basic-memory project set-cloud/set-local`
  - Stdio MCP honors per-project cloud routing (#590)

- **#598**: Upgrade FastMCP 2.12.3 to 3.0.1 with tool annotations

- **#585**: Add JSON output mode for MCP tools (default text)
  - `--json` output for CLI commands for scripting and CI

- **#576**: Add workspace selection flow for MCP and CLI
  - Workspace-aware cloud project listing
  - CLI refactoring for workspace support

- **#544**: Project-prefixed permalinks and memory URL routing

- **#632**: Add overwrite guard to `write_note` tool

- **#614**: `edit_note` append/prepend auto-creates note if not found

- **#609**: Richer content context in search results
  - Return matched chunk text in search results (#601)
  - Improved content hit rate

- **#602**: Add `created_by` and `last_updated_by` user tracking to Entity

- **#600**: Rename `entity_type` to `note_type` across codebase

- **#574**: Add `display_name` and `is_private` to ProjectItem

- **#569**: Expose `external_id` in EntityResponse and link resolver

- **#567**: Isolate default SQLite DB by config dir

- **#560**: Enable `default_project_mode` by default

- **#559**: Add `basic-memory watch` CLI command

- **#546**: Add cloud discovery touchpoints to CLI and MCP

- **#572**: CLI analytics via Umami event collector

- Replace project info with htop-inspired dashboard

- Merge `search_by_metadata` into `search_notes` with optional query

- Add `--strip-frontmatter` to `basic-memory tool read-note`

- Add `destination_folder` parameter to `move_note` tool

### Bug Fixes

- **#644**: Fix default project resolution in cloud mode
  - ChatGPT search/fetch tools broken in cloud mode
  - `resolve_project_parameter` falls back to projects API

- **#638**: Restore API backward compatibility for v0.18.x clients

- **#637**: Create backup before config migration overwrites old format

- **#636**: `list_workspaces` bypasses factory pattern on cloud MCP server

- **#631**: `build_context` related_results schema validation failure

- **#613**: Reduce excessive log volume by demoting per-request noise to DEBUG

- **#612**: Handle quoted picoschema enum strings in YAML frontmatter

- **#607**: Guard against closed streams in promo and missing vector tables

- **#606**: Accept null for `expected_replacements` in `edit_note`

- **#595**: `recent_activity` dedup and pagination across MCP tools

- **#593**: Backend-specific distance-to-similarity conversion

- **#582**: Use LinkResolver fallback in `build_context` for flexible identifier matching

- **#577**: Replace RRF with score-based fusion in hybrid search

- **#575**: Remove hardcoded "main" default from `default_project`

- **#534**: Speed up `bm --version` startup

- Fix semantic embeddings not generated on fresh DB or upgrade

- Clarify `search_notes` parameter naming and fix `note_types` case sensitivity

- Parse `tag:` prefix at MCP tool level to avoid hybrid search failure

- Cap sqlite-vec knn k parameter at 4096 limit

- Parameterize SQL queries in search repository type filters

- Coerce list frontmatter values to strings for title and type fields

- Avoid `Post(**metadata)` crash when frontmatter contains 'content' or 'handler' keys

- Upgrade cryptography and python-multipart for security advisories

### Internal

- **#594**: Add `ty` as supplemental type checker
- Batched vector sync orchestration across repositories
- FastEmbed parallel guardrails and provider caching
- Improved cloud CLI status and error messages
- CI coverage and Postgres test fixes

## v0.18.5 (2026-02-13)

### Bug Fixes

- Strip NUL bytes from content before PostgreSQL search indexing
  ([`ec9b2c4`](https://github.com/basicmachines-co/basic-memory/commit/ec9b2c4))

## v0.18.4 (2026-02-12)

### Bug Fixes

- Use global `--header` flag for Tigris consistency on all rclone transactions
  ([`0eae0e1`](https://github.com/basicmachines-co/basic-memory/commit/0eae0e1))
  - `--header-download` / `--header-upload` only apply to GET/PUT requests, missing S3
    ListObjectsV2 calls that bisync issues first. Non-US users saw stale edge-cached metadata.
  - `--header` applies to ALL HTTP transactions (list, download, upload), fixing bisync for
    users outside the Tigris origin region.

## v0.18.2 (2026-02-11)

### Bug Fixes

- **#562**: Use VIRTUAL instead of STORED columns in SQLite migration
  ([`344e651`](https://github.com/basicmachines-co/basic-memory/commit/344e651))
  - Fixes compatibility issue with SQLite STORED generated columns

## v0.18.1 (2026-02-11)

### Features

- **#552**: Add `--format json` to CLI tool commands
  ([`a47c9c0`](https://github.com/basicmachines-co/basic-memory/commit/a47c9c0))
  - CLI tool commands now support `--format json` for machine-readable output

- **#535**: Support `tag:` query shorthand in search
  ([`f1d50c2`](https://github.com/basicmachines-co/basic-memory/commit/f1d50c2))
  - Use `tag:mytag` as a convenient shorthand in search queries

- **#532**: Fast edit entities, refactors for webui, enhanced search
  ([`530cbac`](https://github.com/basicmachines-co/basic-memory/commit/530cbac))
  - Performance improvements for entity editing and search operations

### Bug Fixes

- **#558**: Add X-Tigris-Consistent headers to all rclone commands
  ([`8489a3d`](https://github.com/basicmachines-co/basic-memory/commit/8489a3d))
  - Ensures consistent reads from Tigris object storage during sync

- **#541**: Handle EntityCreationError as conflict
  ([`343a6e1`](https://github.com/basicmachines-co/basic-memory/commit/343a6e1))

- **#536**: Stabilize metadata filters on Postgres
  ([`009e849`](https://github.com/basicmachines-co/basic-memory/commit/009e849))

- **#533**: Fix recent_activity prompt defaults
  ([`24ca5f6`](https://github.com/basicmachines-co/basic-memory/commit/24ca5f6))

- **#530**: Prevent spurious `metadata: {}` in frontmatter output
  ([`e3ced49`](https://github.com/basicmachines-co/basic-memory/commit/e3ced49))

- Add POST legacy compat routes for v0.18.0 CLI
  ([`c46d7a6`](https://github.com/basicmachines-co/basic-memory/commit/c46d7a6))

- Restore legacy `/projects/projects` endpoint for older CLI versions
  ([`a0e754b`](https://github.com/basicmachines-co/basic-memory/commit/a0e754b))

### Internal

- **#538**: Add fast feedback loop tooling (`just fast-check`, `just doctor`, `just testmon`)
  ([`8072449`](https://github.com/basicmachines-co/basic-memory/commit/8072449))

## v0.18.0 (2026-01-28)

### Features

- **#527**: Add context-aware wiki link resolution with source_path support
  ([`0023e73`](https://github.com/basicmachines-co/basic-memory/commit/0023e73))
  - Add `source_path` parameter to `resolve_link()` for context-aware resolution
  - Relative path resolution: `[[nested/note]]` from `folder/file.md` → `folder/nested/note.md`
  - Proximity-based resolution for duplicate titles (prefers notes in same folder)
  - Strict mode to disable fuzzy search fallback for wiki links

- **#518**: Add directory support to move_note and delete_note tools
  ([`0b20801`](https://github.com/basicmachines-co/basic-memory/commit/0b20801))
  - Add `is_directory` parameter to `move_note` and `delete_note` MCP tools
  - New `POST /move-directory` and delete directory API endpoints
  - Rename `folder` → `directory` parameter across codebase for consistency

- **#522**: Local MCP cloud mode routing
  ([`8730067`](https://github.com/basicmachines-co/basic-memory/commit/8730067))
  - Add `--local` and `--cloud` CLI routing flags
  - Local MCP server (`basic-memory mcp`) automatically uses local routing
  - Enables simultaneous use of local Claude Desktop and cloud-based clients
  - Environment variable `BASIC_MEMORY_FORCE_LOCAL=true` for global override

### Bug Fixes

- **#524**: Fix MCP prompt rendering errors
  ([`e14ba92`](https://github.com/basicmachines-co/basic-memory/commit/e14ba92))
  - Fix "Error rendering prompt recent_activity" error
  - Change `TimeFrame` to `str` in prompt type annotations for FastMCP compatibility

## v0.17.9 (2026-01-24)

### Bug Fixes

- **#523**: Fix `remove_project()` checking stale config in cloud mode
  ([`17c0e0a`](https://github.com/basicmachines-co/basic-memory/commit/17c0e0a))
  - In cloud mode, only check database `is_default` field (source of truth)
  - Config file can become stale when users set default project via v2 API

## v0.17.8 (2026-01-24)

### Bug Fixes

- **#521**: Fix `get_default_project()` returning multiple results
  ([`6888eff`](https://github.com/basicmachines-co/basic-memory/commit/6888eff))
  - Query incorrectly matched any project with non-NULL `is_default` (both True and False)
  - Now correctly checks for `is_default=True` only

## v0.17.7 (2026-01-24)

### Features

- **#476**: Add SPEC-29 Phase 3 bucket snapshot CLI commands
  ([`369ad37`](https://github.com/basicmachines-co/basic-memory/commit/369ad37))
  - New `basic-memory cloud snapshot` commands for managing cloud snapshots
  - Commands: `create`, `list`, `delete`, `show`, `browse`

- **#515**: Add MCP registry publication files
  ([`7a502e6`](https://github.com/basicmachines-co/basic-memory/commit/7a502e6))

### Bug Fixes

- **#520**: Read default project from database in cloud mode
  ([`38616c3`](https://github.com/basicmachines-co/basic-memory/commit/38616c3))

- **#513**: Ensure external_id is set on entity creation
  ([`c7835a9`](https://github.com/basicmachines-co/basic-memory/commit/c7835a9))

### Internal

- **#514**: Remove OpenPanel telemetry
  ([`85835ae`](https://github.com/basicmachines-co/basic-memory/commit/85835ae))

- Update README links to point to basicmemory.com
  ([`2aaee73`](https://github.com/basicmachines-co/basic-memory/commit/2aaee73))

## v0.17.6 (2026-01-17)

### Bug Fixes

- **#510**: Fix Docker container Python symlink broken at runtime
  ([`1799c94`](https://github.com/basicmachines-co/basic-memory/commit/1799c94))

### Internal

- Remove logfire config and specs docs, reduce lifespan and sync logging to debug level
  ([`d1d433d`](https://github.com/basicmachines-co/basic-memory/commit/d1d433d),
  [`803f3ef`](https://github.com/basicmachines-co/basic-memory/commit/803f3ef))

## v0.17.5 (2026-01-11)

### Bug Fixes

- **#505**: Prevent CLI commands from hanging on exit (Python 3.14 compatibility)
  ([`863e0a4`](https://github.com/basicmachines-co/basic-memory/commit/863e0a4))
  - Skip `nest_asyncio` on Python 3.14+ where it causes event loop issues
  - Simplify CLI test infrastructure for cross-version compatibility
  - Update pyright to 1.1.408 for Python 3.14 support
  - Fix SQLAlchemy rowcount typing for Python 3.14

## v0.17.4 (2026-01-05)

### Bug Fixes

- **#503**: Preserve search index across server restarts
  ([`26f7e98`](https://github.com/basicmachines-co/basic-memory/commit/26f7e98))
  - Fixes critical bug where search index was wiped on every MCP server restart
  - Bug was introduced in v0.16.3, affecting v0.16.3-v0.17.3
  - **User action**: Run `basic-memory reset` once after updating to rebuild search index

### Internal

- **#502**: Major architecture refactor with composition roots and typed API clients
  ([`5947f04`](https://github.com/basicmachines-co/basic-memory/commit/5947f04))
  - Add composition roots for API, MCP, and CLI entrypoints
  - Split deps.py into feature-scoped modules (config, db, projects, repositories, services, importers)
  - Add ProjectResolver for unified project selection
  - Add SyncCoordinator for centralized sync/watch lifecycle
  - Introduce typed API clients for MCP tools (KnowledgeClient, SearchClient, MemoryClient, etc.)

## v0.17.3 (2026-01-03)

### Features

- **#485**: Add stable external_id (UUID) to Project and Entity models
  ([`a4000f6`](https://github.com/basicmachines-co/basic-memory/commit/a4000f6))
  - Projects and entities now have immutable UUID identifiers
  - API v2 endpoints use external_id for stable references
  - Directory responses include external_id for entities

### Bug Fixes

- **#501**: Update mcp dependency to support protocol version 2025-11-25
  ([`c6baf58`](https://github.com/basicmachines-co/basic-memory/commit/c6baf58))
  - Fixes "Unsupported protocol version" error when using Claude Code
  - Bump mcp from >=1.2.0 to >=1.23.1

- **#499**: Fix route ordering for cloud deployments
  ([`53c4c20`](https://github.com/basicmachines-co/basic-memory/commit/53c4c20))

- **#486**: Skip config file update for set_default_project in cloud mode
  ([`fd732aa`](https://github.com/basicmachines-co/basic-memory/commit/fd732aa))

- **#484**: Make RelationResponse.from_id optional to handle null permalinks
  ([`537e58a`](https://github.com/basicmachines-co/basic-memory/commit/537e58a))

- Use upsert to prevent IntegrityError during parallel search indexing
  ([`4ce2198`](https://github.com/basicmachines-co/basic-memory/commit/4ce2198))

- Use relative file paths in importers for cloud storage compatibility
  ([`8adf1f4`](https://github.com/basicmachines-co/basic-memory/commit/8adf1f4))

### Internal

- Refactor importers to use FileService for cloud compatibility
  ([`45ce181`](https://github.com/basicmachines-co/basic-memory/commit/45ce181))

- Strengthen integration test coverage, remove stdlib mocks
  ([`b4486d2`](https://github.com/basicmachines-co/basic-memory/commit/b4486d2))

## v0.17.2 (2025-12-29)

### Bug Fixes

- Allow recent_activity discovery mode in cloud mode
  ([`0bcda4a`](https://github.com/basicmachines-co/basic-memory/commit/0bcda4a))
  - Add `allow_discovery` parameter to `resolve_project_parameter()`
  - Tools like `recent_activity` can now work across all projects in cloud mode
  - Fix circular import in project_context module

### Internal

- Optimize release workflow by running lint/typecheck only (skip full tests)
  ([`0b5425f`](https://github.com/basicmachines-co/basic-memory/commit/0b5425f))

## v0.17.1 (2025-12-29)

### Bug Fixes

- **#482**: Only set BASIC_MEMORY_ENV=test during pytest runs
  ([`98fbd60`](https://github.com/basicmachines-co/basic-memory/commit/98fbd60))
  - Fixes environment variable pollution affecting alembic migrations
  - Test environment detection now scoped to pytest execution only

## v0.17.0 (2025-12-28)

### Features

- **#478**: Add anonymous usage telemetry with Homebrew-style opt-out
  ([`856737f`](https://github.com/basicmachines-co/basic-memory/commit/856737f))
  - Privacy-respecting anonymous usage analytics
  - Easy opt-out via `BASIC_MEMORY_NO_ANALYTICS=1` environment variable
  - Helps improve Basic Memory based on real usage patterns

- **#474**: Add auto-format files on save with built-in Python formatter
  ([`1fd680c`](https://github.com/basicmachines-co/basic-memory/commit/1fd680c))
  - Automatic markdown formatting on file save
  - Built-in Python formatter for consistent code style
  - Configurable formatting options

- **#447**: Complete Phase 2 of API v2 migration - MCP tools use v2 endpoints
  ([`1a74d85`](https://github.com/basicmachines-co/basic-memory/commit/1a74d85))
  - All MCP tools now use optimized v2 API endpoints
  - Improved performance for knowledge graph operations
  - Foundation for future API enhancements

### Bug Fixes

- Fix UTF-8 BOM handling in frontmatter parsing
  ([`85684f8`](https://github.com/basicmachines-co/basic-memory/commit/85684f8))
  - Handles files with UTF-8 byte order marks correctly
  - Prevents frontmatter parsing failures

- **#475**: Handle null titles in ChatGPT import
  ([`14ce5a3`](https://github.com/basicmachines-co/basic-memory/commit/14ce5a3))
  - Gracefully handles conversations without titles
  - Improved import robustness

- Remove MaxLen constraint from observation content
  ([`45d6caf`](https://github.com/basicmachines-co/basic-memory/commit/45d6caf))
  - Allows longer observation content without truncation
  - Removes arbitrary 2000 character limit

- Handle FileNotFoundError gracefully during sync
  ([`1652f86`](https://github.com/basicmachines-co/basic-memory/commit/1652f86))
  - Prevents sync failures when files are deleted during sync
  - More resilient file watching

- Use canonical project names in API response messages
  ([`c23927d`](https://github.com/basicmachines-co/basic-memory/commit/c23927d))
  - Consistent project name formatting in all responses

- Suppress CLI warnings for cleaner output
  ([`d71c6e8`](https://github.com/basicmachines-co/basic-memory/commit/d71c6e8))
  - Cleaner terminal output without spurious warnings

- Prevent DEBUG logs from appearing on CLI stdout
  ([`63b9849`](https://github.com/basicmachines-co/basic-memory/commit/63b9849))
  - Debug logging no longer pollutes CLI output

- **#473**: Detect rclone version for --create-empty-src-dirs support
  ([`622d37e`](https://github.com/basicmachines-co/basic-memory/commit/622d37e))
  - Automatic rclone version detection for compatibility
  - Prevents errors on older rclone versions

- **#471**: Prevent CLI commands from hanging on exit
  ([`916baf8`](https://github.com/basicmachines-co/basic-memory/commit/916baf8))
  - Fixes CLI hang on shutdown
  - Proper async cleanup

- Add cloud_mode check to initialize_app()
  ([`ef7adb7`](https://github.com/basicmachines-co/basic-memory/commit/ef7adb7))
  - Correct initialization for cloud deployments

### Internal

- Centralize test environment detection in config.is_test_env
  ([`3cd9178`](https://github.com/basicmachines-co/basic-memory/commit/3cd9178))
  - Unified test environment detection
  - Disables analytics in test environments

- Make test-int-postgres compatible with macOS
  ([`95937c6`](https://github.com/basicmachines-co/basic-memory/commit/95937c6))
  - Cross-platform PostgreSQL testing support

## v0.16.3 (2025-12-20)

### Features

- **#439**: Add PostgreSQL database backend support
  ([`fb5e9e1`](https://github.com/basicmachines-co/basic-memory/commit/fb5e9e1))
  - Full PostgreSQL/Neon database support as alternative to SQLite
  - Async connection pooling with asyncpg
  - Alembic migrations support for both backends
  - Configurable via `BASIC_MEMORY_DATABASE_BACKEND` environment variable

- **#441**: Implement API v2 with ID-based endpoints (Phase 1)
  ([`28cc522`](https://github.com/basicmachines-co/basic-memory/commit/28cc522))
  - New ID-based API endpoints for improved performance
  - Foundation for future API enhancements
  - Backward compatible with existing endpoints

- Add project_id to Relation and Observation for efficient project-scoped queries
  ([`a920a9f`](https://github.com/basicmachines-co/basic-memory/commit/a920a9f))
  - Enables faster queries in multi-project environments
  - Improved database schema for cloud deployments

- Add bulk insert with ON CONFLICT handling for relations
  ([`0818bda`](https://github.com/basicmachines-co/basic-memory/commit/0818bda))
  - Faster relation creation during sync operations
  - Handles duplicate relations gracefully

### Performance

- Lightweight permalink resolution to avoid eager loading
  ([`6f99d2e`](https://github.com/basicmachines-co/basic-memory/commit/6f99d2e))
  - Reduces database queries during entity lookups
  - Improved response times for read operations

### Bug Fixes

- **#464**: Pin FastMCP to 2.12.3 to fix MCP tools visibility
  ([`f227ef6`](https://github.com/basicmachines-co/basic-memory/commit/f227ef6))
  - Fixes issue where MCP tools were not visible to Claude
  - Reverts to last known working FastMCP version

- **#458**: Reduce watch service CPU usage by increasing reload interval
  ([`897b1ed`](https://github.com/basicmachines-co/basic-memory/commit/897b1ed))
  - Lowers CPU usage during file watching
  - More efficient resource utilization

- **#456**: Await background sync task cancellation in lifespan shutdown
  ([`efbc758`](https://github.com/basicmachines-co/basic-memory/commit/efbc758))
  - Prevents hanging on shutdown
  - Clean async task cleanup

- **#434**: Respect --project flag in background sync
  ([`70bb10b`](https://github.com/basicmachines-co/basic-memory/commit/70bb10b))
  - Background sync now correctly uses specified project
  - Fixes multi-project sync issues

- **#446**: Fix observation parsing and permalink limits
  ([`73d940e`](https://github.com/basicmachines-co/basic-memory/commit/73d940e))
  - Handles edge cases in observation content
  - Prevents permalink truncation issues

- **#424**: Handle periods in kebab_filenames mode
  ([`b004565`](https://github.com/basicmachines-co/basic-memory/commit/b004565))
  - Fixes filename handling for files with multiple periods
  - Improved kebab-case conversion

- Fix Postgres/Neon connection settings and search index dedupe
  ([`b5d4fb5`](https://github.com/basicmachines-co/basic-memory/commit/b5d4fb5))
  - Optimized connection pooling for Postgres
  - Prevents duplicate search index entries

### Testing & CI

- Replace py-pglite with testcontainers for Postgres testing
  ([`c462faf`](https://github.com/basicmachines-co/basic-memory/commit/c462faf))
  - More reliable Postgres testing infrastructure
  - Uses Docker-based test containers

- Add PostgreSQL testing to GitHub Actions workflow
  ([`66b91b2`](https://github.com/basicmachines-co/basic-memory/commit/66b91b2))
  - CI now tests both SQLite and PostgreSQL backends
  - Ensures cross-database compatibility

- **#416**: Add integration test for read_note with underscored folders
  ([`0c12a39`](https://github.com/basicmachines-co/basic-memory/commit/0c12a39))
  - Verifies folder name handling edge cases

### Internal

- Cloud compatibility fixes and performance improvements (#454)
- Remove logfire instrumentation for cleaner production deployments
- Truncate content_stems to fix Postgres 8KB index row limit

## v0.16.2 (2025-11-16)

### Bug Fixes

- **#429**: Use platform-native path separators in config.json
  ([`6517e98`](https://github.com/basicmachines-co/basic-memory/commit/6517e98))
  - Fixes config.json path separator issues on Windows
  - Uses os.path.join for platform-native path construction
  - Ensures consistent path handling across platforms

- **#427**: Add rclone installation checks for Windows bisync commands
  ([`1af0539`](https://github.com/basicmachines-co/basic-memory/commit/1af0539))
  - Validates rclone installation before running bisync commands
  - Provides clear error messages when rclone is not installed
  - Improves user experience on Windows

- **#421**: Main project always recreated on project list command
  ([`cad7019`](https://github.com/basicmachines-co/basic-memory/commit/cad7019))
  - Fixes issue where main project was recreated unnecessarily
  - Improves project list command reliability
  - Reduces unnecessary file system operations

## v0.16.1 (2025-11-11)

### Bug Fixes

- **#422**: Handle Windows line endings in rclone bisync
  ([`e9d0a94`](https://github.com/basicmachines-co/basic-memory/commit/e9d0a94))
  - Added `--compare=modtime` flag to rclone bisync to ignore size differences from line ending conversions
  - Fixes issue where LF→CRLF conversion on Windows was treated as file corruption
  - Resolves "corrupted on transfer: sizes differ" errors during cloud sync on Windows
  - Users will need to run `--resync` once after updating to establish new baseline

## v0.16.0 (2025-11-10)

### Features

- **#417**: Add run_in_background parameter to sync endpoint
  ([`7ccec7e`](https://github.com/basicmachines-co/basic-memory/commit/7ccec7e))
  - New `run_in_background` parameter for async sync operations
  - Improved API flexibility for long-running sync tasks
  - Comprehensive test coverage for background sync behavior

- **#405**: SPEC-20 Simplified Project-Scoped Rclone Sync
  ([`0b3272a`](https://github.com/basicmachines-co/basic-memory/commit/0b3272a))
  - Simplified and more reliable cloud synchronization
  - Project-scoped rclone configuration
  - Better error handling and status reporting

- **#384**: Streaming Foundation & Async I/O Consolidation (SPEC-19)
  ([`e78345f`](https://github.com/basicmachines-co/basic-memory/commit/e78345f))
  - Foundation for streaming support in future releases
  - Consolidated async I/O patterns across codebase
  - Improved performance and resource management

- **#364**: Add circuit breaker for file sync failures
  ([`434cdf2`](https://github.com/basicmachines-co/basic-memory/commit/434cdf2))
  - Prevents cascading failures during sync operations
  - Automatic recovery from transient errors
  - Better resilience in cloud sync scenarios

- **#362**: Add --verbose and --no-gitignore options to cloud upload
  ([`7f9c1a9`](https://github.com/basicmachines-co/basic-memory/commit/7f9c1a9))
  - Enhanced upload control with verbose logging
  - Option to bypass gitignore filtering when needed
  - Better debugging and troubleshooting capabilities

- **#391**: Add delete_notes parameter to remove project endpoint
  ([`c9946ec`](https://github.com/basicmachines-co/basic-memory/commit/c9946ec))
  - Option to delete notes when removing projects
  - Safer project cleanup workflows
  - Prevents accidental data loss

### Bug Fixes

- **#420**: Skip archive files during cloud upload
  ([`49b2adc`](https://github.com/basicmachines-co/basic-memory/commit/49b2adc))
  - Prevents uploading of zip, tar, gz and other archive files
  - Reduces storage usage and upload time
  - Better file filtering during cloud operations

- **#419**: Rename write_note entity_type to note_type for clarity
  ([`1646572`](https://github.com/basicmachines-co/basic-memory/commit/1646572))
  - Clearer parameter naming in write_note tool
  - Improved API consistency and documentation
  - Better developer experience

- **#418**: Quote string values in YAML frontmatter to handle special characters
  ([`f0d7398`](https://github.com/basicmachines-co/basic-memory/commit/f0d7398))
  - Fixes YAML parsing errors with special characters
  - More robust frontmatter handling
  - Prevents data corruption in edge cases

- **#415**: Handle dict objects in write_resource endpoint
  ([`4614fd0`](https://github.com/basicmachines-co/basic-memory/commit/4614fd0))
  - Fixes errors when writing dictionary resources
  - Better type handling in resource endpoints
  - Improved API robustness

- **#414**: Replace Unicode arrows with ASCII for Windows compatibility
  ([`fc01f6a`](https://github.com/basicmachines-co/basic-memory/commit/fc01f6a))
  - Fixes display issues on Windows terminals
  - Better cross-platform compatibility
  - Improved CLI user experience on Windows

- **#411**: Windows CLI Unicode encoding errors
  ([`0ba6f21`](https://github.com/basicmachines-co/basic-memory/commit/0ba6f21))
  - Resolves Unicode encoding issues on Windows
  - Better handling of international characters
  - Improved Windows platform support

- **#410**: Various rclone fixes for cloud sync on Windows
  ([`c9946ec`](https://github.com/basicmachines-co/basic-memory/commit/c9946ec))
  - Fixes cloud sync reliability on Windows
  - Better path handling for Windows filesystem
  - Improved rclone integration on Windows

- **#402**: Normalize YAML frontmatter types to prevent AttributeError
  ([`a7d7cc5`](https://github.com/basicmachines-co/basic-memory/commit/a7d7cc5))
  - Fixes AttributeError when reading frontmatter
  - More robust type normalization
  - Better error handling in markdown parsing

- **#396**: Strip duplicate headers in edit_note replace_section
  ([`021af74`](https://github.com/basicmachines-co/basic-memory/commit/021af74))
  - Prevents duplicate headers when replacing sections
  - Cleaner note editing behavior
  - Better content consistency

- **#395**: Simplify search_notes schema by removing Optional wrappers
  ([`d775f7b`](https://github.com/basicmachines-co/basic-memory/commit/d775f7b))
  - Cleaner API schema definition
  - Better type safety and validation
  - Improved developer experience

- **#394**: Add explicit type annotations to MCP tool parameters
  ([`581b7b1`](https://github.com/basicmachines-co/basic-memory/commit/581b7b1))
  - Better type safety in MCP tools
  - Improved IDE support and autocomplete
  - Clearer tool documentation

- **#389**: Handle null, empty, and string 'None' title in markdown frontmatter
  ([`bb8da31`](https://github.com/basicmachines-co/basic-memory/commit/bb8da31))
  - Fixes errors with malformed frontmatter titles
  - More robust title handling
  - Better error recovery

- **#380**: Optimize sync memory usage to prevent OOM on large projects
  ([`4fd6d0c`](https://github.com/basicmachines-co/basic-memory/commit/4fd6d0c))
  - Prevents out-of-memory errors on large knowledge bases
  - Better memory management during sync
  - Improved scalability

- **#379**: Handle YAML parsing errors gracefully in update_frontmatter
  ([`32236cd`](https://github.com/basicmachines-co/basic-memory/commit/32236cd))
  - Better error handling for malformed YAML
  - Graceful degradation instead of crashes
  - Improved robustness

- **#377**: Preserve mtime on WebDAV upload
  ([`e6c8e36`](https://github.com/basicmachines-co/basic-memory/commit/e6c8e36))
  - Maintains file modification times during upload
  - Better sync accuracy
  - Prevents unnecessary re-syncing

- **#370**: Prevent deleted projects from being recreated by background sync
  ([`449b62d`](https://github.com/basicmachines-co/basic-memory/commit/449b62d))
  - Fixes race condition with project deletion
  - Better lifecycle management
  - Prevents unwanted project recreation

- **#369**: Use filesystem timestamps for entity sync instead of database operation time
  ([`b7497d7`](https://github.com/basicmachines-co/basic-memory/commit/b7497d7))
  - More accurate sync detection
  - Better handling of external file modifications
  - Improved sync reliability

- **#368**: Handle YAML parsing errors and missing entity_type in markdown files
  ([`d1431bd`](https://github.com/basicmachines-co/basic-memory/commit/d1431bd))
  - Better error handling for malformed markdown
  - Graceful handling of missing metadata
  - Improved robustness

- **#367**: Resolve UNIQUE constraint violation in entity upsert with observations
  ([`171bef7`](https://github.com/basicmachines-co/basic-memory/commit/171bef7))
  - Fixes database constraint errors during sync
  - Better handling of duplicate observations
  - Improved data integrity

- **#366**: Terminate sync immediately when project is deleted
  ([`729a5a3`](https://github.com/basicmachines-co/basic-memory/commit/729a5a3))
  - Faster project deletion
  - Better resource cleanup
  - Improved user experience

- **#357**: Make project creation endpoint idempotent
  ([`53fb13b`](https://github.com/basicmachines-co/basic-memory/commit/53fb13b))
  - Prevents errors when creating existing projects
  - Better API reliability
  - Improved cloud integration

- **#353**: Handle None text values in Claude conversations importer
  ([`bd6c834`](https://github.com/basicmachines-co/basic-memory/commit/bd6c834))
  - Fixes import errors with empty messages
  - Better error handling in importers
  - Improved data migration

### Performance Improvements

- Force full database sync after project sync/bisync operations
  ([`2ad0ee9`](https://github.com/basicmachines-co/basic-memory/commit/2ad0ee9))
  - Ensures database consistency after cloud operations
  - Better sync reliability
  - Improved data integrity

### Documentation

- Add free trial information to README
  ([`a7d7cc5`](https://github.com/basicmachines-co/basic-memory/commit/a7d7cc5), [`8aaddb6`](https://github.com/basicmachines-co/basic-memory/commit/8aaddb6))
  - Updated README with Basic Memory Cloud trial info
  - Better onboarding experience
  - Clearer pricing information

- Announce Basic Memory Cloud launch in README
  ([`d756531`](https://github.com/basicmachines-co/basic-memory/commit/d756531))
  - Official cloud service announcement
  - Updated documentation for cloud features
  - Improved product positioning

### Migration Guide

No manual migration required. Upgrade with:

```bash
# Update via uv
uv tool upgrade basic-memory

# Or install fresh
uv tool install basic-memory
```

**What's New in v0.16.0:**
- Streaming foundation and consolidated async I/O (SPEC-19)
- Simplified project-scoped rclone sync (SPEC-20)
- Circuit breaker for sync failure resilience
- Enhanced Windows platform support
- Improved cloud upload with verbose and gitignore options
- Better error handling across YAML parsing and frontmatter
- Memory optimization for large projects
- Archive file filtering during upload

**Breaking Changes:**
- `write_note` parameter renamed: `entity_type` → `note_type` for clarity

### Installation

```bash
# Latest stable release
uv tool install basic-memory

# Update existing installation
uv tool upgrade basic-memory

# Docker
docker pull ghcr.io/basicmachines-co/basic-memory:v0.16.0
```

## v0.15.2 (2025-10-14)

### Features

- **#356**: Add WebDAV upload command for cloud projects
  ([`5258f45`](https://github.com/basicmachines-co/basic-memory/commit/5258f457))
  - New `bm cloud upload` command for uploading local files/directories to cloud projects
  - WebDAV-based file transfer with automatic directory creation
  - Support for `.gitignore` and `.bmignore` pattern filtering
  - Automatic project creation with `--create-project` flag
  - Optional post-upload sync with `--sync` flag (enabled by default)
  - Human-readable file size reporting (bytes, KB, MB)
  - Comprehensive test coverage (28 unit tests)

### Migration Guide

No manual migration required. Upgrade with:

```bash
# Update via uv
uv tool upgrade basic-memory

# Or install fresh
uv tool install basic-memory
```

**What's New:**
- Upload local files to cloud projects with `bm cloud upload`
- Streamlined cloud project creation and management
- Better file filtering with gitignore integration

### Installation

```bash
# Latest stable release
uv tool install basic-memory

# Update existing installation
uv tool upgrade basic-memory

# Docker
docker pull ghcr.io/basicmachines-co/basic-memory:v0.15.2
```

## v0.15.1 (2025-10-13)

### Performance Improvements

- **#352**: Optimize sync/indexing for 43% faster performance
  ([`c0538ad`](https://github.com/basicmachines-co/basic-memory/commit/c0538ad2perf0d68a2a3604e255c3f2c42c5ed))
  - Significant performance improvements to file synchronization and indexing operations
  - 43% reduction in sync time for large knowledge bases
  - Optimized database queries and file processing

- **#350**: Optimize directory operations for 10-100x performance improvement
  ([`00b73b0`](https://github.com/basicmachines-co/basic-memory/commit/00b73b0d))
  - Dramatic performance improvements for directory listing operations
  - 10-100x faster directory traversal depending on knowledge base size
  - Reduced memory footprint for large directory structures
  - Exclude null fields from directory endpoint responses for smaller payloads

### Bug Fixes

- **#355**: Update view_note and ChatGPT tools for Claude Desktop compatibility
  ([`2b7008d`](https://github.com/basicmachines-co/basic-memory/commit/2b7008d9))
  - Fix view_note tool formatting for better Claude Desktop rendering
  - Update ChatGPT tool integration for improved compatibility
  - Enhanced artifact display in Claude Desktop interface

- **#348**: Add permalink normalization to project lookups in deps.py
  ([`a09066e`](https://github.com/basicmachines-co/basic-memory/commit/a09066e0))
  - Fix project lookup failures due to case sensitivity
  - Normalize permalinks consistently across project operations
  - Improve project switching reliability

- **#345**: Project deletion failing with permalink normalization
  ([`be352ab`](https://github.com/basicmachines-co/basic-memory/commit/be352ab4))
  - Fix project deletion errors related to permalink handling
  - Ensure proper cleanup of project resources
  - Improve error messages for deletion failures

- **#341**: Correct ProjectItem.home property to return path instead of name
  ([`3e876a7`](https://github.com/basicmachines-co/basic-memory/commit/3e876a75))
  - Fix ProjectItem.home to return correct project path
  - Resolve configuration issues with project paths
  - Improve project path resolution consistency

- **#339**: Prevent nested project paths to avoid data conflicts
  ([`795e339`](https://github.com/basicmachines-co/basic-memory/commit/795e3393))
  - Block creation of nested project paths that could cause data conflicts
  - Add validation to prevent project path hierarchy issues
  - Improve error messages for invalid project configurations

- **#338**: Normalize paths to lowercase in cloud mode to prevent case collisions
  ([`07e304c`](https://github.com/basicmachines-co/basic-memory/commit/07e304ce))
  - Fix path case sensitivity issues in cloud deployments
  - Normalize paths consistently across cloud operations
  - Prevent data loss from case-insensitive filesystem collisions

- **#336**: Cloud mode path validation and sanitization (bmc-issue-103)
  ([`2a1c06d`](https://github.com/basicmachines-co/basic-memory/commit/2a1c06d9))
  - Enhanced path validation for cloud deployments
  - Improved path sanitization to prevent security issues
  - Better error handling for invalid paths in cloud mode

- **#332**: Cloud mode path validation and sanitization
  ([`7616b2b`](https://github.com/basicmachines-co/basic-memory/commit/7616b2bb))
  - Additional cloud mode path fixes and improvements
  - Comprehensive path validation for cloud environments
  - Security enhancements for path handling

### Features

- **#344**: Async client context manager pattern for cloud consolidation (SPEC-16)
  ([`8d2e70c`](https://github.com/basicmachines-co/basic-memory/commit/8d2e70cf))
  - Refactor async client to use context manager pattern
  - Improve resource management and cleanup
  - Enable better dependency injection for cloud deployments
  - Foundation for cloud platform consolidation

- **#343**: Add SPEC-15 for configuration persistence via Tigris
  ([`53438d1`](https://github.com/basicmachines-co/basic-memory/commit/53438d1e))
  - Design specification for persistent configuration storage
  - Foundation for cloud configuration management
  - Tigris S3-compatible storage integration planning

- **#334**: Introduce BASIC_MEMORY_PROJECT_ROOT for path constraints
  ([`ccc4386`](https://github.com/basicmachines-co/basic-memory/commit/ccc43866))
  - Add environment variable for constraining project paths
  - Improve security by limiting project creation locations
  - Better control over project directory structure

### Documentation

- **#335**: v0.15.0 assistant guide updates
  ([`c6f93a0`](https://github.com/basicmachines-co/basic-memory/commit/c6f93a02))
  - Update AI assistant guide for v0.15.0 features
  - Improve documentation for new MCP tools
  - Better examples and usage patterns

- **#339**: Add tool use documentation to write_note for root folder usage
  ([`73202d1`](https://github.com/basicmachines-co/basic-memory/commit/73202d1a))
  - Document how to use empty string for root folder in write_note
  - Clarify folder parameter usage
  - Improve tool documentation clarity

- Fix link in ai_assistant_guide resource
  ([`2a1c06d`](https://github.com/basicmachines-co/basic-memory/commit/2a1c06d9))
  - Correct broken documentation links
  - Improve resource accessibility

### Refactoring

- Add SPEC-17 and SPEC-18 documentation
  ([`962d88e`](https://github.com/basicmachines-co/basic-memory/commit/962d88ea))
  - New specification documents for future features
  - Architecture planning and design documentation

### Breaking Changes

**None** - This release maintains full backward compatibility with v0.15.0

### Migration Guide

No manual migration required. Upgrade with:

```bash
# Update via uv
uv tool upgrade basic-memory

# Or install fresh
uv tool install basic-memory
```

**What's Fixed:**
- Significant performance improvements (43% faster sync, 10-100x faster directory operations)
- Multiple cloud deployment stability fixes
- Project path validation and normalization issues resolved
- Better Claude Desktop and ChatGPT integration

**What's New:**
- Context manager pattern for async clients (foundation for cloud consolidation)
- BASIC_MEMORY_PROJECT_ROOT environment variable for path constraints
- Enhanced cloud mode path handling and security
- SPEC-15 and SPEC-16 architecture documentation

### Installation

```bash
# Latest stable release
uv tool install basic-memory

# Update existing installation
uv tool upgrade basic-memory

# Docker
docker pull ghcr.io/basicmachines-co/basic-memory:v0.15.1
```

## v0.15.0 (2025-10-04)

### Critical Bug Fixes

- **Permalink Collision Data Loss Prevention** - Fixed critical bug where creating similar entity names would overwrite existing files
  ([`2a050ed`](https://github.com/basicmachines-co/basic-memory/commit/2a050edee42b07294f5199902a60b626bfc47be8))
  - **Issue**: Creating "Node C" would overwrite "Node A.md" due to fuzzy search incorrectly matching similar file paths
  - **Solution**: Added `strict=True` parameter to link resolution, disabling fuzzy search fallback during entity creation
  - **Impact**: Prevents data loss from false positive path matching like "edge-cases/Node A.md" vs "edge-cases/Node C.md"
  - **Testing**: Comprehensive integration tests and MCP-level permalink collision tests added
  - **Status**: Manually verified fix prevents file overwrite in production scenarios

### Bug Fixes

- **#330**: Remove .env file loading from BasicMemoryConfig
  ([`f3b1945`](https://github.com/basicmachines-co/basic-memory/commit/f3b1945e4c0070d0282eaf98c085ef188c8edd2d))
  - Clean up configuration initialization to prevent unintended environment variable loading

- **#329**: Normalize underscores in memory:// URLs for build_context
  ([`f5a11f3`](https://github.com/basicmachines-co/basic-memory/commit/f5a11f3911edda55bee6970ed9e7c38f7fd7a059))
  - Fix URL normalization to handle underscores consistently in memory:// protocol
  - Improve knowledge graph navigation with standardized URL handling

- **#328**: Simplify entity upsert to use database-level conflict resolution
  ([`ee83b0e`](https://github.com/basicmachines-co/basic-memory/commit/ee83b0e5a8f00cdcc8e24a0f8c9449c6eaddf649))
  - Leverage SQLite's native UPSERT for cleaner entity creation/update logic
  - Reduce application-level complexity by using database conflict resolution

- **#312**: Add proper datetime JSON schema format annotations for MCP validation
  ([`a7bf42e`](https://github.com/basicmachines-co/basic-memory/commit/a7bf42ef495a3e2c66230985c3445cab5c52c408))
  - Fix MCP schema validation errors with proper datetime format annotations
  - Ensure compatibility with strict MCP schema validators

- **#281**: Fix move_note without file extension
  ([`3e168b9`](https://github.com/basicmachines-co/basic-memory/commit/3e168b98f3962681799f4537eb86ded47e771665))
  - Allow moving notes by title alone without requiring .md extension
  - Improve move operation usability and error handling

- **#310**: Remove obsolete update_current_project function and --project flag reference
  ([`17a6733`](https://github.com/basicmachines-co/basic-memory/commit/17a6733c9d280def922e37c2cd171e3ee44fce21))
  - Clean up deprecated project management code
  - Remove unused CLI flag references

- **#309**: Make sync operations truly non-blocking with thread pool
  ([`1091e11`](https://github.com/basicmachines-co/basic-memory/commit/1091e113227c86f10f574e56a262aff72f728113))
  - Move sync operations to background thread pool for improved responsiveness
  - Prevent blocking during file synchronization operations

### Features

- **#327**: CLI Subscription Validation (SPEC-13 Phase 2)
  ([`ace6a0f`](https://github.com/basicmachines-co/basic-memory/commit/ace6a0f50d8d0b4ea31fb526361c2d9616271740))
  - Implement subscription validation for CLI operations
  - Foundation for future cloud billing integration

- **#322**: Cloud CLI sync via rclone bisync
  ([`99a35a7`](https://github.com/basicmachines-co/basic-memory/commit/99a35a7fb410ef88c50050e666e4244350e44a6e))
  - Add bidirectional cloud synchronization using rclone
  - Enable local-cloud file sync with conflict detection

- **#315**: Implement SPEC-11 API performance optimizations
  ([`5da97e4`](https://github.com/basicmachines-co/basic-memory/commit/5da97e482052907d68a2a3604e255c3f2c42c5ed))
  - Comprehensive API performance improvements
  - Optimized database queries and response times

- **#314**: Integrate ignore_utils to skip .gitignored files in sync process
  ([`33ee1e0`](https://github.com/basicmachines-co/basic-memory/commit/33ee1e0831d2060587de2c9886e74ff111b04583))
  - Respect .gitignore patterns during file synchronization
  - Prevent syncing build artifacts and temporary files

- **#313**: Add disable_permalinks config flag
  ([`9035913`](https://github.com/basicmachines-co/basic-memory/commit/903591384dffeba9996a18463818bdb8b28ca03e))
  - Optional permalink generation for users who don't need them
  - Improves flexibility for different knowledge management workflows

- **#306**: Implement cloud mount CLI commands for local file access
  ([`2c5c606`](https://github.com/basicmachines-co/basic-memory/commit/2c5c606a394ab994334c8fd307b30370037bbf39))
  - Mount cloud files locally using rclone for real-time editing
  - Three performance profiles: fast (5s), balanced (10-15s), safe (15s+)
  - Cross-platform rclone installer with package manager fallbacks

- **#305**: ChatGPT tools for search and fetch
  ([`f40ab31`](https://github.com/basicmachines-co/basic-memory/commit/f40ab31685a9510a07f5d87bf24436c0df80680f))
  - Add ChatGPT-specific search and fetch tools
  - Expand AI assistant integration options

- **#298**: Implement SPEC-6 Stateless Architecture for MCP Tools
  ([`a1d7792`](https://github.com/basicmachines-co/basic-memory/commit/a1d7792bdb6f71c4943b861d1c237f6ac7021247))
  - Redesign MCP tools for stateless operation
  - Enable cloud deployment with better scalability

- **#296**: Basic Memory cloud upload
  ([`e0d8aeb`](https://github.com/basicmachines-co/basic-memory/commit/e0d8aeb14913f3471b9716d0c60c61adb1d74687))
  - Implement file upload capabilities for cloud storage
  - Foundation for cloud-hosted Basic Memory instances

- **#291**: Merge Cloud auth
  ([`3a6baf8`](https://github.com/basicmachines-co/basic-memory/commit/3a6baf80fc6012e9434e06b1605f9a8b198d8688))
  - OAuth 2.1 authentication with Supabase integration
  - JWT-based tenant isolation for multi-user cloud deployments

### Platform & Infrastructure

- **#331**: Add Python 3.13 to test matrix
  ([`16d7edd`](https://github.com/basicmachines-co/basic-memory/commit/16d7eddbf704abfe53373663e80d05ecdde15aa7))
  - Ensure compatibility with latest Python version
  - Expand CI/CD testing coverage

- **#316**: Enable WAL mode and add Windows-specific SQLite optimizations
  ([`c83d567`](https://github.com/basicmachines-co/basic-memory/commit/c83d567917267bb3d52708f4b38d2daf36c1f135))
  - Enable Write-Ahead Logging for better concurrency
  - Platform-specific SQLite optimizations for Windows users

- **#320**: Rework lifecycle management to optimize cloud deployment
  ([`ea2e93d`](https://github.com/basicmachines-co/basic-memory/commit/ea2e93d9265bfa366d2d3796f99f579ab2aed48c))
  - Optimize application lifecycle for cloud environments
  - Improve startup time and resource management

- **#319**: Resolve entity relations in background to prevent cold start blocking
  ([`324844a`](https://github.com/basicmachines-co/basic-memory/commit/324844a670d874410c634db520a68c09149045ea))
  - Move relation resolution to background processing
  - Faster MCP server cold starts

- **#318**: Enforce minimum 1-day timeframe for recent_activity
  ([`f818702`](https://github.com/basicmachines-co/basic-memory/commit/f818702ab7f8d2d706178e7b0ed3467501c9c4a2))
  - Fix timezone-related issues in recent activity queries
  - Ensure consistent behavior across time zones

- **#317**: Critical cloud deployment fixes for MCP stability
  ([`2efd8f4`](https://github.com/basicmachines-co/basic-memory/commit/2efd8f44e2d0259079ed5105fea34308875c0e10))
  - Multiple stability improvements for cloud-hosted MCP servers
  - Enhanced error handling and recovery

### Technical Improvements

- **Comprehensive Testing** - Extensive test coverage for critical fixes
  - New permalink collision test suite with 4 MCP-level integration tests
  - Entity service test coverage expanded to reproduce fuzzy search bug
  - Manual testing verification of data loss prevention
  - All 55 entity service tests passing with new strict resolution

- **Windows Support Enhancements**
  ([`7a8b08d`](https://github.com/basicmachines-co/basic-memory/commit/7a8b08d11ee627b54af6f5ea7ab4ef9fcd8cf4ed),
   [`9aa4024`](https://github.com/basicmachines-co/basic-memory/commit/9aa40246a8ad1c3cef82b32e1ca7ce8ea23e1e05))
  - Fix Windows test failures and add Windows CI support
  - Address platform-specific issues for Windows users
  - Enhanced cross-platform compatibility

- **Docker Improvements**
  ([`105bcaa`](https://github.com/basicmachines-co/basic-memory/commit/105bcaa025576a06f889183baded6c18f3782696))
  - Implement non-root Docker container to fix file ownership issues
  - Improved security and compatibility in containerized deployments

- **Code Quality**
  - Enhanced filename sanitization with optional kebab case support
  - Improved character conflict detection for sync operations
  - Better error handling across the codebase
  - Path traversal security vulnerability fixes

### Documentation

- **#321**: Corrected dead links in README
  ([`fc38877`](https://github.com/basicmachines-co/basic-memory/commit/fc38877008cd8c762116f7ff4b2573495b4e5c0f))
  - Fix broken documentation links
  - Improve navigation and accessibility

- **#308**: Update Claude Code GitHub Workflow
  ([`8c7e29e`](https://github.com/basicmachines-co/basic-memory/commit/8c7e29e325f36a67bdefe8811637493bef4bbf56))
  - Enhanced GitHub integration documentation
  - Better Claude Code collaboration workflow

### Breaking Changes

**None** - This release maintains full backward compatibility with v0.14.x

All changes are either:
- Bug fixes that correct unintended behavior
- New optional features that don't affect existing functionality
- Internal optimizations that are transparent to users

### Migration Guide

No manual migration required. Upgrade with:

```bash
# Update via uv
uv tool upgrade basic-memory

# Or install fresh
uv tool install basic-memory
```

**What's Fixed:**
- Data loss bug from permalink collisions is completely resolved
- Cloud deployment stability significantly improved
- Windows platform compatibility enhanced
- Better performance across all operations

**What's New:**
- Cloud sync capabilities via rclone
- Subscription validation foundation
- Python 3.13 support
- Enhanced security and stability

### Installation

```bash
# Latest stable release
uv tool install basic-memory

# Update existing installation
uv tool upgrade basic-memory

# Docker
docker pull ghcr.io/basicmachines-co/basic-memory:v0.15.0
```

## v0.14.2 (2025-07-03)

### Bug Fixes

- **#204**: Fix MCP Error with MCP-Hub integration
  ([`3621bb7`](https://github.com/basicmachines-co/basic-memory/commit/3621bb7b4d6ac12d892b18e36bb8f7c9101c7b10))
  - Resolve compatibility issues with MCP-Hub
  - Improve error handling in project management tools
  - Ensure stable MCP tool integration across different environments

- **Modernize datetime handling and suppress SQLAlchemy warnings**
  ([`f80ac0e`](https://github.com/basicmachines-co/basic-memory/commit/f80ac0e3e74b7a737a7fc7b956b5c1d61b0c67b8))
  - Replace deprecated `datetime.utcnow()` with timezone-aware alternatives
  - Suppress SQLAlchemy deprecation warnings for cleaner output
  - Improve future compatibility with Python datetime best practices

## v0.14.1 (2025-07-03)

### Bug Fixes

- **#203**: Constrain fastmcp version to prevent breaking changes
  ([`827f7cf`](https://github.com/basicmachines-co/basic-memory/commit/827f7cf86e7b84c56e7a43bb83f2e5d84a1ad8b8))
  - Pin fastmcp to compatible version range to avoid API breaking changes
  - Ensure stable MCP server functionality across updates
  - Improve dependency management for production deployments

- **#190**: Fix Problems with MCP integration  
  ([`bd4f551`](https://github.com/basicmachines-co/basic-memory/commit/bd4f551a5bb0b7b4d3a5b04de70e08987c6ab2f9))
  - Resolve MCP server initialization and communication issues
  - Improve error handling and recovery in MCP operations
  - Enhance stability for AI assistant integrations

### Features

- **Add Cursor IDE integration button** - One-click setup for Cursor IDE users
  ([`5360005`](https://github.com/basicmachines-co/basic-memory/commit/536000512294d66090bf87abc8014f4dfc284310))
  - Direct installation button for Cursor IDE in README
  - Streamlined setup process for Cursor users
  - Enhanced developer experience for AI-powered coding

- **Add Homebrew installation instructions** - Official Homebrew tap support
  ([`39f811f`](https://github.com/basicmachines-co/basic-memory/commit/39f811f8b57dd998445ae43537cd492c680b2e11))
  - Official Homebrew formula in basicmachines-co/basic-memory tap
  - Simplified installation process for macOS users
  - Package manager integration for easier dependency management

## v0.14.0 (2025-06-26)

### Features

- **Docker Container Registry Migration** - Switch from Docker Hub to GitHub Container Registry for better security and integration  
  ([`616c1f0`](https://github.com/basicmachines-co/basic-memory/commit/616c1f0710da59c7098a5f4843d4f017877ff7b2))
  - Automated Docker image publishing via GitHub Actions CI/CD pipeline
  - Enhanced container security with GitHub's integrated vulnerability scanning
  - Streamlined container deployment workflow for production environments

- **Enhanced Search Documentation** - Comprehensive search syntax examples for improved user experience
  ([`a589f8b`](https://github.com/basicmachines-co/basic-memory/commit/a589f8b894e78cce01eb25656856cfea8785fbbf))
  - Detailed examples for Boolean search operators (AND, OR, NOT)
  - Advanced search patterns including phrase matching and field-specific queries
  - User-friendly documentation for complex search scenarios

- **Cross-Project File Management** - Intelligent move operations with project boundary detection
  ([`db5ef7d`](https://github.com/basicmachines-co/basic-memory/commit/db5ef7d35cc0894309c7a57b5741c9dd978526d4))
  - Automatic detection of cross-project move attempts with helpful guidance
  - Clear error messages when attempting unsupported cross-project operations

### Bug Fixes

- **#184**: Preserve permalinks when editing notes without frontmatter permalinks
  ([`c2f4b63`](https://github.com/basicmachines-co/basic-memory/commit/c2f4b632cf04921b1a3c2f0d43831b80c519cb31))
  - Fix permalink preservation during note editing operations
  - Ensure consistent permalink handling across different note formats
  - Maintain note identity and searchability during incremental edits

- **#183**: Implement project-specific sync status checks for MCP tools
  ([`12b5152`](https://github.com/basicmachines-co/basic-memory/commit/12b51522bc953fca117fc5bc01fcb29c6ca7e13c))
  - Fix sync status reporting to correctly reflect current project state
  - Resolve inconsistencies where sync status showed global instead of project-specific information
  - Improve project isolation for sync operations and status reporting

- **#180**: Handle Boolean search syntax with hyphenated terms
  ([`546e3cd`](https://github.com/basicmachines-co/basic-memory/commit/546e3cd8db98b74f746749d41887f8a213cd0b11))
  - Fix search parsing issues with hyphenated terms in Boolean queries
  - Improve search query tokenization for complex term structures
  - Enhanced search reliability for technical documentation and multi-word concepts

- **#174**: Respect BASIC_MEMORY_HOME environment variable in Docker containers
  ([`9f1db23`](https://github.com/basicmachines-co/basic-memory/commit/9f1db23c78d4648e2c242ad1ee27eed85e3f3b5d))
  - Fix Docker container configuration to properly honor custom home directory settings
  - Improve containerized deployment flexibility with environment variable support
  - Ensure consistent behavior between local and containerized installations

- **#168**: Scope entity queries by project_id in upsert_entity method
  ([`2a3adc1`](https://github.com/basicmachines-co/basic-memory/commit/2a3adc109a3e4d7ccd65cae4abf63d9bb2338326))
  - Fix entity isolation issues in multi-project setups
  - Prevent cross-project entity conflicts during database operations
  - Strengthen project boundary enforcement at the database level

- **#166**: Handle None from_entity in Context API RelationSummary
  ([`8a065c3`](https://github.com/basicmachines-co/basic-memory/commit/8a065c32f4e41613207d29aafc952a56e3a52241))
  - Fix null pointer exceptions in relation processing
  - Improve error handling for incomplete relation data
  - Enhanced stability for knowledge graph traversal operations

- **#164**: Remove log level configuration from mcp_server.run()
  ([`224e4bf`](https://github.com/basicmachines-co/basic-memory/commit/224e4bf9e4438c44a82ffc21bd1a282fe9087690))
  - Simplify MCP server startup by removing redundant log level settings
  - Fix potential logging configuration conflicts
  - Streamline server initialization process

- **#162**: Ensure permalinks are generated for entities with null permalinks during move operations
  ([`f506507`](https://github.com/basicmachines-co/basic-memory/commit/f50650763dbd4322c132e4bdc959ce4bf074374b))
  - Fix move operations for entities without existing permalinks
  - Automatic permalink generation during file move operations
  - Maintain database consistency during file reorganization

### Technical Improvements

- **Comprehensive Test Coverage** - Extensive test suites for new features and edge cases
  - Enhanced test coverage for project-specific sync status functionality
  - Additional test scenarios for search syntax validation and edge cases
  - Integration tests for Docker CI workflow and container publishing
  - Comprehensive move operations testing with project boundary validation

- **Docker CI/CD Pipeline** - Production-ready automated container publishing
  ([`74847cc`](https://github.com/basicmachines-co/basic-memory/commit/74847cc3807b0c6ed511e0d83e0d560e9f07ec44))
  - Automated Docker image building and publishing on release
  - Multi-architecture container support for AMD64 and ARM64 platforms
  - Integrated security scanning and vulnerability assessments
  - Streamlined deployment pipeline for production environments

- **Release Process Improvements** - Enhanced automation and quality gates
  ([`a52ce1c`](https://github.com/basicmachines-co/basic-memory/commit/a52ce1c8605ec2cd450d1f909154172cbc30faa2))
  - Homebrew formula updates limited to stable releases only
  - Improved release automation with better quality control
  - Enhanced CI/CD pipeline reliability and error handling

- **Code Quality Enhancements** - Improved error handling and validation
  - Better null safety in entity and relation processing
  - Enhanced project isolation validation throughout the codebase
  - Improved error messages and user guidance for edge cases
  - Strengthened database consistency guarantees across operations

### Infrastructure

- **GitHub Container Registry Integration** - Modern container infrastructure
  - Migration from Docker Hub to GitHub Container Registry (ghcr.io)
  - Improved security with integrated vulnerability scanning
  - Better integration with GitHub-based development workflow
  - Enhanced container versioning and artifact management

- **Enhanced CI/CD Workflows** - Robust automated testing and deployment
  - Automated Docker image publishing on releases
  - Comprehensive test coverage validation before deployment
  - Multi-platform container building and publishing
  - Integration with GitHub's security and monitoring tools

### Migration Guide

This release includes several behind-the-scenes improvements and fixes. All changes are backward compatible:

- **Docker Users**: Container images now served from `ghcr.io/basicmachines-co/basic-memory` instead of Docker Hub
- **Search Users**: Enhanced search syntax handling - existing queries continue to work unchanged
- **Multi-Project Users**: Improved project isolation - all existing projects remain fully functional
- **All Users**: Enhanced stability and error handling - no breaking changes to existing workflows

### Installation

```bash
# Latest stable release
uv tool install basic-memory

# Update existing installation  
uv tool upgrade basic-memory

# Docker (new registry)
docker pull ghcr.io/basicmachines-co/basic-memory:latest
```

## v0.13.7 (2025-06-19)

### Bug Fixes

- **Homebrew Integration** - Automatic Homebrew formula updates
- **Documentation** - Add git sign-off reminder to development guide

## v0.13.6 (2025-06-18)

### Bug Fixes

- **Custom Entity Types** - Support for custom entity types in write_note
  ([`7789864`](https://github.com/basicmachines-co/basic-memory/commit/77898644933589c2da9bdd60571d54137a5309ed))
  - Fixed `entity_type` parameter for `write_note` MCP tool to respect value passed in
  - Frontmatter `type` field automatically respected when no explicit parameter provided
  - Maintains backward compatibility with default "note" type

- **#139**: Fix "UNIQUE constraint failed: entity.permalink" database error
  ([`c6215fd`](https://github.com/basicmachines-co/basic-memory/commit/c6215fd819f9564ead91cf3a950f855241446096))
  - Implement SQLAlchemy UPSERT strategy to handle permalink conflicts gracefully
  - Eliminates crashes when creating notes with existing titles in same folders
  - Seamlessly updates existing entities instead of failing with constraint errors

- **Database Migration Performance** - Eliminate redundant migration initialization
  ([`84d2aaf`](https://github.com/basicmachines-co/basic-memory/commit/84d2aaf6414dd083af4b0df73f6c8139b63468f6))
  - Fix duplicate migration calls that slowed system startup
  - Improve performance with multiple projects (tested with 28+ projects)
  - Add migration deduplication safeguards with comprehensive test coverage

- **User Experience** - Correct spelling error in continue_conversation prompt
  ([`b4c26a6`](https://github.com/basicmachines-co/basic-memory/commit/b4c26a613379e6f2ba655efe3d7d8d40c27999e5))
  - Fix "Chose a folder" → "Choose a folder" in MCP prompt instructions
  - Improve grammar and clarity in user-facing prompt text

### Documentation

- **Website Updates** - Add new website and community links to README
  ([`3fdce68`](https://github.com/basicmachines-co/basic-memory/commit/3fdce683d7ad8b6f4855d7138d5ff2136d4c07bc))

- **Project Documentation** - Update README.md and CLAUDE.md with latest project information
  ([`782cb2d`](https://github.com/basicmachines-co/basic-memory/commit/782cb2df28803482d209135a054e67cc32d7363e))

### Technical Improvements

- **Comprehensive Test Coverage** - Add extensive test suites for new features
  - Custom entity type validation with 8 new test scenarios
  - UPSERT behavior testing with edge case coverage
  - Migration deduplication testing with 6 test scenarios
  - Database constraint handling validation

- **Code Quality** - Enhanced error handling and validation
  - Improved SQLAlchemy patterns with modern UPSERT operations
  - Better conflict resolution strategies for entity management
  - Strengthened database consistency guarantees

### Performance

- **Database Operations** - Faster startup and improved scalability
  - Reduced migration overhead for multi-project setups
  - Optimized conflict resolution for entity creation
  - Enhanced performance with growing knowledge bases

### Migration Guide

This release includes automatic database improvements. No manual migration required:

- Existing notes and entity types continue working unchanged
- New `entity_type` parameter is optional and backward compatible
- Database performance improvements apply automatically
- All existing MCP tool behavior preserved

### Installation

```bash
# Latest stable release
uv tool install basic-memory

# Update existing installation
uv tool upgrade basic-memory
```

## v0.13.5 (2025-06-11)

### Bug Fixes

- **MCP Tools**: Renamed `create_project` tool to `create_memory_project` for namespace isolation
- **Namespace**: Continued namespace isolation effort to prevent conflicts with other MCP servers

### Changes

- Tool functionality remains identical - only the name changed from `create_project` to `create_memory_project`
- All integration tests updated to use the new tool name
- Completes namespace isolation for project management tools alongside `list_memory_projects`

## v0.13.4 (2025-06-11)

### Bug Fixes

- **MCP Tools**: Renamed `list_projects` tool to `list_memory_projects` to avoid naming conflicts with other MCP servers
- **Namespace**: Improved tool naming specificity for better MCP server integration and isolation

### Changes

- Tool functionality remains identical - only the name changed from `list_projects` to `list_memory_projects`
- All integration tests updated to use the new tool name
- Better namespace isolation for Basic Memory MCP tools

## v0.13.3 (2025-06-11)

### Bug Fixes

- **Projects**: Fixed case-insensitive project switching where switching succeeded but subsequent operations failed due to session state inconsistency
- **Config**: Enhanced config manager with case-insensitive project lookup using permalink-based matching
- **MCP Tools**: Updated project management tools to store canonical project names from database instead of user input
- **API**: Improved project service to handle both name and permalink lookups consistently

### Technical Improvements

- Added comprehensive case-insensitive project switching test coverage with 5 new integration test scenarios
- Fixed permalink generation inconsistencies where different case inputs could generate different permalinks
- Enhanced project URL construction to use permalinks consistently across all API calls
- Improved error handling and session state management for project operations

### Changes

- Project switching now preserves canonical project names from database in session state
- All project operations use permalink-based lookups for case-insensitive matching
- Enhanced test coverage ensures reliable case-insensitive project operations

## v0.13.2 (2025-06-11)

### Features

- **Release Management**: Added automated release management system with version control in `__init__.py`
- **Automation**: Implemented justfile targets for `release` and `beta` commands with comprehensive quality gates
- **CI/CD**: Enhanced release process with automatic version updates, git tagging, and GitHub release creation

### Development Experience

- Added `.claude/commands/release/` directory with automation documentation
- Implemented release validation including lint, type-check, and test execution
- Streamlined release workflow from manual process to single-command automation

### Technical Improvements

- Updated package version management to use actual version numbers instead of dynamic versioning
- Added release process documentation and command references
- Enhanced justfile with comprehensive release automation targets

## v0.13.1 (2025-06-11)

### Bug Fixes

- **CLI**: Fixed  `basic-memory project` project management commands that were  not working in v0.13.0 (#129)
- **Projects**: Resolved case sensitivity issues when switching between projects that caused "Project not found" errors (#127)
- **API**: Standardized CLI project command endpoints and improved error handling
- **Core**: Implemented consistent project name handling using permalinks to avoid case-related conflicts

### Changes

- Renamed `basic-memory project sync` command to `basic-memory project sync-config` for clarity
- Improved project switching reliability across different case variations
- Removed redundant server status messages from CLI error outputs

## v0.13.0 (2025-06-11)

### Overview

Basic Memory v0.13.0 is a **major release** that transforms Basic Memory into a true multi-project knowledge management system. This release introduces fluid project switching, advanced note editing capabilities, robust file management, and production-ready OAuth authentication - all while maintaining full backward compatibility.

**What's New for Users:**
- 🎯 **Switch between projects instantly** during conversations with Claude
- ✏️ **Edit notes incrementally** without rewriting entire documents
- 📁 **Move and organize notes** with full database consistency
- 📖 **View notes as formatted artifacts** for better readability in Claude Desktop
- 🔍 **Search frontmatter tags** to discover content more easily
- 🔐 **OAuth authentication** for secure remote access
- ⚡ **Development builds** automatically published for beta testing

**Key v0.13.0 Accomplishments:**
- ✅ **Complete Project Management System** - Project switching and project-specific operations
- ✅ **Advanced Note Editing** - Incremental editing with append, prepend, find/replace, and section operations  
- ✅ **View Notes as Artifacts in Claude Desktop/Web** - Use the view_note tool to view a note as an artifact
- ✅ **File Management System** - Full move operations with database consistency and rollback protection
- ✅ **Enhanced Search Capabilities** - Frontmatter tags now searchable, improved content discoverability
- ✅ **Unified Database Architecture** - Single app-level database for better performance and project management

### Major Features

#### 1. Multiple Project Management 

**Switch between projects instantly during conversations:**

```
💬 "What projects do I have?"
🤖 Available projects:
   • main (current, default)
   • work-notes
   • personal-journal
   • code-snippets

💬 "Switch to work-notes"
🤖 ✓ Switched to work-notes project
   
   Project Summary:
   • 47 entities
   • 125 observations  
   • 23 relations

💬 "What did I work on yesterday?"
🤖 [Shows recent activity from work-notes project]
```

**Key Capabilities:**
- **Instant Project Switching**: Change project context mid-conversation without restart
- **Project-Specific Operations**: Operations work within the currently active project context
- **Project Discovery**: List all available projects with status indicators
- **Session Context**: Maintains active project throughout conversation
- **Backward Compatibility**: Existing single-project setups continue to work seamlessly

#### 2. Advanced Note Editing 

**Edit notes incrementally without rewriting entire documents:**

```python
# Append new sections to existing notes
edit_note("project-planning", "append", "\n## New Requirements\n- Feature X\n- Feature Y")

# Prepend timestamps to meeting notes
edit_note("meeting-notes", "prepend", "## 2025-05-27 Update\n- Progress update...")

# Replace specific sections under headers
edit_note("api-spec", "replace_section", "New implementation details", section="## Implementation")

# Find and replace with validation
edit_note("config", "find_replace", "v0.13.0", find_text="v0.12.0", expected_replacements=2)
```

**Key Capabilities:**
- **Append Operations**: Add content to end of notes (most common use case)
- **Prepend Operations**: Add content to beginning of notes
- **Section Replacement**: Replace content under specific markdown headers
- **Find & Replace**: Simple text replacements with occurrence counting
- **Smart Error Handling**: Helpful guidance when operations fail
- **Project Context**: Works within the active project with session awareness

#### 3. Smart File Management

**Move and organize notes:**

```python
# Simple moves with automatic folder creation
move_note("my-note", "work/projects/my-note.md")

# Organize within the active project
move_note("shared-doc", "archive/old-docs/shared-doc.md")

# Rename operations
move_note("old-name", "same-folder/new-name.md")
```

**Key Capabilities:**
- **Database Consistency**: Updates file paths, permalinks, and checksums automatically
- **Search Reindexing**: Maintains search functionality after moves
- **Folder Creation**: Automatically creates destination directories
- **Project Isolation**: Operates within the currently active project
- **Link Preservation**: Maintains internal links and references

#### 4. Enhanced Search & Discovery 

**Find content more easily with improved search capabilities:**

- **Frontmatter Tag Search**: Tags from YAML frontmatter are now indexed and searchable
- **Improved Content Discovery**: Search across titles, content, tags, and metadata
- **Project-Scoped Search**: Search within the currently active project
- **Better Search Quality**: Enhanced FTS5 indexing with tag content inclusion

**Example:**
```yaml
---
title: Coffee Brewing Methods
tags: [coffee, brewing, equipment]
---
```
Now searchable by: "coffee", "brewing", "equipment", or "Coffee Brewing Methods"

#### 5. Unified Database Architecture 

**Single app-level database for better performance and project management:**

- **Migration from Per-Project DBs**: Moved from multiple SQLite files to single app database
- **Project Isolation**: Proper data separation with project_id foreign keys
- **Better Performance**: Optimized queries and reduced file I/O

### Complete MCP Tool Suite

#### New Project Management Tools
- **`list_projects()`** - Discover and list all available projects with status
- **`switch_project(project_name)`** - Change active project context during conversations
- **`get_current_project()`** - Show currently active project with statistics
- **`set_default_project(project_name)`** - Update default project configuration
- **`sync_status()`** - Check file synchronization status and background operations

#### New Note Operations Tools
- **`edit_note()`** - Incremental note editing (append, prepend, find/replace, section replace)
- **`move_note()`** - Move notes with database consistency and search reindexing
- **`view_note()`** - Display notes as formatted artifacts for better readability in Claude Desktop

#### Enhanced Existing Tools
All existing tools now support:
- **Session context awareness** (operates within the currently active project)
- **Enhanced error messages** with project context metadata
- **Improved response formatting** with project information footers
- **Project isolation** ensures operations stay within the correct project boundaries


### User Experience Improvements

#### Installation Options

**Multiple ways to install and test Basic Memory:**

```bash
# Stable release
uv tool install basic-memory

# Beta/pre-releases
uv tool install basic-memory --pre
```


#### Bug Fixes & Quality Improvements

**Major issues resolved in v0.13.0:**

- **#118**: Fixed YAML tag formatting to follow standard specification
- **#110**: Fixed `--project` flag consistency across all CLI commands
- **#107**: Fixed write_note update failures with existing notes
- **#93**: Fixed custom permalink handling in frontmatter
- **#52**: Enhanced search capabilities with frontmatter tag indexing
- **FTS5 Search**: Fixed special character handling in search queries
- **Error Handling**: Improved error messages and validation across all tools

### Breaking Changes & Migration

#### For Existing Users

**Automatic Migration**: First run will automatically migrate existing data to the new unified database structure. No manual action required.

**What Changes:**
- Database location: Moved to `~/.basic-memory/memory.db` (unified across projects)
- Configuration: Projects defined in `~/.basic-memory/config.json` are synced with database

**What Stays the Same:**
- All existing notes and data remain unchanged
- Default project behavior maintained for single-project users
- All existing MCP tools continue to work without modification

### Documentation & Resources

#### New Documentation
- [Project Management Guide](docs/Project%20Management.md) - Multi-project workflows
- [Note Editing Guide](docs/Note%20Editing.md) - Advanced editing techniques

#### Updated Documentation
- [README.md](README.md) - Installation options and beta build instructions
- [CONTRIBUTING.md](CONTRIBUTING.md) - Release process and version management
- [CLAUDE.md](CLAUDE.md) - Development workflow and CI/CD documentation
- [Claude.ai Integration](docs/Claude.ai%20Integration.md) - Updated MCP tool examples

#### Quick Start Examples

**Project Switching:**
```
💬 "Switch to my work project and show recent activity"
🤖 [Calls switch_project("work") then recent_activity()]
```

**Note Editing:**
```
💬 "Add a section about deployment to my API docs"
🤖 [Calls edit_note("api-docs", "append", "## Deployment\n...")]
```

**File Organization:**
```
💬 "Move my old meeting notes to the archive folder"
🤖 [Calls move_note("meeting-notes", "archive/old-meetings.md")]
```



## v0.12.3 (2025-04-17)

### Bug Fixes

- Add extra logic for permalink generation with mixed Latin unicode and Chinese characters
  ([`73ea91f`](https://github.com/basicmachines-co/basic-memory/commit/73ea91fe0d1f7ab89b99a1b691d59fe608b7fcbb))

Signed-off-by: phernandez <paul@basicmachines.co>

- Modify recent_activity args to be strings instead of enums
  ([`3c1cc34`](https://github.com/basicmachines-co/basic-memory/commit/3c1cc346df519e703fae6412d43a92c7232c6226))

Signed-off-by: phernandez <paul@basicmachines.co>


## v0.12.2 (2025-04-08)

### Bug Fixes

- Utf8 for all file reads/write/open instead of default platform encoding
  ([#91](https://github.com/basicmachines-co/basic-memory/pull/91),
  [`2934176`](https://github.com/basicmachines-co/basic-memory/commit/29341763318408ea8f1e954a41046c4185f836c6))

Signed-off-by: phernandez <paul@basicmachines.co>


## v0.12.1 (2025-04-07)

### Bug Fixes

- Run migrations and sync when starting mcp
  ([#88](https://github.com/basicmachines-co/basic-memory/pull/88),
  [`78a3412`](https://github.com/basicmachines-co/basic-memory/commit/78a3412bcff83b46e78e26f8b9fce42ed9e05991))


## v0.12.0 (2025-04-06)

### Bug Fixes

- [bug] `#` character accumulation in markdown frontmatter tags prop
  ([#79](https://github.com/basicmachines-co/basic-memory/pull/79),
  [`6c19c9e`](https://github.com/basicmachines-co/basic-memory/commit/6c19c9edf5131054ba201a109b37f15c83ef150c))

- [bug] Cursor has errors calling search tool
  ([#78](https://github.com/basicmachines-co/basic-memory/pull/78),
  [`9d581ce`](https://github.com/basicmachines-co/basic-memory/commit/9d581cee133f9dde4a0a85118868227390c84161))

- [bug] Some notes never exit "modified" status
  ([#77](https://github.com/basicmachines-co/basic-memory/pull/77),
  [`7930ddb`](https://github.com/basicmachines-co/basic-memory/commit/7930ddb2919057be30ceac8c4c19da6aaa1d3e92))

- [bug] write_note Tool Fails to Update Existing Files in Some Situations.
  ([#80](https://github.com/basicmachines-co/basic-memory/pull/80),
  [`9bff1f7`](https://github.com/basicmachines-co/basic-memory/commit/9bff1f732e71bc60f88b5c2ce3db5a2aa60b8e28))

- Set default mcp log level to ERROR
  ([#81](https://github.com/basicmachines-co/basic-memory/pull/81),
  [`248214c`](https://github.com/basicmachines-co/basic-memory/commit/248214cb114a269ca60ff6398e382f9e2495ad8e))

- Write_note preserves frontmatter fields in content
  ([#84](https://github.com/basicmachines-co/basic-memory/pull/84),
  [`3f4d9e4`](https://github.com/basicmachines-co/basic-memory/commit/3f4d9e4d872ebc0ed719c61b24d803c14a9db5e6))

### Documentation

- Add VS Code instructions to README
  ([#76](https://github.com/basicmachines-co/basic-memory/pull/76),
  [`43cbb7b`](https://github.com/basicmachines-co/basic-memory/commit/43cbb7b38cc0482ac0a41b6759320e3588186e43))

- Updated basicmachines.co links to be https
  ([#69](https://github.com/basicmachines-co/basic-memory/pull/69),
  [`40ea28b`](https://github.com/basicmachines-co/basic-memory/commit/40ea28b0bfc60012924a69ecb76511daa4c7d133))

### Features

- Add watch to mcp process ([#83](https://github.com/basicmachines-co/basic-memory/pull/83),
  [`00c8633`](https://github.com/basicmachines-co/basic-memory/commit/00c8633cfcee75ff640ff8fe81dafeb956281a94))

- Permalink enhancements ([#82](https://github.com/basicmachines-co/basic-memory/pull/82),
  [`617e60b`](https://github.com/basicmachines-co/basic-memory/commit/617e60bda4a590678a5f551f10a73e7b47e3b13e))

- Avoiding "useless permalink values" for files without metadata - Enable permalinks to be updated
  on move via config setting


## v0.11.0 (2025-03-29)

### Bug Fixes

- Just delete db for reset db instead of using migrations.
  ([#65](https://github.com/basicmachines-co/basic-memory/pull/65),
  [`0743ade`](https://github.com/basicmachines-co/basic-memory/commit/0743ade5fc07440f95ecfd816ba7e4cfd74bca12))

Signed-off-by: phernandez <paul@basicmachines.co>

- Make logs for each process - mcp, sync, cli
  ([#64](https://github.com/basicmachines-co/basic-memory/pull/64),
  [`f1c9570`](https://github.com/basicmachines-co/basic-memory/commit/f1c95709cbffb1b88292547b0b8f29fcca22d186))

Signed-off-by: phernandez <paul@basicmachines.co>

### Documentation

- Update broken "Multiple Projects" link in README.md
  ([#55](https://github.com/basicmachines-co/basic-memory/pull/55),
  [`3c68b7d`](https://github.com/basicmachines-co/basic-memory/commit/3c68b7d5dd689322205c67637dca7d188111ee6b))

### Features

- Add bm command alias for basic-memory
  ([#67](https://github.com/basicmachines-co/basic-memory/pull/67),
  [`069c0a2`](https://github.com/basicmachines-co/basic-memory/commit/069c0a21c630784e1bf47d2b7de5d6d1f6fadd7a))

Signed-off-by: phernandez <paul@basicmachines.co>

- Rename search tool to search_notes
  ([#66](https://github.com/basicmachines-co/basic-memory/pull/66),
  [`b278276`](https://github.com/basicmachines-co/basic-memory/commit/b27827671dc010be3e261b8b221aca6b7f836661))

Signed-off-by: phernandez <paul@basicmachines.co>


## v0.10.1 (2025-03-25)

### Bug Fixes

- Make set_default_project also activate project for current session to fix #37
  ([`cbe72be`](https://github.com/basicmachines-co/basic-memory/commit/cbe72be10a646c0b03931bb39aff9285feae47f9))

This change makes the 'basic-memory project default <name>' command both: 1. Set the default project
  for future invocations (persistent change) 2. Activate the project for the current session
  (immediate change)

Added tests to verify this behavior, which resolves issue #37 where the project name and path
  weren't changing properly when the default project was changed.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

- Make set_default_project also activate project for current session to fix #37
  ([`46c4fd2`](https://github.com/basicmachines-co/basic-memory/commit/46c4fd21645b109af59eb2a0201c7bd849b34a49))

This change makes the 'basic-memory project default <name>' command both: 1. Set the default project
  for future invocations (persistent change) 2. Activate the project for the current session
  (immediate change)

Added tests to verify this behavior, which resolves issue #37 where the project name and path
  weren't changing properly when the default project was changed.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

Signed-off-by: phernandez <paul@basicmachines.co>

- Move ai_assistant_guide.md into package resources to fix #39
  ([`390ff9d`](https://github.com/basicmachines-co/basic-memory/commit/390ff9d31ccee85bef732e8140b5eeecd7ee176f))

This change relocates the AI assistant guide from the static directory into the package resources
  directory, ensuring it gets properly included in the distribution package and is accessible when
  installed via pip/uv.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

- Move ai_assistant_guide.md into package resources to fix #39
  ([`cc2cae7`](https://github.com/basicmachines-co/basic-memory/commit/cc2cae72c14b380f78ffeb67c2261e4dbee45faf))

This change relocates the AI assistant guide from the static directory into the package resources
  directory, ensuring it gets properly included in the distribution package and is accessible when
  installed via pip/uv.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

Signed-off-by: phernandez <paul@basicmachines.co>

- Preserve custom frontmatter fields when updating notes
  ([`78f234b`](https://github.com/basicmachines-co/basic-memory/commit/78f234b1806b578a0a833e8ee4184015b7369a97))

Fixes #36 by modifying entity_service.update_entity() to read existing frontmatter from files before
  updating them. Custom metadata fields such as Status, Priority, and Version are now preserved when
  notes are updated through the write_note MCP tool.

Added test case that verifies this behavior by creating a note with custom frontmatter and then
  updating it.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

- Preserve custom frontmatter fields when updating notes
  ([`e716946`](https://github.com/basicmachines-co/basic-memory/commit/e716946b4408d017eca4be720956d5a210b4e6b1))

Fixes #36 by modifying entity_service.update_entity() to read existing frontmatter from files before
  updating them. Custom metadata fields such as Status, Priority, and Version are now preserved when
  notes are updated through the write_note MCP tool.

Added test case that verifies this behavior by creating a note with custom frontmatter and then
  updating it.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

Signed-off-by: phernandez <paul@basicmachines.co>

### Chores

- Remove duplicate code in entity_service.py from bad merge
  ([`681af5d`](https://github.com/basicmachines-co/basic-memory/commit/681af5d4505dadc40b4086630f739d76bac9201d))

Signed-off-by: phernandez <paul@basicmachines.co>

### Documentation

- Add help docs to mcp cli tools
  ([`731b502`](https://github.com/basicmachines-co/basic-memory/commit/731b502d36cec253d114403d73b48fab3c47786e))

Signed-off-by: phernandez <paul@basicmachines.co>

- Add mcp badge, update cli reference, llms-install.md
  ([`b26afa9`](https://github.com/basicmachines-co/basic-memory/commit/b26afa927f98021246cd8b64858e57333595ea90))

Signed-off-by: phernandez <paul@basicmachines.co>

- Update CLAUDE.md ([#33](https://github.com/basicmachines-co/basic-memory/pull/33),
  [`dfaf0fe`](https://github.com/basicmachines-co/basic-memory/commit/dfaf0fea9cf5b97d169d51a6276ec70162c21a7e))

fix spelling in CLAUDE.md: environment typo Signed-off-by: Ikko Eltociear Ashimine
  <eltociear@gmail.com>

### Refactoring

- Move project stats into project subcommand
  ([`2a881b1`](https://github.com/basicmachines-co/basic-memory/commit/2a881b1425c73947f037fbe7ac5539c015b62526))

Signed-off-by: phernandez <paul@basicmachines.co>


## v0.10.0 (2025-03-15)

### Bug Fixes

- Ai_resource_guide.md path
  ([`da97353`](https://github.com/basicmachines-co/basic-memory/commit/da97353cfc3acc1ceb0eca22ac6af326f77dc199))

Signed-off-by: phernandez <paul@basicmachines.co>

- Ai_resource_guide.md path
  ([`c4732a4`](https://github.com/basicmachines-co/basic-memory/commit/c4732a47b37dd2e404139fb283b65556c81ce7c9))

- Ai_resource_guide.md path
  ([`2e9d673`](https://github.com/basicmachines-co/basic-memory/commit/2e9d673e54ad6a63a971db64f01fc2f4e59c2e69))

Signed-off-by: phernandez <paul@basicmachines.co>

- Don't sync *.tmp files on watch ([#31](https://github.com/basicmachines-co/basic-memory/pull/31),
  [`6b110b2`](https://github.com/basicmachines-co/basic-memory/commit/6b110b28dd8ba705ebfc0bcb41faf2cb993da2c3))

Fixes #30

Signed-off-by: phernandez <paul@basicmachines.co>

- Drop search_index table on db reindex
  ([`31cca6f`](https://github.com/basicmachines-co/basic-memory/commit/31cca6f913849a0ab8fc944803533e3072e9ef88))

Signed-off-by: phernandez <paul@basicmachines.co>

- Improve utf-8 support for file reading/writing
  ([#32](https://github.com/basicmachines-co/basic-memory/pull/32),
  [`eb5e4ec`](https://github.com/basicmachines-co/basic-memory/commit/eb5e4ec6bd4d2fe757087be030d867f4ca1d38ba))

fixes #29

Signed-off-by: phernandez <paul@basicmachines.co>

### Chores

- Remove logfire
  ([`9bb8a02`](https://github.com/basicmachines-co/basic-memory/commit/9bb8a020c3425a02cb3a88f6f02adcd281bccee2))

Signed-off-by: phernandez <paul@basicmachines.co>

### Documentation

- Add glama badge. Fix typos in README.md
  ([#28](https://github.com/basicmachines-co/basic-memory/pull/28),
  [`9af913d`](https://github.com/basicmachines-co/basic-memory/commit/9af913da4fba7bb4908caa3f15f2db2aa03777ec))

Signed-off-by: phernandez <paul@basicmachines.co>

- Update CLAUDE.md with GitHub integration capabilities
  ([#25](https://github.com/basicmachines-co/basic-memory/pull/25),
  [`fea2f40`](https://github.com/basicmachines-co/basic-memory/commit/fea2f40d1b54d0c533e6d7ee7ce1aa7b83ad9a47))

This PR updates the CLAUDE.md file to document the GitHub integration capabilities that enable
  Claude to participate directly in the development workflow.

### Features

- Add Smithery integration for easier installation
  ([#24](https://github.com/basicmachines-co/basic-memory/pull/24),
  [`eb1e7b6`](https://github.com/basicmachines-co/basic-memory/commit/eb1e7b6088b0b3dead9c104ee44174b2baebf417))

This PR adds support for deploying Basic Memory on the Smithery platform.

Signed-off-by: bm-claudeai <claude@basicmachines.co>


## v0.9.0 (2025-03-07)

### Chores

- Pre beta prep ([#20](https://github.com/basicmachines-co/basic-memory/pull/20),
  [`6a4bd54`](https://github.com/basicmachines-co/basic-memory/commit/6a4bd546466a45107007b5000276b6c9bb62ef27))

fix: drop search_index table on db reindex

fix: ai_resource_guide.md path

chore: remove logfire

Signed-off-by: phernandez <paul@basicmachines.co>

### Documentation

- Update README.md and CLAUDE.md
  ([`182ec78`](https://github.com/basicmachines-co/basic-memory/commit/182ec7835567fc246798d9b4ad121b2f85bc6ade))

### Features

- Add project_info tool ([#19](https://github.com/basicmachines-co/basic-memory/pull/19),
  [`d2bd75a`](https://github.com/basicmachines-co/basic-memory/commit/d2bd75a949cc4323cb376ac2f6cb39f47c78c428))

Signed-off-by: phernandez <paul@basicmachines.co>

- Beta work ([#17](https://github.com/basicmachines-co/basic-memory/pull/17),
  [`e6496df`](https://github.com/basicmachines-co/basic-memory/commit/e6496df595f3cafde6cc836384ee8c60886057a5))

feat: Add multiple projects support

feat: enhanced read_note for when initial result is not found

fix: merge frontmatter when updating note

fix: handle directory removed on sync watch

- Implement boolean search ([#18](https://github.com/basicmachines-co/basic-memory/pull/18),
  [`90d5754`](https://github.com/basicmachines-co/basic-memory/commit/90d5754180beaf4acd4be38f2438712555640b49))


## v0.8.0 (2025-02-28)

### Chores

- Formatting
  ([`93cc637`](https://github.com/basicmachines-co/basic-memory/commit/93cc6379ebb9ecc6a1652feeeecbf47fc992d478))

- Refactor logging setup
  ([`f4b703e`](https://github.com/basicmachines-co/basic-memory/commit/f4b703e57f0ddf686de6840ff346b8be2be499ad))

### Features

- Add enhanced prompts and resources
  ([#15](https://github.com/basicmachines-co/basic-memory/pull/15),
  [`093dab5`](https://github.com/basicmachines-co/basic-memory/commit/093dab5f03cf7b090a9f4003c55507859bf355b0))

## Summary - Add comprehensive documentation to all MCP prompt modules - Enhance search prompt with
  detailed contextual output formatting - Implement consistent logging and docstring patterns across
  prompt utilities - Fix type checking in prompt modules

## Prompts Added/Enhanced - `search.py`: New formatted output with relevance scores, excerpts, and
  next steps - `recent_activity.py`: Enhanced with better metadata handling and documentation -
  `continue_conversation.py`: Improved context management

## Resources Added/Enhanced - `ai_assistant_guide`: Resource with description to give to LLM to
  understand how to use the tools

## Technical improvements - Added detailed docstrings to all prompt modules explaining their purpose
  and usage - Enhanced the search prompt with rich contextual output that helps LLMs understand
  results - Created a consistent pattern for formatting output across prompts - Improved error
  handling in metadata extraction - Standardized import organization and naming conventions - Fixed
  various type checking issues across the codebase

This PR is part of our ongoing effort to improve the MCP's interaction quality with LLMs, making the
  system more helpful and intuitive for AI assistants to navigate knowledge bases.

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: phernandez <phernandez@basicmachines.co>

- Add new `canvas` tool to create json canvas files in obsidian.
  ([#14](https://github.com/basicmachines-co/basic-memory/pull/14),
  [`0d7b0b3`](https://github.com/basicmachines-co/basic-memory/commit/0d7b0b3d7ede7555450ddc9728951d4b1edbbb80))

Add new `canvas` tool to create json canvas files in obsidian.

---------

Co-authored-by: phernandez <phernandez@basicmachines.co>

- Incremental sync on watch ([#13](https://github.com/basicmachines-co/basic-memory/pull/13),
  [`37a01b8`](https://github.com/basicmachines-co/basic-memory/commit/37a01b806d0758029d34a862e76d44c7e5d538a5))

- incremental sync on watch - sync non-markdown files in knowledge base - experimental
  `read_resource` tool for reading non-markdown files in raw form (pdf, image)


## v0.7.0 (2025-02-19)

### Bug Fixes

- Add logfire instrumentation to tools
  ([`3e8e3e8`](https://github.com/basicmachines-co/basic-memory/commit/3e8e3e8961eae2e82839746e28963191b0aef0a0))

- Add logfire spans to cli
  ([`00d23a5`](https://github.com/basicmachines-co/basic-memory/commit/00d23a5ee15ddac4ea45e702dcd02ab9f0509276))

- Add logfire spans to cli
  ([`812136c`](https://github.com/basicmachines-co/basic-memory/commit/812136c8c22ad191d14ff32dcad91aae076d4120))

- Search query pagination params
  ([`bc9ca07`](https://github.com/basicmachines-co/basic-memory/commit/bc9ca0744ffe4296d7d597b4dd9b7c73c2d63f3f))

### Chores

- Fix tests
  ([`57984aa`](https://github.com/basicmachines-co/basic-memory/commit/57984aa912625dcde7877afb96d874c164af2896))

- Remove unused tests
  ([`2c8ed17`](https://github.com/basicmachines-co/basic-memory/commit/2c8ed1737d6769fe1ef5c96f8a2bd75b9899316a))

### Features

- Add cli commands for mcp tools
  ([`f5a7541`](https://github.com/basicmachines-co/basic-memory/commit/f5a7541da17e97403b7a702720a05710f68b223a))

- Add pagination to build_context and recent_activity
  ([`0123544`](https://github.com/basicmachines-co/basic-memory/commit/0123544556513af943d399d70b849b142b834b15))

- Add pagination to read_notes
  ([`02f8e86`](https://github.com/basicmachines-co/basic-memory/commit/02f8e866923d5793d2620076c709c920d99f2c4f))


## v0.6.0 (2025-02-18)

### Chores

- Re-add sync status console on watch
  ([`66b57e6`](https://github.com/basicmachines-co/basic-memory/commit/66b57e682f2e9c432bffd4af293b0d1db1d3469b))

### Features

- Configure logfire telemetry ([#12](https://github.com/basicmachines-co/basic-memory/pull/12),
  [`6da1438`](https://github.com/basicmachines-co/basic-memory/commit/6da143898bd45cdab8db95b5f2b75810fbb741ba))

Co-authored-by: phernandez <phernandez@basicmachines.co>


## v0.5.0 (2025-02-18)

### Features

- Return semantic info in markdown after write_note
  ([#11](https://github.com/basicmachines-co/basic-memory/pull/11),
  [`0689e7a`](https://github.com/basicmachines-co/basic-memory/commit/0689e7a730497827bf4e16156ae402ddc5949077))

Co-authored-by: phernandez <phernandez@basicmachines.co>


## v0.4.3 (2025-02-18)

### Bug Fixes

- Re do enhanced read note format ([#10](https://github.com/basicmachines-co/basic-memory/pull/10),
  [`39bd5ca`](https://github.com/basicmachines-co/basic-memory/commit/39bd5ca08fd057220b95a8b5d82c5e73a1f5722b))

Co-authored-by: phernandez <phernandez@basicmachines.co>


## v0.4.2 (2025-02-17)


## v0.4.1 (2025-02-17)

### Bug Fixes

- Fix alemic config
  ([`71de8ac`](https://github.com/basicmachines-co/basic-memory/commit/71de8acfd0902fc60f27deb3638236a3875787ab))

- More alembic fixes
  ([`30cd74e`](https://github.com/basicmachines-co/basic-memory/commit/30cd74ec95c04eaa92b41b9815431f5fbdb46ef8))


## v0.4.0 (2025-02-16)

### Features

- Import chatgpt conversation data ([#9](https://github.com/basicmachines-co/basic-memory/pull/9),
  [`56f47d6`](https://github.com/basicmachines-co/basic-memory/commit/56f47d6812982437f207629e6ac9a82e0e56514e))

Co-authored-by: phernandez <phernandez@basicmachines.co>

- Import claude.ai data ([#8](https://github.com/basicmachines-co/basic-memory/pull/8),
  [`a15c346`](https://github.com/basicmachines-co/basic-memory/commit/a15c346d5ebd44344b76bad877bb4d1073fcbc3b))

Import Claude.ai conversation and project data to basic-memory Markdown format.

---------

Co-authored-by: phernandez <phernandez@basicmachines.co>


## v0.3.0 (2025-02-15)

### Bug Fixes

- Refactor db schema migrate handling
  ([`ca632be`](https://github.com/basicmachines-co/basic-memory/commit/ca632beb6fed5881f4d8ba5ce698bb5bc681e6aa))


## v0.2.21 (2025-02-15)

### Bug Fixes

- Fix osx installer github action
  ([`65ebe5d`](https://github.com/basicmachines-co/basic-memory/commit/65ebe5d19491e5ff047c459d799498ad5dd9cd1a))

- Handle memory:// url format in read_note tool
  ([`e080373`](https://github.com/basicmachines-co/basic-memory/commit/e0803734e69eeb6c6d7432eea323c7a264cb8347))

- Remove create schema from init_db
  ([`674dd1f`](https://github.com/basicmachines-co/basic-memory/commit/674dd1fd47be9e60ac17508476c62254991df288))

### Features

- Set version in var, output version at startup
  ([`a91da13`](https://github.com/basicmachines-co/basic-memory/commit/a91da1396710e62587df1284da00137d156fc05e))


## v0.2.20 (2025-02-14)

### Bug Fixes

- Fix installer artifact
  ([`8de84c0`](https://github.com/basicmachines-co/basic-memory/commit/8de84c0221a1ee32780aa84dac4d3ea60895e05c))


## v0.2.19 (2025-02-14)

### Bug Fixes

- Get app artifact for installer
  ([`fe8c3d8`](https://github.com/basicmachines-co/basic-memory/commit/fe8c3d87b003166252290a87cbe958301cccf797))


## v0.2.18 (2025-02-14)

### Bug Fixes

- Don't zip app on release
  ([`8664c57`](https://github.com/basicmachines-co/basic-memory/commit/8664c57bb331d7f3f7e0239acb5386c7a3c6144e))


## v0.2.17 (2025-02-14)

### Bug Fixes

- Fix app zip in installer release
  ([`8fa197e`](https://github.com/basicmachines-co/basic-memory/commit/8fa197e2ec8a1b6caaf6dbb39c3c6626bba23e2e))


## v0.2.16 (2025-02-14)

### Bug Fixes

- Debug inspect build on ci
  ([`1d6054d`](https://github.com/basicmachines-co/basic-memory/commit/1d6054d30a477a4e6a5d6ac885632e50c01945d3))


## v0.2.15 (2025-02-14)

### Bug Fixes

- Debug installer ci
  ([`dab9573`](https://github.com/basicmachines-co/basic-memory/commit/dab957314aec9ed0e12abca2265552494ae733a2))


## v0.2.14 (2025-02-14)


## v0.2.13 (2025-02-14)

### Bug Fixes

- Refactor release.yml installer
  ([`a152657`](https://github.com/basicmachines-co/basic-memory/commit/a15265783e47c22d8c7931396281d023b3694e27))

- Try using symlinks in installer build
  ([`8dd923d`](https://github.com/basicmachines-co/basic-memory/commit/8dd923d5bc0587276f92b5f1db022ad9c8687e45))


## v0.2.12 (2025-02-14)

### Bug Fixes

- Fix cx_freeze options for installer
  ([`854cf83`](https://github.com/basicmachines-co/basic-memory/commit/854cf8302e2f83578030db05e29b8bdc4348795a))


## v0.2.11 (2025-02-14)

### Bug Fixes

- Ci installer app fix #37
  ([`2e215fe`](https://github.com/basicmachines-co/basic-memory/commit/2e215fe83ca421b921186c7f1989dc2cb5cca278))


## v0.2.10 (2025-02-14)

### Bug Fixes

- Fix build on github ci for app installer
  ([`29a2594`](https://github.com/basicmachines-co/basic-memory/commit/29a259421a0ccb10cfa68e3707eaa506ad5e55c0))


## v0.2.9 (2025-02-14)


## v0.2.8 (2025-02-14)

### Bug Fixes

- Fix installer on ci, maybe
  ([`edbc04b`](https://github.com/basicmachines-co/basic-memory/commit/edbc04be601d234bb1f5eb3ba24d6ad55244b031))


## v0.2.7 (2025-02-14)

### Bug Fixes

- Try to fix installer ci
  ([`230738e`](https://github.com/basicmachines-co/basic-memory/commit/230738ee9c110c0509e0a09cb0e101a92cfcb729))


## v0.2.6 (2025-02-14)

### Bug Fixes

- Bump project patch version
  ([`01d4672`](https://github.com/basicmachines-co/basic-memory/commit/01d46727b40c24b017ea9db4b741daef565ac73e))

- Fix installer setup.py change ci to use make
  ([`3e78fcc`](https://github.com/basicmachines-co/basic-memory/commit/3e78fcc2c208d83467fe7199be17174d7ffcad1a))


## v0.2.5 (2025-02-14)

### Bug Fixes

- Refix virtual env in installer build
  ([`052f491`](https://github.com/basicmachines-co/basic-memory/commit/052f491fff629e8ead629c9259f8cb46c608d584))


## v0.2.4 (2025-02-14)


## v0.2.3 (2025-02-14)

### Bug Fixes

- Workaround unsigned app
  ([`41d4d81`](https://github.com/basicmachines-co/basic-memory/commit/41d4d81c1ad1dc2923ba0e903a57454a0c8b6b5c))


## v0.2.2 (2025-02-14)

### Bug Fixes

- Fix path to installer app artifact
  ([`53d220d`](https://github.com/basicmachines-co/basic-memory/commit/53d220df585561f9edd0d49a9e88f1d4055059cf))


## v0.2.1 (2025-02-14)

### Bug Fixes

- Activate virtualenv in installer build
  ([`d4c8293`](https://github.com/basicmachines-co/basic-memory/commit/d4c8293687a52eaf3337fe02e2f7b80e4cc9a1bb))

- Trigger installer build on release
  ([`f11bf78`](https://github.com/basicmachines-co/basic-memory/commit/f11bf78f3f600d0e1b01996cf8e1f9c39e3dd218))


## v0.2.0 (2025-02-14)

### Features

- Build installer via github action ([#7](https://github.com/basicmachines-co/basic-memory/pull/7),
  [`7c381a5`](https://github.com/basicmachines-co/basic-memory/commit/7c381a59c962053c78da096172e484f28ab47e96))

* feat(ci): build installer via github action

* enforce conventional commits in PR titles

* feat: add icon to installer

---------

Co-authored-by: phernandez <phernandez@basicmachines.co>


## v0.1.2 (2025-02-14)

### Bug Fixes

- Fix installer for mac
  ([`dde9ff2`](https://github.com/basicmachines-co/basic-memory/commit/dde9ff228b72852b5abc58faa1b5e7c6f8d2c477))

- Remove unused FileChange dataclass
  ([`eb3360c`](https://github.com/basicmachines-co/basic-memory/commit/eb3360cc221f892b12a17137ae740819d48248e8))

- Update uv installer url
  ([`2f9178b`](https://github.com/basicmachines-co/basic-memory/commit/2f9178b0507b3b69207d5c80799f2d2f573c9a04))


## v0.1.1 (2025-02-07)


## v0.1.0 (2025-02-07)

### Bug Fixes

- Create virtual env in test workflow
  ([`8092e6d`](https://github.com/basicmachines-co/basic-memory/commit/8092e6d38d536bfb6f93c3d21ea9baf1814f9b0a))

- Fix permalink uniqueness violations on create/update/sync
  ([`135bec1`](https://github.com/basicmachines-co/basic-memory/commit/135bec181d9b3d53725c8af3a0959ebc1aa6afda))

- Fix recent activity bug
  ([`3d2c0c8`](https://github.com/basicmachines-co/basic-memory/commit/3d2c0c8c32fcfdaf70a1f96a59d8f168f38a1aa9))

- Install fastapi deps after removing basic-foundation
  ([`51a741e`](https://github.com/basicmachines-co/basic-memory/commit/51a741e7593a1ea0e5eb24e14c70ff61670f9663))

- Recreate search index on db reset
  ([`1fee436`](https://github.com/basicmachines-co/basic-memory/commit/1fee436bf903a35c9ebb7d87607fc9cc9f5ff6e7))

- Remove basic-foundation from deps
  ([`b8d0c71`](https://github.com/basicmachines-co/basic-memory/commit/b8d0c7160f29c97cdafe398a7e6a5240473e0c89))

- Run tests via uv
  ([`4eec820`](https://github.com/basicmachines-co/basic-memory/commit/4eec820a32bc059a405e2f4dac4c73b245ca4722))

### Chores

- Rename import tool
  ([`af6b7dc`](https://github.com/basicmachines-co/basic-memory/commit/af6b7dc40a55eaa2aa78d6ea831e613851081d52))

### Features

- Add memory-json importer, tweak observation content
  ([`3484e26`](https://github.com/basicmachines-co/basic-memory/commit/3484e26631187f165ee6eb85517e94717b7cf2cf))


## v0.0.1 (2025-02-04)

### Bug Fixes

- Fix versioning for 0.0.1 release
  ([`ba1e494`](https://github.com/basicmachines-co/basic-memory/commit/ba1e494ed1afbb7af3f97c643126bced425da7e0))


## v0.0.0 (2025-02-04)

### Chores

- Remove basic-foundation src ref in pyproject.toml
  ([`29fce8b`](https://github.com/basicmachines-co/basic-memory/commit/29fce8b0b922d54d7799bf2534107ee6cfb961b8))