From c44f0fbeae92272eef2fc4d9c5344fa35edf0120 Mon Sep 17 00:00:00 2001 From: phernandez Date: Sat, 24 Oct 2026 00:07:39 -0500 Subject: [PATCH 1/5] docs: migrate guides and reference to 1.0 MCP tools Signed-off-by: phernandez --- CLAUDE.md | 4 +- .../01.start-here/1.what-is-basic-memory.md | 24 +- content/01.start-here/2.quickstart-cloud.md | 10 +- content/01.start-here/3.quickstart-local.md | 8 +- content/03.cloud/01.cloud-guide.md | 6 +- content/03.cloud/05.cloud-sync.md | 6 +- content/03.cloud/08.api-keys.md | 6 +- content/04.teams/4.team-projects.md | 6 +- content/04.teams/5.join-a-team.md | 6 +- content/04.teams/6.copy-between-workspaces.md | 16 +- content/06.local/4.mcp-tools-local.md | 42 +- content/06.local/5.user-guide.md | 34 +- content/07.concepts/0.vs-built-in-memory.md | 6 +- content/07.concepts/1.knowledge-format.md | 12 +- content/07.concepts/2.projects-and-folders.md | 10 +- .../3.observations-and-relations.md | 8 +- content/07.concepts/4.memory-urls.md | 10 +- content/07.concepts/6.schema-system.md | 6 +- content/07.concepts/7.semantic-search.md | 14 +- content/07.concepts/8.metadata-search.md | 72 +- content/07.concepts/9.documents-and-pdfs.md | 12 +- content/09.how-to/1.project-documentation.md | 6 +- content/09.how-to/2.writing-organization.md | 6 +- content/09.how-to/4.note-taking.md | 8 +- content/10.reference/2.mcp-tools-reference.md | 1124 ++++++++++------- content/10.reference/3.ai-assistant-guide.md | 49 +- .../10.reference/4.technical-information.md | 8 +- content/10.reference/5.troubleshooting.md | 16 +- content/10.reference/7.migrating-to-1-0.md | 87 ++ 29 files changed, 1022 insertions(+), 600 deletions(-) create mode 100644 content/10.reference/7.migrating-to-1-0.md diff --git a/CLAUDE.md b/CLAUDE.md index 41f60c5..722731b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -15,7 +15,7 @@ This is the documentation website for Basic Memory (`docs.basicmemory.com`), bui **Current Version**: v0.24.1 (released October 2026) **Key Features**: -- 17 MCP tools for AI integration (write_note, read_note, edit_note, search_notes, build_context, etc.) +- Twelve core 1.0 MCP tools (`bm_read`, `bm_write`, `bm_edit`, `bm_search`, `bm_context`, etc.); reference pages are being prepared ahead of release - Local markdown files create a semantic knowledge graph - Multi-project support with project switching - Integrations with Claude Desktop, VS Code, Cursor, Obsidian @@ -62,7 +62,7 @@ This documentation site covers both: 1. **Basic Memory** (local-first product) - Installation, MCP tools, CLI, integrations, knowledge format 2. **Basic Memory Cloud** (upcoming) - Cloud-specific features, authentication, sync, billing -The site documents the latest v0.24.x release and includes cloud product documentation. +Release history documents v0.24.x. Current MCP reference pages target the upcoming 1.0 surface and must state that status. Hosted extension documentation retains its separately advertised contract. ## Development Commands diff --git a/content/01.start-here/1.what-is-basic-memory.md b/content/01.start-here/1.what-is-basic-memory.md index 1931a75..2645807 100644 --- a/content/01.start-here/1.what-is-basic-memory.md +++ b/content/01.start-here/1.what-is-basic-memory.md @@ -3,6 +3,10 @@ title: What is Basic Memory description: An overview of what Basic Memory is and how it works. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Basic Memory is real memory for your AI — a knowledge base you own. It stores notes as plain Markdown files, so your work stays readable, portable, and searchable. Instead of losing valuable insights in conversation history, you build a persistent knowledge base that every AI tool you use can read, write, and enhance — Claude, ChatGPT, Codex, OpenClaw, Hermes, and all your team's agents, working from one shared memory. @@ -65,7 +69,7 @@ Use the hosted cloud service or run everything locally - your choice. ## How it works -Basic Memory stores your notes as Markdown files and keeps a search index over them. Your AI assistant connects through MCP and calls tools like `search_notes`, `read_note`, and `write_note` to work with your notes. +Basic Memory stores your notes as Markdown files and keeps a search index over them. Your AI assistant connects through MCP and calls tools like `bm_search`, `bm_read`, and `bm_write` to work with your notes. ::mermaid --- @@ -191,9 +195,9 @@ When you ask a question, the AI doesn't just return one note. It traverses the g --- code: | flowchart LR - Q[Your question] --> S[search_notes] + Q[Your question] --> S[bm_search] S --> M[Matching notes] - M --> B[build_context] + M --> B[bm_context] B --> R[Related notes] R --> C[Full context] C --> A[AI answer] @@ -203,7 +207,7 @@ code: | **The flow:** 1. **Search** - Your question triggers a search across all notes -2. **Expand** - The AI uses `build_context` to follow relations and gather connected notes +2. **Expand** - The AI uses `bm_context` to follow relations and gather connected notes 3. **Synthesize** - With the full context loaded, the AI can give a complete answer This recursive traversal means asking about "API authentication" automatically pulls in related decisions, dependencies, and connected topics - giving your AI the full picture. @@ -334,12 +338,12 @@ The open-source local version provides: Basic Memory uses the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) to connect with AI assistants. MCP is an open standard that lets AI assistants use external tools. **Available tools:** -- `write_note` - Create or update notes -- `read_note` - Read notes with context -- `search_notes` - Full-text and semantic search -- `edit_note` - Incremental editing -- `build_context` - Load related notes -- `list_memory_projects` - List your projects +- `bm_write` - Create or update notes +- `bm_read` - Read notes with context +- `bm_search` - Full-text and semantic search +- `bm_edit` - Incremental editing +- `bm_context` - Load related notes +- `bm_project(command="list")` - List your projects - `cat`, `grep`, `ls`, `find`, `tail`, `man` - Familiar read-only tools for browsing notes like files - ...and many more diff --git a/content/01.start-here/2.quickstart-cloud.md b/content/01.start-here/2.quickstart-cloud.md index a896c43..2f490c2 100644 --- a/content/01.start-here/2.quickstart-cloud.md +++ b/content/01.start-here/2.quickstart-cloud.md @@ -3,6 +3,10 @@ title: "Quickstart: Cloud" description: Connect Basic Memory Cloud and create your first note in 2 minutes. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Basic Memory Cloud gives you a hosted MCP endpoint and a web app. Connect your AI assistant and start writing notes in minutes - no installation required. ::docs-video{src="/videos/docs-quickstart.mp4" poster="/videos/posters/docs-quickstart.png" alt="Meet your workspace and write your first notes"} @@ -108,7 +112,7 @@ Try this prompt: Create a note called "My First Note" with a summary of what Basic Memory does. ``` -Your assistant will use the `write_note` tool to create a Markdown file in your cloud storage. +Your assistant will use the `bm_write` tool to create a Markdown file in your cloud storage. **Example conversation:** ```bash @@ -116,7 +120,7 @@ You: Create a note called "My First Note" with a summary of what Basic Memory do AI: I'll create a note summarizing Basic Memory for you. -[Uses write_note tool] +[Uses bm_write tool] I've created "My First Note" in your knowledge base. The note covers: - What Basic Memory is @@ -186,7 +190,7 @@ AI: [Searches knowledge base, finds your pour-over note] You: "Add a section about water temperature to my coffee notes" -AI: [Uses edit_note to append new content] +AI: [Uses bm_edit to append new content] ``` --- diff --git a/content/01.start-here/3.quickstart-local.md b/content/01.start-here/3.quickstart-local.md index b3b0d30..3bb8d7d 100644 --- a/content/01.start-here/3.quickstart-local.md +++ b/content/01.start-here/3.quickstart-local.md @@ -3,6 +3,10 @@ title: "Quickstart: Local" description: Install Basic Memory locally and connect it to your AI assistant. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Local mode keeps notes on your machine and runs the MCP server locally. It's open-source and free to use. ::mermaid @@ -114,7 +118,7 @@ You: Create a note called "My First Note" with a summary of what Basic Memory do Claude: I'll create a note for you. -[Uses write_note tool] +[Uses bm_write tool] Done! I've created "My First Note.md" in your basic-memory folder. It includes an overview of Basic Memory's key features: @@ -193,7 +197,7 @@ Claude: [Searches knowledge base] You: "Add a section about rate limiting" -Claude: [Uses edit_note to append] +Claude: [Uses bm_edit to append] "I've added a rate limiting section to your API design notes." ``` diff --git a/content/03.cloud/01.cloud-guide.md b/content/03.cloud/01.cloud-guide.md index dd6fde0..c9f073a 100644 --- a/content/03.cloud/01.cloud-guide.md +++ b/content/03.cloud/01.cloud-guide.md @@ -3,6 +3,10 @@ title: Basic Memory Cloud description: Cloud remote MCP setup, web editor, CLI tools, and snapshots for Basic Memory Cloud. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Basic Memory Cloud provides hosted MCP access with no local installation required. Bring your knowledge to the cloud - all your existing notes, connections, and context accessible from anywhere. ::docs-video{src="/videos/hero.mp4" poster="/videos/posters/hero.png" alt="What Basic Memory is, in one minute"} @@ -133,7 +137,7 @@ A configured local sync directory is **kept** unless you pass `--delete-local-fi Hosted deletion is asynchronous: the project is hidden from cloud workspace operations when deletion is accepted, then a background job removes its database rows and every object under the project's storage prefix. -The MCP `delete_project` tool on a cloud route also always deletes the project's cloud files. From a local stdio MCP session, pass `workspace` to route the request to that cloud workspace. Its `delete_notes` parameter applies only to local projects. MCP deletion never removes a local sync directory; use `bm project remove --delete-local-files` when you want both copies gone. The MCP response reports the pending deletion status and background job ID. +The MCP `bm_project_delete` tool on a cloud route also always deletes the project's cloud files. From a local stdio MCP session, pass `workspace` to route the request to that cloud workspace. Its `delete_notes` parameter applies only to local projects. MCP deletion never removes a local sync directory; use `bm project remove --delete-local-files` when you want both copies gone. The MCP response reports the pending deletion status and background job ID. --- diff --git a/content/03.cloud/05.cloud-sync.md b/content/03.cloud/05.cloud-sync.md index cafdfff..f4ea63b 100644 --- a/content/03.cloud/05.cloud-sync.md +++ b/content/03.cloud/05.cloud-sync.md @@ -3,6 +3,10 @@ title: Cloud Sync Guide description: Guide to syncing your local Basic Memory projects with Basic Memory Cloud. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + The Basic Memory Cloud CLI provides seamless integration between local and cloud knowledge bases using **project-scoped synchronization**. Each project can optionally sync with the cloud, giving you fine-grained control over what syncs and where. --- @@ -267,7 +271,7 @@ bm cloud pull --name research --on-conflict keep-both | `bm cloud bisync --name research` | `bm cloud pull --name research`, then `bm cloud push --name research` | | `bm cloud bisync-reset research` | Nothing — `pull`/`push` keep no baseline to reset | -`push` never deletes cloud files. To remove cloud files that match a newly added `.bmignore` pattern, use `bm cloud prune` (below). To delete individual notes, delete them in the [web app](/cloud/web-app) or with the `delete_note` MCP tool. +`push` never deletes cloud files. To remove cloud files that match a newly added `.bmignore` pattern, use `bm cloud prune` (below). To delete individual notes, delete them in the [web app](/cloud/web-app) or with the `bm_delete` MCP tool. ::warning Until it is removed, `bm cloud sync` still deletes a previously synced cloud file when it becomes ignored by `.bmignore` (v0.23 behavior). Preview with `--dry-run` if you still run it. diff --git a/content/03.cloud/08.api-keys.md b/content/03.cloud/08.api-keys.md index 3a3c0d8..53ad3f3 100644 --- a/content/03.cloud/08.api-keys.md +++ b/content/03.cloud/08.api-keys.md @@ -3,6 +3,10 @@ title: API Keys description: Create API keys for programmatic access to Basic Memory Cloud without OAuth. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + API keys provide an alternative to OAuth for authenticating with Basic Memory Cloud. Use them for CLI tools, automation scripts, or any MCP client that supports bearer token authentication. --- @@ -151,7 +155,7 @@ If you suspect a key has been compromised, revoke it immediately and create a ne ## Read-only keys -A read-only key can run every read operation — search, read, `build_context`, project status — and is refused on any write. Write tools (`write_note`, `edit_note`, `move_note`, `delete_note`) return an MCP tool error (`isError`) saying the key is read-only, so a client never mistakes a refused write for a saved one. +A read-only key can run every read operation — search, read, `bm_context`, project status — and is refused on any write. Write tools (`bm_write`, `bm_edit`, `bm_move`, `bm_delete`) return an MCP tool error (`isError`) saying the key is read-only, so a client never mistakes a refused write for a saved one. ::note Use Basic Memory v0.24 or later with read-only keys. Earlier CLI and local MCP versions checked project status with a `POST` request, so a read-only key could get "This API key is read-only" on an ordinary search that returned no results. diff --git a/content/04.teams/4.team-projects.md b/content/04.teams/4.team-projects.md index df1c3d0..ddee65f 100644 --- a/content/04.teams/4.team-projects.md +++ b/content/04.teams/4.team-projects.md @@ -3,6 +3,10 @@ title: Team Projects description: Team and invite-only project access, and working with team projects from the app, MCP, and CLI. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Projects are how a team organizes its knowledge base. Every project in a team workspace has an access level, and every member's reach into it follows their [role](/teams/members-and-roles). --- @@ -77,7 +81,7 @@ bm cloud workspace list bm cloud workspace set-default acme ``` -You can also target a specific workspace when creating a project, either from the CLI (`--workspace`) or from MCP (`create_memory_project(workspace="acme")`). +You can also target a specific workspace when creating a project, either from the CLI (`--workspace`) or from MCP (`bm_project(command="create", workspace="acme")`). ### Targeting a team project explicitly diff --git a/content/04.teams/5.join-a-team.md b/content/04.teams/5.join-a-team.md index 630a5cb..c1bee54 100644 --- a/content/04.teams/5.join-a-team.md +++ b/content/04.teams/5.join-a-team.md @@ -3,6 +3,10 @@ title: Joining a Team Workspace description: First-time setup for new team members — accept the invite, sign in, switch workspaces, and connect your AI assistant to the shared knowledge base. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + You got an invite to a Basic Memory [team workspace](/teams/about). This page walks through what to do on day one — accept the invite, get into the workspace, find the shared projects, and point your AI assistant at the same knowledge base. ::note @@ -62,7 +66,7 @@ bm cloud workspace set-default acme bm project list --workspace acme ``` -From MCP, pass the workspace through `create_memory_project(workspace="acme")`, or reference notes with a workspace-qualified memory URL — `memory://acme/research/note-title`. See [Team Projects](/teams/team-projects) for the full targeting guide. +From MCP, pass the workspace through `bm_project(command="create", workspace="acme")`, or reference notes with a workspace-qualified memory URL — `memory://acme/research/note-title`. See [Team Projects](/teams/team-projects) for the full targeting guide. --- diff --git a/content/04.teams/6.copy-between-workspaces.md b/content/04.teams/6.copy-between-workspaces.md index b19c7a9..6c8bda8 100644 --- a/content/04.teams/6.copy-between-workspaces.md +++ b/content/04.teams/6.copy-between-workspaces.md @@ -3,6 +3,10 @@ title: Copy Content Between Workspaces description: Move notes, folders, or whole projects between personal, team, and local workspaces using export/import or MCP. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + You'll often want to promote work from your personal workspace into a [team workspace](/teams/about), or pull team content back into a personal one. Today, this is a **copy-then-(optionally)-delete** workflow rather than an atomic move — you export from the source, import into the target, verify, and only then remove the original if you wanted a true move. ::note{icon="i-lucide-info"} @@ -84,16 +88,16 @@ Remove the originals from the source project once you're satisfied. MCP doesn't expose an atomic cross-project or cross-workspace move. Express it as **read → write → (optionally) delete** instead. Your AI assistant can drive this for you, or you can run the tools directly. ```text -read_note("source note", project="source-project") -write_note("Note Title", "", "target-folder", project="target-project") -delete_note("source note", project="source-project") # optional, only after verifying +bm_read("source note", project="source-project") +bm_write(title="Note Title", content="", directory="target-folder", project="target-project") +bm_delete("source note", project="source-project") # optional, only after verifying ``` A few notes on this pattern: - Pass `project` on each call so the read and write hit the right place. In a team setup, use a [project-prefixed permalink](/concepts/memory-urls) or workspace-qualified routing to be unambiguous. - For many notes, loop the read/write pair — there's no batch move, but the pattern is straightforward to script. -- Don't `delete_note` until the new copy is in place and verified. Treat this as **copy-then-optional-delete**, never as a transactional move. +- Don't `bm_delete` until the new copy is in place and verified. Treat this as **copy-then-optional-delete**, never as a transactional move. See the [MCP Tools Reference](/reference/mcp-tools-reference) for full parameter details on each tool. @@ -114,7 +118,7 @@ This is the fastest option when you have lots of notes and both projects already ## What about renaming or restructuring? -Within a single workspace, you can rename and move notes and folders freely from the app or with `move_note`. Cross-workspace, do the copy first, then reorganize on the target side. +Within a single workspace, you can rename and move notes and folders freely from the app or with `bm_move`. Cross-workspace, do the copy first, then reorganize on the target side. --- @@ -124,4 +128,4 @@ Within a single workspace, you can rename and move notes and folders freely from - [Web App](/cloud/web-app) — projects, downloads, and imports - [Cloud Sync](/cloud/cloud-sync) — push/pull sync setup - [Shared Notes](/cloud/shared-notes) — public links for individual notes -- [MCP Tools Reference](/reference/mcp-tools-reference) — `read_note`, `write_note`, `delete_note` +- [MCP Tools Reference](/reference/mcp-tools-reference) — `bm_read`, `bm_write`, `bm_delete` diff --git a/content/06.local/4.mcp-tools-local.md b/content/06.local/4.mcp-tools-local.md index cd576c4..a1d9bd9 100644 --- a/content/06.local/4.mcp-tools-local.md +++ b/content/06.local/4.mcp-tools-local.md @@ -3,6 +3,10 @@ title: MCP tools (local) description: Use MCP tools against local projects. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + MCP tools are the same in Cloud and Local. In local mode, they operate on folders on your machine. ## Use tools in local mode @@ -11,33 +15,27 @@ Once your MCP client runs the local server (see [Local install](/local/local-ins ## Common tools -- `search_notes` to find notes (keyword, semantic, and hybrid search) -- `read_note` to load a note -- `write_note` to create or update a note -- `edit_note` to append or replace sections -- `schema_validate`, `schema_infer`, `schema_diff` for schema workflows -- `build_context` for graph traversal via [memory:// URLs](/concepts/memory-urls) +- `bm_search` to find notes (keyword, semantic, and hybrid search) +- `bm_read` to load a note +- `bm_write` to create or update a note +- `bm_edit` to append or replace sections +- `bm_schema(command="validate")`, `bm_schema(command="infer")`, `bm_schema(command="diff")` for schema workflows +- `bm_context` for graph traversal via [memory:// URLs](/concepts/memory-urls) -Most tools default to `output_format="text"` (human-readable) and also accept `"json"` (machine-readable); `build_context` defaults to `"json"` — see the [MCP Tools Reference](/reference/mcp-tools-reference) for per-tool defaults. +Most tools default to `output_format="text"` (human-readable) and also accept `"json"` (machine-readable); `bm_context` defaults to `"json"` — see the [MCP Tools Reference](/reference/mcp-tools-reference) for per-tool defaults. -## POSIX read tools +## Navigation and project routing -Since v0.24, the server also exposes six read-only tools modeled on shell commands: `ls`, `find`, `grep`, `cat`, `tail`, and `man`. Your local projects act as mount points: `ls(path="/")` lists them, and a path that starts with a project name reads from that project. +The 1.0 MCP surface consolidates the old rich and POSIX tools. Use `bm_list` for one directory level, `bm_find` for recursive paths or frontmatter queries, `bm_search` for ranked results and matching lines, and `bm_read` for full or sliced content. ```python -ls(path="/") # list projects -find(path="research", meta=["status=active"]) # notes by frontmatter -grep(pattern="retry", project="main", context_lines=3) -cat(identifier="research/specs/auth.md", section="Decisions") +bm_list(path="/") +bm_find(path="research", filters={"status": "active"}) +bm_search(query="retry", project="main", mode="text", lines=3) +bm_read(identifier="research/specs/auth.md", section="Decisions") ``` -To hide them, set `enable_posix_tools` to `false` in `~/.basic-memory/config.json` (or `BASIC_MEMORY_ENABLE_POSIX_TOOLS=false`) and restart your MCP client. - -## Which project a call uses - -A call without `project` uses your `default_project`. There is no per-session "active project" to switch, so pass `project` on each call that targets another project. If the server was started with `BASIC_MEMORY_MCP_PROJECT`, every call is constrained to that project. - -The POSIX tools are stricter: with more than one project, an unqualified path (or a `grep` / `tail` call without `project`) is refused rather than defaulted, so qualify the path (`main/notes/x.md`) or pass `project`. +Pass `project` as a name, workspace-qualified name, or UUID. Otherwise calls use the configured default. A server constrained with `BASIC_MEMORY_MCP_PROJECT` stays in that project. The legacy `enable_posix_tools` setting does not hide the new `bm_*` tools. ## Semantic search @@ -46,11 +44,11 @@ Semantic search is always on in v0.24; the old `semantic_search_enabled` setting ## Example ```python -search_notes(query="architecture", project="main") +bm_search(query="architecture", project="main") ``` ::tip -Each tool has a manual page built in. Ask your assistant to read `memory://man`, or run `bm man search-notes` in a terminal. +Each tool has a manual page built in. Ask your assistant to read `memory://man`, or run `bm man bm-search` in a terminal. :: See [What's New in v0.24](/whats-new/v0-24) for everything that changed in this release. diff --git a/content/06.local/5.user-guide.md b/content/06.local/5.user-guide.md index 40f93e4..cbf0f04 100644 --- a/content/06.local/5.user-guide.md +++ b/content/06.local/5.user-guide.md @@ -3,6 +3,10 @@ title: User Guide description: Learn how to effectively use Basic Memory in your daily workflow to build rich semantic knowledge. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + This guide covers everything from creating your first notes to building a comprehensive knowledge graph. ::tip @@ -49,7 +53,7 @@ You: We've covered several authentication approaches. Could you create a note Claude: I'll create a note summarizing our authentication discussion. -[Uses write_note tool] +[Uses bm_write tool] Done! I've created "Authentication Approaches.md" with: - Overview of options we discussed @@ -246,7 +250,7 @@ Deleting a note keeps the links that pointed at it as unresolved references inst ## Multi-Project Workflows -Basic Memory supports multiple projects for organizing different knowledge bases. The AI discovers your projects with `list_memory_projects` and names the project on each tool call; a call without a project always goes to the default project — there's no per-session "active project". Project setup, creation commands, and the default-project fallback are covered in [Set Up Local Projects](/local/getting-started). +Basic Memory supports multiple projects for organizing different knowledge bases. The AI discovers your projects with `bm_project(command="list")` and names the project on each tool call; a call without a project always goes to the default project — there's no per-session "active project". Project setup, creation commands, and the default-project fallback are covered in [Set Up Local Projects](/local/getting-started). ### Single Project Mode (Locked) @@ -271,7 +275,7 @@ This **locks** the entire MCP session - the `project` parameter in tool calls wi ### Searching Across Projects -Ask your AI to search several projects at once — "search my work and research projects for rate limiting". It passes `projects=["work", "research"]` (or `search_all_projects=True` for everything) to `search_notes` and gets one ranked list, with each result labeled by project. +Ask your AI to search several projects at once — "search my work and research projects for rate limiting". It passes `projects=["work", "research"]` (or `all_projects=True` for everything) to `bm_search` and gets one ranked list, with each result labeled by project. ### Moving Notes Between Projects @@ -361,7 +365,7 @@ Edit notes without rewriting entire documents: ```bash You: "Add a troubleshooting section to my setup guide" -Claude: [Uses edit_note with append operation] +Claude: [Uses bm_edit with append operation] "I've added a troubleshooting section to the end of your setup guide." ``` @@ -391,7 +395,7 @@ Move and rename notes with database consistency: ```bash You: "Move my old meeting notes to the archive folder" -Claude: [Uses move_note] +Claude: [Uses bm_move] "Done! I've moved 12 meeting notes to the archive folder." ``` @@ -401,11 +405,11 @@ Move or delete entire folders: ```bash You: "Move the old-projects folder to archive" -Claude: [Uses move_note with is_directory=true] +Claude: [Uses bm_move with is_directory=true] "Moved old-projects/ → archive/old-projects/ (15 files)" You: "Delete the empty temp folder" -Claude: [Uses delete_note with is_directory=true] +Claude: [Uses bm_delete with is_directory=true] "Deleted temp/ and all 3 contained files" ``` @@ -415,27 +419,27 @@ Tags and frontmatter fields are searchable. Use `tag:` shorthand or metadata fil ```bash You: "Find all my notes tagged with security" -Claude: [Uses search_notes with query="tag:security"] +Claude: [Uses bm_search with query="tag:security"] You: "Show me in-progress specs" -Claude: [Uses search_notes with note_types=["spec"], metadata_filters={"status": "in-progress"}] +Claude: [Uses bm_search with note_types=["spec"], filters={"status": "in-progress"}] You: "Find high priority items from this year" -Claude: [Uses search_notes with metadata_filters={"priority": {"$in": ["high", "critical"]}}, - after_date="2026-01-01"] +Claude: [Uses bm_search with filters={"priority": {"$in": ["high", "critical"]}}, + since="2026-01-01"] You: "Which specs don't have an owner yet?" -Claude: [Uses search_notes with note_types=["spec"], metadata_filters={"owner": {"$exists": false}}] +Claude: [Uses bm_search with note_types=["spec"], filters={"owner": {"$exists": false}}] You: "What decisions were in effect on July 1st?" -Claude: [Uses search_notes with categories=["decision"], valid_at="2026-07-01"] +Claude: [Uses bm_search with categories=["decision"], valid_at="2026-07-01"] ``` You can also search purely by metadata — no text query needed: ```bash You: "What notes have status draft?" -Claude: [Uses search_notes with status="draft"] +Claude: [Uses bm_search with status="draft"] ``` --- @@ -479,7 +483,7 @@ Semantic search lets you find notes by meaning rather than exact keywords. This ```bash You: "Find my notes about making the app faster" -Claude: [Uses search_notes with search_type="hybrid"] +Claude: [Uses bm_search with mode="hybrid"] I found several relevant notes: 1. "React Performance Optimization" — contains observations about bundle size and lazy loading diff --git a/content/07.concepts/0.vs-built-in-memory.md b/content/07.concepts/0.vs-built-in-memory.md index 4240402..b1d0ceb 100644 --- a/content/07.concepts/0.vs-built-in-memory.md +++ b/content/07.concepts/0.vs-built-in-memory.md @@ -3,6 +3,10 @@ title: Using Basic Memory with Built-in AI Memory description: How to use Basic Memory alongside the memory features in Claude, ChatGPT, and Cursor — what goes where, and how they complement each other. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Your AI tools already have built-in memory features. Basic Memory doesn't replace them — it works alongside them. This page explains what each system is good at and how to use them together effectively. ::tip @@ -13,7 +17,7 @@ Save this to your memory: Use Basic Memory as my long-term knowledge store — record durable decisions, research, and context there as notes. Keep your built-in memory for short-term working context, and have your memories reference Basic Memory notes for the details. Use Basic -Memory's search_notes, recent_activity, and build_context tools to find +Memory's bm_search, recent_activity, and bm_context tools to find information before answering questions about past work. ``` diff --git a/content/07.concepts/1.knowledge-format.md b/content/07.concepts/1.knowledge-format.md index 5c13b94..219a431 100644 --- a/content/07.concepts/1.knowledge-format.md +++ b/content/07.concepts/1.knowledge-format.md @@ -3,6 +3,10 @@ title: Knowledge Format description: Basic Memory stores knowledge as plain markdown files with simple patterns that create a searchable, connected knowledge graph. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Basic Memory is a knowledge base that you and your AI share. Everything is stored as plain markdown files on your machine — files you can open in any text editor, track with git, browse in Obsidian, or back up however you like. You own your data completely. This page explains how those files are structured and how that structure turns a folder of notes into a connected knowledge graph. @@ -66,7 +70,7 @@ modified: 2026-08-10T09:15:00Z - **permalink** — A stable identifier for this note. Generated automatically from the file's path (and prefixed with the project name by default) if you don't set one. Stays the same even if you later move the file. Every Markdown note has one — as of v0.24 there is no setting to turn permalinks off. - **created** and **modified** — Optional authoritative timestamps for the note. When present, Basic Memory uses them for recency ordering instead of filesystem timestamps. Without `created`, a new note takes its file's creation time, and later edits, moves, and reindexes keep it. -Historical `created` or `modified` values can move a note earlier in `recent_activity` and date-sorted search results after the note is reindexed. Use valid date or datetime values and change them only when you intend to change the note's recorded chronology. +Historical `created` or `modified` values can move a note earlier in `bm_project(command="recent")` and date-sorted search results after the note is reindexed. Use valid date or datetime values and change them only when you intend to change the note's recorded chronology. ### Keys Basic Memory manages @@ -166,7 +170,7 @@ For relation-type conventions and how inline references index, see [Observations Every note you write becomes a node. Every relation becomes an edge. Together, they form a knowledge graph that grows with your conversations. -This graph is what makes Basic Memory more than a folder of files. When the AI uses `build_context`, it can follow connections across notes to pull together relevant information from across your entire knowledge base — not just the one note you asked about, but the notes it links to, and the notes that link back to it. +This graph is what makes Basic Memory more than a folder of files. When the AI uses `bm_context`, it can follow connections across notes to pull together relevant information from across your entire knowledge base — not just the one note you asked about, but the notes it links to, and the notes that link back to it. --- @@ -187,7 +191,7 @@ Permalinks stay the same even if you rename or move the file. Basic Memory write Organize your files however you want — the knowledge graph is built from the content of your notes, not from where they sit on disk. See [Projects and Folders](/concepts/projects-and-folders) for organizing with projects and folder structure. ::note -`write_note` rejects filename-convention twins instead of creating a duplicate. For example, if a folder already contains the conventional equivalent of `Project Plan.md`, writing `project-plan.md` returns an error. Read or edit the existing note, or choose a genuinely different name. +`bm_write` rejects filename-convention twins instead of creating a duplicate. For example, if a folder already contains the conventional equivalent of `Project Plan.md`, writing `project-plan.md` returns an error. Read or edit the existing note, or choose a genuinely different name. :: --- @@ -226,7 +230,7 @@ In Basic Memory Cloud, notes can include `::bm-*` components — charts, tables, :: ``` -The data lives in the body as plain Markdown, so the same note still reads as an ordinary list or table in a local editor, on GitHub, or in a raw `read_note`. Components never block a write; problems are reported back so they can be fixed. The `comark(7)` manual page (`bm man comark`, or `memory://man/comark(7)` over MCP) is the quick reference, and the `memory-comark` [agent skill](/integrations/skills) teaches your AI the full component set. +The data lives in the body as plain Markdown, so the same note still reads as an ordinary list or table in a local editor, on GitHub, or in a raw `bm_read`. Components never block a write; problems are reported back so they can be fixed. The `comark(7)` manual page (`bm man comark`, or `memory://man/comark(7)` over MCP) is the quick reference, and the `memory-comark` [agent skill](/integrations/skills) teaches your AI the full component set. --- diff --git a/content/07.concepts/2.projects-and-folders.md b/content/07.concepts/2.projects-and-folders.md index c386b73..0611b6e 100644 --- a/content/07.concepts/2.projects-and-folders.md +++ b/content/07.concepts/2.projects-and-folders.md @@ -3,6 +3,10 @@ title: Projects and folders description: Projects are separate knowledge bases in Basic Memory. Learn when to use multiple projects, how folders work inside them, and how cloud routing keeps your data where you want it. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Most people start Basic Memory with a single project and a single folder. That works fine for a while, but eventually you need boundaries. Maybe you want work notes separate from personal notes. Maybe you have three clients and their knowledge should never overlap. That is what projects are for. ## What is a project? @@ -11,7 +15,7 @@ A project is a separate knowledge base. Each project maps to a folder on disk (o Think of projects the way you think of separate notebooks, not separate pages in the same notebook. -When you run a command or an AI tool like `write_note`, it targets the project you name — each call carries a `project` parameter or CLI argument. If you don't specify one, it goes to the **default project**, and you can target a different project at any time, including mid-conversation. +When you run a command or an AI tool like `bm_write`, it targets the project you name — each call carries a `project` parameter or CLI argument. If you don't specify one, it goes to the **default project**, and you can target a different project at any time, including mid-conversation. ## Creating and managing projects @@ -40,7 +44,7 @@ Switch to a different project in conversation using the MCP tool: Switch to the "personal" project. ``` -The AI will simply pass `project="personal"` on its next tool calls — there's no switch step; it discovers your projects with `list_memory_projects`. From the CLI, change the fallback for commands that don't specify a project: +The AI will simply pass `project="personal"` on its next tool calls — there's no switch step; it discovers your projects with `bm_project(command="list")`. From the CLI, change the fallback for commands that don't specify a project: ```bash bm project default "personal" @@ -69,7 +73,7 @@ Projects stay separate, but you can still search several of them at once when yo Search my work and research projects for notes about rate limiting. ``` -Behind the scenes, `search_notes` takes `search_all_projects=True` or, as of [v0.24](/whats-new/v0-24), a `projects` list of names (or project ids) to search together. An unknown name is an error rather than a silent skip. Results from all the chosen projects come back as one ranked list, and each hit says which project it came from so the AI can read it from the right place. +Behind the scenes, `bm_search` takes `all_projects=True` or, as of [v0.24](/whats-new/v0-24), a `projects` list of names (or project ids) to search together. An unknown name is an error rather than a silent skip. Results from all the chosen projects come back as one ranked list, and each hit says which project it came from so the AI can read it from the right place. ## Folders within a project diff --git a/content/07.concepts/3.observations-and-relations.md b/content/07.concepts/3.observations-and-relations.md index d271b61..ac067ef 100644 --- a/content/07.concepts/3.observations-and-relations.md +++ b/content/07.concepts/3.observations-and-relations.md @@ -3,6 +3,10 @@ title: Observations and relations description: How Basic Memory turns your notes into searchable facts and a connected knowledge graph — and why you rarely need to write the syntax yourself. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Basic Memory notes aren't just text. Each note can contain **observations** (individual facts) and **relations** (links to other notes). Together, they turn a folder of Markdown files into a searchable, navigable knowledge graph. The important thing to know up front: **you don't need to write these by hand.** When you ask your AI assistant to write a note, it creates observations and relations automatically. You should understand what they are so you can read your notes and give feedback, but you never need to memorize the syntax. @@ -173,7 +177,7 @@ If you have a 2000-word architecture document with dozens of observations, a sea ### Knowledge graph navigation -Relations create a graph you can traverse. The `build_context` tool follows links between notes to assemble relevant information from across your knowledge base. When you ask your AI assistant about a topic, it doesn't just find one note — it follows relations to pull in connected context. +Relations create a graph you can traverse. The `bm_context` tool follows links between notes to assemble relevant information from across your knowledge base. When you ask your AI assistant about a topic, it doesn't just find one note — it follows relations to pull in connected context. For example, if you ask about a system design decision, the assistant might start with the design note, follow a `depends_on` link to the caching strategy, then follow a `relates_to` link to the performance requirements. That chain of connections gives it a much richer understanding than any single note would. @@ -185,7 +189,7 @@ Categories, tags, and relation types give your AI assistant structured metadata If you want to ensure consistency across similar notes, Basic Memory's schema system (introduced in v0.19) can validate that notes of a certain type contain the observations and relations you expect. -For example, you could define a schema that requires every "person" note to have a `name` observation and a `works_at` relation. You can then validate notes on demand — ask your AI to check them (the `schema_validate` tool) or run `bm schema validate` — and the report flags anything that's missing. Validation warns rather than blocking writes. +For example, you could define a schema that requires every "person" note to have a `name` observation and a `works_at` relation. You can then validate notes on demand — ask your AI to check them (the `bm_schema(command="validate")` tool) or run `bm schema validate` — and the report flags anything that's missing. Validation warns rather than blocking writes. ::note See [Schema System](/concepts/schema-system) for details on defining and applying schemas. diff --git a/content/07.concepts/4.memory-urls.md b/content/07.concepts/4.memory-urls.md index 1997cee..7d95b6b 100644 --- a/content/07.concepts/4.memory-urls.md +++ b/content/07.concepts/4.memory-urls.md @@ -3,6 +3,10 @@ title: Memory URLs description: Address notes directly with memory:// paths, including project-prefixed routing. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Basic Memory is a knowledge base that you and your AI share. Memory URLs are how notes are addressed — by your AI, by CLI commands, and by links between notes. Every note in Basic Memory has an address — a `memory://` URL that works like a web link for your knowledge base. Your AI uses these behind the scenes to read notes, follow connections, and build context. You'll see them in tool output and can use them directly when you want to point your AI at something specific. @@ -18,7 +22,7 @@ memory://auth-approaches-2024 memory://Auth Approaches 2024 ``` -Both a permalink and an exact note title resolve. Exact matches — file path, permalink, and title — are always tried first, including on project-prefixed URLs like `memory://main/Auth Approaches 2024`. `build_context` doesn't fall back to fuzzy matching: a URL that names no note returns nothing, and a title shared by more than one note is refused, so pass the permalink instead. +Both a permalink and an exact note title resolve. Exact matches — file path, permalink, and title — are always tried first, including on project-prefixed URLs like `memory://main/Auth Approaches 2024`. `bm_context` doesn't fall back to fuzzy matching: a URL that names no note returns nothing, and a title shared by more than one note is refused, so pass the permalink instead. ### By path @@ -65,13 +69,13 @@ The `project::note-path` form is treated as `project/note-path`, and the same sy Your AI uses memory URLs when reading notes, building context, and following links between notes. You can also use them directly in conversation — "read memory://docs/authentication" — or in CLI commands. -Behind the scenes, tools like `read_note` and `build_context` accept memory URLs as their primary input, and assistant workflows pass them between calls to maintain stable references. +Behind the scenes, tools like `bm_read` and `bm_context` accept memory URLs as their primary input, and assistant workflows pass them between calls to maintain stable references. --- ## Notes as MCP resources -As of [v0.24](/whats-new/v0-24), every `memory://` URL Basic Memory hands out is also a readable MCP resource. A client that supports `resources/read` can fetch `memory:///` and get the note's raw Markdown, frontmatter included. The identifier can be a permalink, title, or file path. An unknown note points you at `search_notes`, and a binary file points at `read_content`. +As of [v0.24](/whats-new/v0-24), every `memory://` URL Basic Memory hands out is also a readable MCP resource. A client that supports `resources/read` can fetch `memory:///` and get the note's raw Markdown, frontmatter included. The identifier can be a permalink, title, or file path. An unknown note points you at `bm_search`, and a binary file points at `bm_read`. Two other resource families share the scheme: diff --git a/content/07.concepts/6.schema-system.md b/content/07.concepts/6.schema-system.md index e51897b..0792b99 100644 --- a/content/07.concepts/6.schema-system.md +++ b/content/07.concepts/6.schema-system.md @@ -3,6 +3,10 @@ title: Schema System description: Define, validate, and evolve note structure in Basic Memory with schemas. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + In Basic Memory, your notes are Markdown files with structured information — facts (called [observations](/concepts/observations-and-relations)) and links to other notes (called [relations](/concepts/observations-and-relations)). A schema describes what a particular type of note should contain — like making sure every person note has a name. ::docs-video{src="/videos/docs-schema-system.mp4" poster="/videos/posters/docs-schema-system.png" alt="Schema validation catching a bad record, fixed with one sentence"} @@ -518,7 +522,7 @@ See the [CLI Reference](/reference/cli-reference) for full flag documentation. ### MCP tool parameters -See the [MCP Tools Reference](/reference/mcp-tools-reference) for full `schema_validate`, `schema_infer`, and `schema_diff` parameter tables. +See the [MCP Tools Reference](/reference/mcp-tools-reference) for full `bm_schema(command="validate")`, `bm_schema(command="infer")`, and `bm_schema(command="diff")` parameter tables. --- diff --git a/content/07.concepts/7.semantic-search.md b/content/07.concepts/7.semantic-search.md index 45e1c8a..24dd0ee 100644 --- a/content/07.concepts/7.semantic-search.md +++ b/content/07.concepts/7.semantic-search.md @@ -3,6 +3,10 @@ title: Semantic Search description: Meaning-based retrieval with vector and hybrid search in Basic Memory. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Most knowledge tools make you organize everything up front so you can find it later. Basic Memory takes the opposite approach — write naturally, and let search figure out the connections. ::docs-video{src="/videos/docs-semantic-search.mp4" poster="/videos/posters/docs-semantic-search.png" alt="Semantic search answering a plain-language question"} @@ -134,11 +138,11 @@ See [Metadata Search](/concepts/metadata-search) for the full operator reference ### Valid-time filters -Observations can carry a date qualifier that says when a fact holds — `- [decision] @effective:2026-06-10 ...` (see [Observations and Relations](/concepts/observations-and-relations#when-a-fact-holds-valid-time)). `search_notes` can filter on that authored time with `valid_at` (true at a date or instant), `valid_overlaps` (true at any point in a range), and `time_kind` (`effective`, `valid`, `occurred`, `due`, or `mentioned`): +Observations can carry a date qualifier that says when a fact holds — `- [decision] @effective:2026-06-10 ...` (see [Observations and Relations](/concepts/observations-and-relations#when-a-fact-holds-valid-time)). `bm_search` can filter on that authored time with `valid_at` (true at a date or instant), `valid_overlaps` (true at any point in a range), and `time_kind` (`effective`, `valid`, `occurred`, `due`, or `mentioned`): ```text You: "Which caching decisions were in effect on July 1st?" -AI: [search_notes("caching", valid_at="2026-07-01", time_kind="effective")] +AI: [bm_search("caching", valid_at="2026-07-01", time_kind="effective")] ``` These filters only match observations that carry a qualifier, and they compose with vector and hybrid search. Details are in [Metadata Search](/concepts/metadata-search#searching-by-valid-time). @@ -160,11 +164,11 @@ bm tool search-notes "error handling" --meta status=active ### Searching across projects -Search normally runs in one project. Pass `search_all_projects=True` to search every project, or `projects=["work", "research"]` to search a chosen set (new in v0.24). Results come back as a single ranking across the chosen projects, and each hit names its project. +Search normally runs in one project. Pass `all_projects=True` to search every project, or `projects=["work", "research"]` to search a chosen set (new in v0.24). Results come back as a single ranking across the chosen projects, and each hit names its project. ```text You: "Search my work and research projects for rate limiting" -AI: [search_notes("rate limiting", projects=["work", "research"])] +AI: [bm_search("rate limiting", projects=["work", "research"])] ``` --- @@ -554,7 +558,7 @@ title: MCP Tools Reference icon: i-lucide-wrench to: /reference/mcp-tools-reference --- -`search_notes` parameters and search modes. +`bm_search` parameters and search modes. :: ::card diff --git a/content/07.concepts/8.metadata-search.md b/content/07.concepts/8.metadata-search.md index 370fa9f..bd77a90 100644 --- a/content/07.concepts/8.metadata-search.md +++ b/content/07.concepts/8.metadata-search.md @@ -3,19 +3,23 @@ title: Metadata Search description: Filter and find notes by their YAML frontmatter — status, type, tags, priority, confidence, custom fields, and more. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Every note in Basic Memory has YAML frontmatter at the top. Metadata search lets you find notes by those fields — status, type, tags, custom fields, anything you put there. It's how you ask things like _"show me all in-progress specs tagged security"_ or _"find decisions made in the last quarter with priority high or critical"_ without scanning text. ::docs-video{src="/videos/docs-metadata-search.mp4" poster="/videos/posters/docs-metadata-search.png" alt="Filtering notes by frontmatter fields in Structured search"} :: -Metadata search is a parameter on the same [`search_notes`](/reference/mcp-tools-reference#search_notes) tool you use for text and [semantic search](/concepts/semantic-search). You can use it on its own, or combine it with a text query and tag filters. +Metadata search is a parameter on the same [`bm_search`](/reference/mcp-tools-reference#bm_search) tool you use for text and [semantic search](/concepts/semantic-search). You can use it on its own, or combine it with a text query and tag filters. ::tip Frontmatter is structured data. The richer your frontmatter, the sharper your search. A note with `type: meeting`, `status: open`, `priority: high`, and `attendees: [...]` is reachable from many more angles than one with just a title. :: ::note -Observation categories such as `[decision]`, `[rule]`, or `[follow-up]` are not frontmatter fields — see [Searching observations by category](#searching-observations-by-category) below instead of `metadata_filters`. +Observation categories such as `[decision]`, `[rule]`, or `[follow-up]` are not frontmatter fields — see [Searching observations by category](#searching-observations-by-category) below instead of `filters`. :: --- @@ -35,7 +39,7 @@ confidence: 0.85 --- ``` -A few fields have shortcuts in `search_notes` (`tags`, `status`, `type`), but all custom fields work the same way through `metadata_filters`. You can also reach into nested objects with **dot notation** — `schema.confidence` targets the `confidence` key inside a `schema` object. +Use `filters` for tags, status, and custom fields; `note_types` filters note types. You can also reach into nested objects with **dot notation** — `schema.confidence` targets the `confidence` key inside a `schema` object. ::note Field **names** must match the chars `A-Z a-z 0-9 _ -` (with `.` for nesting). Field **values** can be strings, numbers, booleans, dates, or lists. @@ -45,7 +49,7 @@ Field **names** must match the chars `A-Z a-z 0-9 _ -` (with `.` for nesting). F ## Filter syntax -`metadata_filters` is a JSON object. Each key is a field name; each value is either a literal (for equality) or an operator object. +`filters` is a JSON object. Each key is a field name; each value is either a literal (for equality) or an operator object. Multiple top-level keys combine with **AND** — all conditions must match. @@ -143,52 +147,30 @@ Several operators in one object AND together (`{"$gt": 0.5, "$lt": 1.0}`), and t --- -## Convenience shortcuts +## Tags and note types -`search_notes` exposes a few common metadata filters as top-level parameters: - -| Shortcut | Equivalent filter | -|----------|-------------------| -| `tags=["security"]` | `{"tags": ["security"]}` | -| `status="draft"` | `{"status": "draft"}` | -| `note_types=["spec", "decision"]` | type filter (any of) | - -You can also write a tag filter directly in the query string: +Use `filters={"tags": ["security"], "status": "draft"}` for frontmatter fields and `note_types=["spec", "decision"]` for note types. The old top-level `tags` and `status` MCP parameters are removed. ```python -# All equivalent -search_notes("tag:security") -search_notes(tags=["security"]) -search_notes(metadata_filters={"tags": ["security"]}) +bm_search(filters={"tags": ["security", "oauth"]}) +bm_search(note_types=["spec", "decision"], filters={"status": "draft"}) ``` -Multiple tags in the shorthand mean _all of them_: - -```python -search_notes("tag:tier1,alpha") # comma-separated -search_notes("tag:tier1 tag:alpha") # repeated tag: tokens -# Both require BOTH tags to be present. -``` - -A bare word after a `tag:` token isn't a tag — `"tag:tier1 alpha"` filters on `tier1` and treats `alpha` as ordinary query text. - -If a key appears in both a shortcut and `metadata_filters`, the explicit filter wins. - --- ## Combining with text and semantic search -Metadata filters compose with everything else `search_notes` does. The text query and the filters apply together (AND): +Metadata filters compose with everything else `bm_search` does. The text query and the filters apply together (AND): ```python # OAuth-related notes that are still in progress -search_notes("OAuth", metadata_filters={"status": "in-progress"}) +bm_search("OAuth", filters={"status": "in-progress"}) # Pure metadata — no text query -search_notes(metadata_filters={"type": "spec", "status": "active"}) +bm_search(filters={"type": "spec", "status": "active"}) # Text + tag shortcut + metadata -search_notes("auth", tags=["security"], metadata_filters={"priority": {"$in": ["high", "critical"]}}) +bm_search("auth", filters={"tags": ["security"], "priority": {"$in": ["high", "critical"]}}) ``` See [Semantic Search](/concepts/semantic-search) for how text and vector modes interact. @@ -197,7 +179,7 @@ See [Semantic Search](/concepts/semantic-search) for how text and vector modes i ## From the CLI -`bm tool search-notes` mirrors the same surface: +The CLI retains its command names and shortcut flags: ```bash # Simple equality @@ -243,7 +225,7 @@ confidence: 0.6 --- ``` -| You want… | `metadata_filters` | +| You want… | `filters` | |-----------|--------------------| | All in-progress specs | `{"status": "in-progress", "type": "spec"}` | | Specs with confidence above 0.7 | `{"type": "spec", "confidence": {"$gt": 0.7}}` | @@ -251,24 +233,24 @@ confidence: 0.6 | Specs in confidence range [0.5, 0.9] | `{"type": "spec", "confidence": {"$between": [0.5, 0.9]}}` | | Decisions since April | `{"type": "decision", "date": {"$gte": "2026-04-01"}}` — dates compare as ISO strings | | Notes tagged both `security` AND `oauth` | `{"tags": ["security", "oauth"]}` | -| "OAuth" matches in still-open work | use `search_notes("OAuth", metadata_filters={"status": "in-progress"})` | +| "OAuth" matches in still-open work | use `bm_search("OAuth", filters={"status": "in-progress"})` | | Anything with nested `schema.confidence` ≥ 0.7 | `{"schema.confidence": {"$gte": 0.7}}` | --- ## Searching observations by category -Observation categories (`- [decision] ...`, `- [rule] ...`) live on observations, not in frontmatter — so they get their own filter, `categories`, instead of `metadata_filters`: +Observation categories (`- [decision] ...`, `- [rule] ...`) live on observations, not in frontmatter — so they get their own filter, `categories`, instead of `filters`: ```python # All decision observations, anywhere -search_notes(categories=["decision"]) +bm_search(categories=["decision"]) # Decisions mentioning auth -search_notes("auth", categories=["decision"], entity_types=["observation"]) +bm_search("auth", categories=["decision"], items=["observation"]) ``` -Matching is exact, and when you pass `categories` without `entity_types`, results default to observations. From the CLI: +Matching is exact, and when you pass `categories` without `items`, results default to observations. From the CLI: ```bash bm tool search-notes "auth" --entity-type observation --category decision @@ -285,7 +267,7 @@ Frontmatter dates such as `date` or `due_date` describe a whole note. When indiv - [decision] @effective:2026-07-27 Cache layer uses Memcached. ``` -`search_notes` has three filters for that authored time. They're about what the note *says* was true, separate from `after_date`, which filters by when content was indexed: +`bm_search` has three filters for that authored time. They're about what the note *says* was true, separate from `since`, which filters by when content was indexed: | Parameter | Value | Matches | |---|---|---| @@ -295,10 +277,10 @@ Frontmatter dates such as `date` or `due_date` describe a whole note. When indiv ```python # What cache decision was in effect on July 1st? -search_notes("cache", valid_at="2026-07-01", time_kind="effective") +bm_search("cache", valid_at="2026-07-01", time_kind="effective") # Everything due during Q3 -search_notes(valid_overlaps="[2026-07-01,2026-10-01)", time_kind="due") +bm_search(valid_overlaps="[2026-07-01,2026-10-01)", time_kind="due") ``` - `valid_at` and `valid_overlaps` can't be combined in one search. @@ -336,7 +318,7 @@ The authoring syntax is covered in [Observations and Relations](/concepts/observ ## Related -- [Search Notes (MCP Tools Reference)](/reference/mcp-tools-reference#search_notes) +- [Search Notes (MCP Tools Reference)](/reference/mcp-tools-reference#bm_search) - [Semantic Search](/concepts/semantic-search) — text, vector, and hybrid modes - [Schema System](/concepts/schema-system) — make required frontmatter fields explicit - [Knowledge Format](/concepts/knowledge-format) — the structure of a note diff --git a/content/07.concepts/9.documents-and-pdfs.md b/content/07.concepts/9.documents-and-pdfs.md index 6b1bb99..3ff45c4 100644 --- a/content/07.concepts/9.documents-and-pdfs.md +++ b/content/07.concepts/9.documents-and-pdfs.md @@ -3,6 +3,10 @@ title: Documents and PDFs description: How Basic Memory turns PDFs, Word, PowerPoint, and CSV files into searchable Markdown notes that stay linked to the original file. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Knowledge doesn't only live in notes. Reports, slide decks, papers, and spreadsheets sit in the same folders, and until now your AI could see them only as opaque files. As of [v0.24](/whats-new/v0-24), Basic Memory can extract a document's text into a Markdown note that sits next to the original file, so search finds what's inside the document and your AI can read it like any other note. --- @@ -22,7 +26,7 @@ Basic Memory indexes the project, extracts the file, and writes two notes: | **Extracted text** | `reports/q3-review.pdf.md` | The document's text as Markdown, next to the source file | | **Ingestion run** | `document-ingestion-runs/.md` | Provenance: which extractor ran, with what settings, against which bytes | -The original file is never modified. The extracted-text note is an ordinary Markdown file: full-text and semantic search index it, `read_note` reads it, and you can open it in any editor. +The original file is never modified. The extracted-text note is an ordinary Markdown file: full-text and semantic search index it, `bm_read` reads it, and you can open it in any editor. ``` reports/ @@ -104,7 +108,7 @@ Q3 Business Review Raw extracted text is searchable, but it doesn't add observations or relations to your knowledge graph — `bm_parse_semantics: false`. A PDF that happens to contain `- [note] ...` or `[[Something]]` won't flood your graph with accidental facts and links. -The one connection every extracted-text note does get is a **`derived_from`** relation to its source file. Basic Memory adds it from the note's `source` frontmatter at index time, so `build_context` can walk from the text to the original PDF and back. Don't write this relation into the body yourself. +The one connection every extracted-text note does get is a **`derived_from`** relation to its source file. Basic Memory adds it from the note's `source` frontmatter at index time, so `bm_context` can walk from the text to the original PDF and back. Don't write this relation into the body yourself. --- @@ -140,9 +144,9 @@ sources: ## Other files in your project -Files you don't extract are still part of the project. Images, PDFs, and other non-Markdown files are indexed as file entries you can list, read with `read_content`, link to, and move. As of v0.24 each one also records its content type and format. Moving one preserves its bytes exactly, and deleting one through Basic Memory removes it from storage. +Files you don't extract are still part of the project. Images, PDFs, and other non-Markdown files are indexed as file entries you can list, read with `bm_read`, link to, and move. As of v0.24 each one also records its content type and format. Moving one preserves its bytes exactly, and deleting one through Basic Memory removes it from storage. -Metadata filters in `search_notes` apply to Markdown notes only. +Metadata filters in `bm_search` apply to Markdown notes only. --- diff --git a/content/09.how-to/1.project-documentation.md b/content/09.how-to/1.project-documentation.md index a9aa7a7..28da2c6 100644 --- a/content/09.how-to/1.project-documentation.md +++ b/content/09.how-to/1.project-documentation.md @@ -3,6 +3,10 @@ title: Code Project Documentation description: Keep living project documentation alongside your code using Basic Memory and your AI assistant --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Basic Memory turns your project's `docs/` folder into a shared knowledge base that both you and your AI can read and write. Architecture decisions, API docs, coding patterns -- they all live as markdown files right next to your code, connected through a knowledge graph that makes them easy to find and keep current. ## Setting Up @@ -13,7 +17,7 @@ Create a project for your documentation — ask your AI, and it works the same o Create a new project called "my-project-docs" ``` -The AI calls `create_memory_project` behind the scenes. +The AI calls `bm_project(command="create")` behind the scenes. **Cloud is a great home for project docs**: browse and edit them in the [web app](/cloud/web-app), give the whole [team](/teams/about) (and their agents) access, and publish any page externally with a [share link](/cloud/shared-notes). Prefer docs living inside the repo? On a local install, point the project at your `docs/` folder instead: diff --git a/content/09.how-to/2.writing-organization.md b/content/09.how-to/2.writing-organization.md index d3b8d0a..deb6f56 100644 --- a/content/09.how-to/2.writing-organization.md +++ b/content/09.how-to/2.writing-organization.md @@ -3,6 +3,10 @@ title: Organizing Notes for Writing description: Organize a writing project in Basic Memory — characters, plots, research, and drafts in a knowledge base your AI can help you navigate --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Basic Memory is a knowledge base that you and your AI share. You write notes in markdown, and they become a connected graph that both of you can read, search, and build on. For writing projects — novels, screenplays, nonfiction — this means your characters, plot arcs, research, and drafts all live in one place where your AI can help you stay organized across hundreds of pages. This page walks through setting up a writing project, developing characters and plot, tracking research, and using schemas and search to keep everything consistent as the project grows. @@ -94,7 +98,7 @@ You: "What do we know about Sarah's weaknesses? I want to make sure they create real obstacles in the plot." ``` -The AI reads the existing note, adds to it with `edit_note`, and connects it to related notes in your project. Because notes can't be accidentally overwritten (the AI uses `edit_note` for updates), your polished character work stays safe. +The AI reads the existing note, adds to it with `bm_edit`, and connects it to related notes in your project. Because notes can't be accidentally overwritten (the AI uses `bm_edit` for updates), your polished character work stays safe. ### Character Relationships diff --git a/content/09.how-to/4.note-taking.md b/content/09.how-to/4.note-taking.md index a1a75f5..8ac1565 100644 --- a/content/09.how-to/4.note-taking.md +++ b/content/09.how-to/4.note-taking.md @@ -3,6 +3,10 @@ title: Note Taking description: How to use Basic Memory for collaborative note-taking — capture notes in markdown, let your AI enhance and connect them, then find anything later with semantic search. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Basic Memory is a knowledge base that you and your AI share. You write notes in markdown. Your AI reads and writes notes through MCP tools. Every note becomes part of a connected knowledge graph that both of you can search, enhance, and build on over time. This page covers practical note-taking workflows — from quick capture to structured meeting notes to finding things weeks later. @@ -89,7 +93,7 @@ tags: [marketing, strategy, q1-planning] Notice the `type: meeting` in the frontmatter. Note types help you categorize and filter your knowledge base — meeting, lecture, idea, code-review, or whatever types make sense for your work. -Behind the scenes, the AI enhances your existing note with `edit_note` rather than creating a new one. Basic Memory's write protection means the AI won't accidentally overwrite your content — it adds to it. +Behind the scenes, the AI enhances your existing note with `bm_edit` rather than creating a new one. Basic Memory's write protection means the AI won't accidentally overwrite your content — it adds to it. ## Learning and Lecture Notes @@ -184,7 +188,7 @@ Notes don't have to be finished in one sitting. Basic Memory supports an iterati > "Review the e-commerce planning note and add connections to our previous e-commerce projects, Stripe integration docs, and Q2 revenue goals." -Each iteration uses `edit_note` to append or update sections. The note grows through contributions from both you and the AI — and in [Basic Memory Cloud](/cloud/file-history), every save is a version you can step back through. +Each iteration uses `bm_edit` to append or update sections. The note grows through contributions from both you and the AI — and in [Basic Memory Cloud](/cloud/file-history), every save is a version you can step back through. ## Best Practices diff --git a/content/10.reference/2.mcp-tools-reference.md b/content/10.reference/2.mcp-tools-reference.md index 3bef4f5..27f5590 100644 --- a/content/10.reference/2.mcp-tools-reference.md +++ b/content/10.reference/2.mcp-tools-reference.md @@ -1,619 +1,885 @@ --- title: MCP Tools Reference -description: Current MCP tool reference for Basic Memory local and cloud usage. +description: Basic Memory 1.0 MCP tools, parameters, responses, and migration guidance. --- ::note -This is a technical reference for developers and AI integrations. For a conceptual overview of what Basic Memory can do, see [What is Basic Memory](/start-here/what-is-basic-memory). +This page targets the upcoming 1.0 tool surface. It does not announce a release or a hosted rollout. Install a build with the `bm_*` tools, and check your connected server's tool list. See [Migrating to 1.0](/reference/migrating-to-1-0) for the changes from v0.24. :: -This page lists core Basic Memory MCP tools and their current parameters as of v0.24. For what changed in this release, see [What's New in v0.24](/whats-new/v0-24) and [Upgrade to v0.24](/whats-new/v0-24-upgrade). +The twelve core tools share target, routing, pagination, and error conventions. Most default to text; `bm_context` defaults to JSON. Pass `output_format="json"` for machine-readable results. -::tip -Project resolution order is: constrained project env (`BASIC_MEMORY_MCP_PROJECT`) -> explicit `project` / `project_id` parameter -> `default_project` fallback. There is no session "active project": MCP requests carry no session state, so a call without `project` always uses the default project, locally and in the cloud. Pass `project` on every call that targets anything else. -:: +Pass a project name, `workspace/project`, or the project's external UUID as `project`. Get IDs from `bm_project(command="list")`. A constrained server wins over a supplied project; otherwise use an explicit route when several projects are addressable. Unqualified note/search calls are refused in that case. `bm_list(path="/")` without a project lists project mounts. -::tip -**The manual is built in.** Every tool has a manual page served over MCP. `memory://man` is the index and `memory://man/` is one page (for example `memory://man/search-notes(3)`). The `man` tool and `bm man ` read the same pages. When a tool's description leaves a question open or a call fails, read its page. -:: +## Errors and revision guards -### Common parameters +Refusals are MCP tool errors (`isError: true`). In JSON mode their text contains `error`, `message`, and optionally `try_instead`. Codes include `NOT_FOUND`, `AMBIGUOUS`, `ALREADY_EXISTS`, `REVISION_CONFLICT`, and `INVALID_ARGUMENTS`. A missing read, edit, or delete is an error. Only `bm_write` creates notes. -Most tools accept these optional parameters. They are **not** repeated in every table below. +`OUTCOME_UNKNOWN` means a request may have landed: inspect the note before retrying. `PARTIAL_FAILURE` means some items in a directory operation changed. Neither means nothing was written. -| Parameter | Type | Default | Notes | -|---|---|---|---| -| `project` | string | resolved via fallback | Project name. Constrained project env → explicit parameter → `default_project` config | -| `project_id` | string | — | Project external UUID from `list_memory_projects`. Prefer this when the same project name exists in more than one workspace | -| `output_format` | `"text"` or `"json"` | `"text"` | Machine-readable JSON output. `build_context` defaults to `"json"`; most other tools default to `"text"` | +Read a note's full `checksum` and pass it as `expected_checksum` to guard a write, edit, move, or delete. On conflict, read again and reconcile. `bm_write(expected_checksum=...)` implies overwrite; explicitly setting `overwrite=false` contradicts it. -`workspace` is not a universal parameter. It appears on the note-writing tools (`write_note`, `edit_note`) and on the tools that create or delete cloud projects. For ordinary read, search, and schema calls, use `project` or `project_id`. +```python +note = bm_read(identifier="plans/launch.md", project="main", output_format="json") +bm_write(identifier="plans/launch.md", content="Updated content", project="main", + expected_checksum=note["checksum"], output_format="json") +``` -### Errors and refusals +## Tools -Since v0.24, a refused or failed write is an MCP tool error (`isError: true`), never an ordinary result. This covers `write_note` (note already exists without `overwrite`, revision conflict, moved note, directory outside the project), `edit_note` (missing section, mismatched replacement count, concurrent-modification conflict, revision conflict), `delete_note`, and `move_note`. Nothing is written when a call is refused, so a client that checks `isError` can safely retry. In JSON mode, the error message is the same payload as before (for example `action: "conflict"`, `error: "NOTE_ALREADY_EXISTS"`). +## `bm_read` -`delete_note` still returns `false` (not an error) for a note that does not exist. +### NAME -### Revision guards +**bm-read** — read a note or file by path, permalink, memory:// URL or title -`write_note` (with `overwrite=true`) and `edit_note` accept `expected_checksum`: the full `checksum` from a JSON `read_note`, `write_note`, or `edit_note` result. The write applies only while the note is still that revision. Otherwise nothing changes and the tool error is a revision conflict. A `write_note` conflict in JSON mode looks like this (`edit_note` returns the same fields with `operation` and `fileCreated` in place of `action`): +### SYNOPSIS -```json -{ - "title": "Meeting Notes", - "permalink": "main/meetings/meeting-notes", - "file_path": "meetings/Meeting Notes.md", - "checksum": null, - "action": "conflict", - "error": "NOTE_REVISION_CONFLICT", - "currentChecksum": "" -} +``` +bm_read(identifier, section=None, start_line=None, end_line=None, + max_tokens=None, include_frontmatter=True, include_content=True, + output_format="text", project=None) ``` -`checksum` is `null` because nothing was written; retry against `currentChecksum` after re-reading the note. A guarded `append` or `prepend` on a note that no longer exists is a conflict, not an auto-create, and a checksum for a path no note owns is a conflict too, so a note deleted since you read it is never silently recreated. Without `expected_checksum`, `overwrite=true` still replaces unconditionally. +### DESCRIPTION -To refresh a stale checksum without reading the body, call `read_note(identifier=..., include_content=False)`. Text output shows only the first 8 characters of a checksum, so use JSON output when you plan to guard a write. +Returns one note's Markdown, frontmatter included. The identifier can be a file +path (`notes/plan.md`), a permalink, a `memory://` URL, an exact title, an +external id, or a project-qualified path (`research/notes/plan.md`). ---- +Read part of a long note with `section` (a heading), `start_line`/`end_line`, +or `max_tokens`. Line numbers count the whole file, frontmatter included, so +they match `cat -n`. A partial read says which lines it returned and where to +continue. -## Knowledge tools +`include_content=false` returns only the title, paths, checksum and +`updated_at`. The checksum is the `expected_checksum` that bm_write, bm_edit, +bm_move and bm_delete take to guard a change. -### `write_note` +Images come back as images and other binary files as documents. A missing note +is a `NOT_FOUND` error; find notes with bm_search. -Create or update a markdown note. +The shell counterpart is cat(1). -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `title` | string | Yes | Note title | -| `content` | string | Yes | Markdown body | -| `directory` | string | Yes | Relative folder path. Since v0.23.2, each segment resolves to a unique existing case-insensitive folder match | -| `tags` | list[string] or string | No | Comma-separated string accepted | -| `note_type` | string | No | Default `note`. Sets the `type` frontmatter field (e.g., `person`, `meeting`, `decision`) | -| `metadata` | object or JSON string | No | Extra frontmatter fields merged into the note's YAML header | -| `overwrite` | boolean | No | Default follows `write_note_overwrite_default` config (`false` unless changed). Pass `true` to replace an existing note; without it, writing to an existing path is a tool error | -| `expected_checksum` | string | No | With `overwrite=true`, replace the note only while it is still this revision. See [Revision guards](#revision-guards) | -| `workspace` | string | No | Cloud workspace to write into (name or tenant ID) | +### PARAMETERS -The `note_type` parameter controls the `type` field in frontmatter, which is used for schema resolution and filtering. A `type:` in frontmatter inside `content` takes precedence over `note_type`. The `metadata` parameter accepts any key-value pairs that get written directly into the note's frontmatter — useful for custom fields like `status`, `priority`, or `due_date`. `write_note` does not add an H1 for you; include `# Title` in `content` if the note should open with one. +- **identifier** (string, required) — The note or file: a file path ('notes/plan.md'), permalink, memory:// URL, exact title, external id, or '/path'. +- **section** (string | null, optional, default: None) — A heading to read: "Decisions", "Auth/Decisions" for a heading under "Auth", or "Decisions[1]" for the second "Decisions" heading. +- **start_line** (integer | null, optional, default: None) +- **end_line** (integer | null, optional, default: None) +- **max_tokens** (integer | null, optional, default: None) — Approximate token budget. Longer content is cut at a section or paragraph boundary, and the result says which line to continue from. +- **include_frontmatter** (boolean, optional, default: True) — Include the YAML frontmatter in a whole-note read. +- **include_content** (boolean, optional, default: True) — False returns only title, paths, checksum and updated_at. +- **output_format** (optional, default: "text") +- **project** (string | null, optional, default: None) — Project name, 'workspace/project', or project external id. With several projects, pass an explicit scope or a project-qualified target. -Aliases accepted for `directory`: `folder`, `dir`, and `path`. +### EXAMPLES -**What `overwrite=true` does to frontmatter.** The body is replaced. Frontmatter keys this write sets (title, type, tags, metadata, or frontmatter in `content`) replace the old values; keys only the existing note has (custom fields) are kept. Existing frontmatter that cannot be parsed is discarded. To remove a key, use `edit_note` or edit the file. +``` +bm_read(identifier="plans/launch-plan.md", project="demo") +# → --- +# title: launch-plan +# type: plan +# permalink: demo/plans/launch-plan +# ... +# # Launch Plan +# ... + +bm_read(identifier="plans/launch-plan.md", section="Decisions", project="demo") +# → Lines 15-18 of 21 (document, including frontmatter); next: start_line=19, end_line=21 +# 15: ## Decisions +# 16: +# 17: - [decision] one PR per tool group +# 18: + +bm_read(identifier="plans/launch-plan.md", include_content=False, + output_format="json", project="demo") +# → {"title": "launch-plan", "permalink": "demo/plans/launch-plan", +# "file_path": "plans/launch-plan.md", "checksum": "13e0d14c…", +# "updated_at": "2026-10-23T14:47:04.550062-05:00"} + +bm_read(identifier="demo/plans/launch-plan.md", start_line=1, end_line=4) +# → Lines 1-4 of 21 (document, including frontmatter); next: start_line=5, end_line=8 +# 1: --- +# 2: title: launch-plan +# ... + +bm_read(identifier="plans/missing.md", project="demo") +# → error: NOT_FOUND: No note matches 'plans/missing.md' in project 'demo'. +# Try instead: bm_search(query='plans/missing.md') +``` -**Similar existing notes.** When `write_note` creates a new note, it checks the semantic index for notes that look like it and, if any match closely, appends a "Similar existing notes" section asking whether you meant to write to one of those instead. Options are 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 scores are shown, notes the new note already links to are skipped, and nothing is changed on your behalf. +### GOTCHAS -Results report the note's real checksum and end with `[Project: 'name']`, noting when no project was given and the default was used. +- With more than one project, an unqualified identifier is refused even when a + default project is set. Pass `project`, or qualify the path (`demo/plans/...`). +- A section read returns numbered lines, like `start_line`/`end_line`; a whole + note comes back without line numbers. -Folder casing resolution uses known indexed directories, so local and Cloud writes behave identically. Exact matches win; a unique case-insensitive match reuses the existing spelling; no match creates the folder as requested; and existing case-variant siblings keep exact-match behavior. +### SEE ALSO -### `read_note` +- see_also [[cat(1)]] +- see_also [[head(1)]] +- [bm_search](#bm_search) +- [bm_edit](#bm_edit) +- [bm_context](#bm_context) -Read note content by title/permalink/memory URL. +## `bm_write` -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `identifier` | string | Yes | Title, permalink, or `memory://...` | -| `page` | integer | No | Pagination page number (for fallback search suggestions) | -| `page_size` | integer | No | Results per page | -| `include_frontmatter` | boolean | No | Default `false`. When `true`, includes YAML frontmatter in output | -| `start_line` | integer | No | First document line to read (1-based, inclusive). Lines count the full Markdown, frontmatter included, matching `cat` | -| `end_line` | integer | No | Last line to read (inclusive). Omit to read to the end | -| `include_content` | boolean | No | Default `true`. Set `false` to return only title, permalink, file path, full checksum, and `updated_at`, without the body. Cannot be combined with `start_line` / `end_line` | -| `review_mode` | `structured` or `raw` | No | Cloud only; default `structured`. Returns clean prose and typed review threads, or exact persisted CriticMarkup in `raw` mode | +### NAME -With `start_line` or `end_line`, text output is numbered and JSON carries the range coordinates, `has_more`, and `next_start_line` / `next_end_line` for the next read. Reversed or invalid ranges fail; edits between calls can shift line numbers. +**bm-write** — create or replace a note -JSON output includes `checksum`, the revision that `write_note` and `edit_note` compare against when you pass `expected_checksum`. A note that does not exist returns `error: "NOTE_NOT_FOUND"` in JSON. +### SYNOPSIS -```text -read_note(identifier="specs/search-spec", start_line=120, end_line=180) -read_note(identifier="specs/search-spec", include_content=False, output_format="json") +``` +bm_write(content, identifier=None, title=None, directory=None, + note_type="note", tags=None, metadata=None, overwrite=None, + expected_checksum=None, output_format="text", project=None) ``` -On Cloud, structured JSON also returns `revision_checksum` and a `review` object containing summary counts and typed comment/suggestion items. Use that checksum for review decisions and for ordinary edits while review work is open. Raw mode is an inspection escape hatch; agents should not author or mutate CriticMarkup directly. +### DESCRIPTION -### `edit_note` +Writes a whole note. Give the file path as `identifier` (`notes/plan.md`), or a +`title` plus a `directory`. With a path the file lands exactly there. -Edit an existing note incrementally. +The title comes from the content's frontmatter `title:`, then the `title` +argument, then the file name. A `# Heading` in the content does not set it. -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `identifier` | string | Yes | Exact note identifier | -| `operation` | string | Yes | `append`, `prepend`, `find_replace`, `replace_section`, `insert_before_section`, `insert_after_section` | -| `content` | string | Yes | New content | -| `section` | string | Conditional | Required for `replace_section`, `insert_before_section`, `insert_after_section` | -| `find_text` | string | Conditional | Required for `find_replace` | -| `expected_replacements` | integer | No | Default `1` | -| `replace_subsections` | boolean | No | For `replace_section`; default `true` replaces nested subsections. Set `false` to preserve them | -| `metadata` | object | No | Merge frontmatter fields independently of the body operation; provided keys overwrite or add values | -| `workspace` | string | No | Cloud workspace containing the note (name or tenant ID) | -| `expected_checksum` | string | Conditional | Apply the edit only while the note is still this revision (see [Revision guards](#revision-guards)). Optional in general; required on Cloud notes with review threads, where stale or intersecting edits are rejected | +Writing over an existing note is an `ALREADY_EXISTS` error unless +`overwrite=true`. Pass `expected_checksum` (from bm_read) to replace a note only +if it is still the revision you read. To change part of a note, use bm_edit. -Aliases: `new_content`, `replacement`, `replace_with` for `content`; `section_heading`, `heading` for `section`; `find`, `old_text`, `old_content`, `search` for `find_text`. +Content may hold frontmatter, observations (`- [category] fact #tag`) and +relations (`- relation_type [[Other Note]]`). Observations and relations are +indexed after the write, so they show up in bm_context and bm_search moments +later. -::warning -**`replace_section` requires the exact heading.** Since v0.24, if the heading is not in the note, `replace_section` fails without writing instead of appending a duplicate section. A heading such as `## Open items #urgent` must be given in full. Use `append` to create a new section on purpose. -:: +### PARAMETERS -A failed or refused edit is an MCP tool error (`isError`), including a "modified concurrently" conflict when two clients edit one note. A refusal always comes from a write that rolled back, so a refused append is never in the note and is safe to retry. +- **content** (string, required) — The note's Markdown. Saved as given; it may start with frontmatter. +- **identifier** (string | null, optional, default: None) — File path for the note, e.g. 'notes/plan.md'; '.md' is added when missing. '/path' writes into another project. Use instead of title + directory. +- **title** (string | null, optional, default: None) — Note title. With `directory`, it also names the file. With `identifier`, it is used when the content has no frontmatter title. +- **directory** (string | null, optional, default: None) — Folder for a note addressed by title, e.g. 'meetings'; '/' is the root. +- **note_type** (string, optional, default: "note") — Frontmatter `type:`. A `type:` in the content wins. +- **tags** (array | string | null, optional, default: None) — Tags, as a list or 'a,b,c'. +- **metadata** (object | null, optional, default: None) — Extra frontmatter fields, merged into the note's frontmatter. +- **overwrite** (boolean | null, optional, default: None) — Replace a note that already exists. Default: the write_note_overwrite_default setting (false unless changed). +- **expected_checksum** (string | null, optional, default: None) — Replace the note only while it is still this revision (the checksum from bm_read). Implies overwrite=true. +- **output_format** (optional, default: "text") +- **project** (string | null, optional, default: None) — Project name, 'workspace/project', or project external id. With several projects, pass an explicit scope or a project-qualified target. -`append` and `prepend` create the note if it does not exist (unless `expected_checksum` is set). `find_replace`, `replace_section`, and the `insert_*_section` operations require an existing note. +### EXAMPLES + +``` +bm_write(identifier="plans/launch-plan.md", note_type="plan", tags=["release"], + content="# Launch Plan\n\n- [goal] ship the 1.0 tools #release\n" + "- depends_on [[Release Checklist]]\n", + project="demo") +# → Created plans/launch-plan.md +# title: launch-plan +# permalink: demo/plans/launch-plan +# checksum: 13e0d14c… + +bm_write(title="Release Checklist", directory="plans", + content="# Release Checklist\n\n- [step] tag the release\n", project="demo") +# → Created plans/Release Checklist.md + +bm_write(identifier="plans/launch-plan.md", content="# again", project="demo") +# → error: ALREADY_EXISTS: A note already exists at 'plans/launch-plan.md'. Nothing was written. +# Try instead: bm_edit(identifier='plans/launch-plan.md', command='append', content='...') +# to add to it, or bm_write(..., overwrite=true) to replace it +``` -`replace_section` follows Markdown heading levels. By default, a selected section extends through the next heading of the same or higher level, so replacing an `##` section also replaces its nested `###` subsections. Set `replace_subsections=false` to stop at the next heading of any level and keep nested subsections. +### GOTCHAS -`metadata` preserves unrelated frontmatter and the note body. It ignores `title` and `permalink`, which have dedicated handling, and does not support deleting keys. `metadata={"type": ...}` changes an existing note's type. +- A note written by path is titled after the file (`launch-plan`) unless the + content's frontmatter or the `title` argument says otherwise. +- With `title` plus `directory` the file name keeps the title's spelling + (`Release Checklist.md`); its permalink is the slug (`release-checklist`). +- A folder name the model would rewrite (unsupported characters) is refused + rather than silently changed. -On Cloud, `edit_note` preserves active review markers byte-for-byte. If an edit would change an anchored review range, it fails with the blocking review ID; use `review_note` to resolve or decide that item first. `write_note(overwrite=true)` is a full replacement and may remove review state. +### SEE ALSO -### `review_note` (Cloud) +- [bm_edit](#bm_edit) +- [bm_read](#bm_read) +- [bm_move](#bm_move) +- [bm_delete](#bm_delete) -Manage comments and suggestions on an existing Markdown note. Always begin with `read_note(review_mode="structured", output_format="json")`, and do not write CriticMarkup directly. +## `bm_edit` -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `identifier` | string | Yes | Exact title, permalink, file path, external ID, or `memory://` URL | -| `command` | `comment`, `suggest`, `reply`, `resolve`, `accept`, or `reject` | Yes | One review lifecycle action | -| `anchor` | object | Conditional | Required for `comment` and `suggest`. `exact` is a single-line prose selection; optional `prefix`, `suffix`, or one-based `occurrence` disambiguates repeated text | -| `body` | string | Conditional | Required for `comment` and `reply`; optional final reply when resolving a comment | -| `suggestion_kind` | `addition`, `deletion`, or `replacement` | Conditional | Required for `suggest` | -| `replacement` | string | Conditional | Required for addition and replacement suggestions; omit for deletion | -| `review_id` | string | Conditional | Required for `reply`, `resolve`, `accept`, and `reject`; obtain it from structured `read_note` or a prior mutation response | -| `expected_checksum` | string | Conditional | Required for `accept` and `reject`; optional stale-write guard for other commands | +### NAME -`comment` and `suggest` create attributed review records and return their IDs. `reply` works on comments or suggestions. `resolve` closes a comment without changing its anchored prose and can include a final reply. `accept` applies a pending suggestion; `reject` keeps the original prose. Every mutation is atomic and returns the new `revision_checksum`. +**bm-edit** — change part of an existing note -```text -# Create a replacement suggestion -review_note( - identifier="Launch plan", - command="suggest", - anchor={"exact": "Ship the beta on Friday."}, - suggestion_kind="replacement", - replacement="Ship the beta after the security review." -) +### SYNOPSIS -# After a fresh structured read, accept it -review_note( - identifier="Launch plan", - command="accept", - review_id="suggestion-id", - expected_checksum="checksum-from-read-note" -) ``` +bm_edit(identifier, command, content=None, section=None, find_text=None, + expected_replacements=1, replace_subsections=True, metadata=None, + expected_checksum=None, output_format="text", project=None) +``` + +### DESCRIPTION + +Edits a note in place. `command` picks the change: -See [Comments and Suggestions](/cloud/comments-and-suggestions) for the complete human-and-agent workflow. +- `append` / `prepend` — add `content` at the end or after the frontmatter. +- `find_replace` — replace the exact text `find_text` with `content`. It must + occur `expected_replacements` times (default 1). +- `replace_section`, `insert_before_section`, `insert_after_section` — act on the + `section` heading, named as bm_read takes it (`Decisions`, `Auth/Decisions`, + `Decisions[1]`). +- `set_metadata` — merge `metadata` into the frontmatter without touching the + body. `metadata` also merges with any other command. -### `move_note` +Pass `expected_checksum` (from bm_read) to edit only the revision you read; a +changed note is a `REVISION_CONFLICT` error carrying the current checksum. A +missing note is an error; create notes with bm_write. -Move a note or directory. +### PARAMETERS -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `identifier` | string | Yes | Note or directory identifier | -| `destination_path` | string | Conditional | Target path. Mutually exclusive with `destination_folder`; parent folders receive v0.23.2 casing resolution | -| `destination_folder` | string | Conditional | Target folder — moves note into folder preserving filename. Mutually exclusive with `destination_path`; each segment can reuse a unique case-insensitive folder match | -| `is_directory` | boolean | No | Default `false`. Set to `true` to move an entire directory | +- **identifier** (string, required) — The note or file: a file path ('notes/plan.md'), permalink, memory:// URL, exact title, external id, or '/path'. +- **command** (required) — The edit. +- **content** (string | null, optional, default: None) — The text to add or the replacement. Not used by set_metadata. +- **section** (string | null, optional, default: None) — The heading for section commands: "Decisions", "Auth/Decisions" for one under "Auth", or "Decisions[1]" for the second of two. +- **find_text** (string | null, optional, default: None) — For find_replace: the exact, case-sensitive text to replace. +- **expected_replacements** (integer, optional, default: 1) — For find_replace: how many times find_text must occur. +- **replace_subsections** (boolean, optional, default: True) — For replace_section: true replaces the section's subsections too; false stops at the first subsection heading. +- **metadata** (object | null, optional, default: None) — Frontmatter fields to set; other fields are kept. +- **expected_checksum** (string | null, optional, default: None) — Edit only while the note is still this revision (from bm_read). +- **output_format** (optional, default: "text") +- **project** (string | null, optional, default: None) — Project name, 'workspace/project', or project external id. With several projects, pass an explicit scope or a project-qualified target. -A failed or refused move is an MCP tool error. A move can rename a `.markdown` note to `.md`; other extension changes are refused. Directory moves move each note the same way `move_note` does for a single note, and apply the same cross-project guard. +### EXAMPLES -Folder casing resolution applies to note destinations, not directory renames. The response reports the actual landing path after a case-corrected move. Case-only folder renames and merging already duplicated case variants remain separate operations. +``` +bm_edit(identifier="plans/launch-plan.md", command="find_replace", + find_text="one PR per tool group", content="one PR per tool", project="demo") +# → Edited plans/launch-plan.md (find_replace) + +bm_edit(identifier="plans/launch-plan.md", command="set_metadata", + metadata={"status": "active"}, project="demo") +# → Edited plans/launch-plan.md (set_metadata) + +bm_edit(identifier="plans/launch-plan.md", command="append", + content="- [risk] the docs lag", project="demo") +# → Edited plans/launch-plan.md (append) + +bm_edit(identifier="plans/launch-plan.md", command="append", content="x", + expected_checksum="stale", project="demo") +# → error: REVISION_CONFLICT: 'plans/launch-plan.md' changed since you read it +# (current checksum 77a457af…). Nothing was changed. +# Try instead: bm_read(identifier='plans/launch-plan.md'), then retry with +# expected_checksum='77a457af…' +``` -### `delete_note` +### GOTCHAS -Delete a note or directory. +- `section` belongs to the section commands only; `append` with a `section` is + refused. Use `insert_after_section` to add under a heading. +- `set_metadata` refuses `title` and `permalink`: they are the note's identity. + Rename with bm_move. -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `identifier` | string | Yes | Note or directory | -| `is_directory` | boolean | No | Set to `true` to delete an entire directory and its contents | +### SEE ALSO -A refused delete (for example from a read-only API key, or a note with `locked: true` in its frontmatter) is an MCP tool error. A note that does not exist returns `false`. Deleting a note leaves relations that pointed at it in place as unresolved links, so recreating the target re-links them. +- [bm_read](#bm_read) +- [bm_write](#bm_write) +- [bm_move](#bm_move) -### `read_content` +## `bm_delete` -Read a file's content by path or permalink. Text files return as plain text; PNG, JPEG, and WebP images are resized/optimized for display (other image formats, GIF included, return "Unsupported image format"); other binary files return base64-encoded (subject to size limits). Useful for non-markdown files like images, PDFs, or attachments. Only exact paths, permalinks, titles, and ids resolve; a miss is "Resource not found" rather than a fuzzy match to some other file. +### NAME -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `path` | string | Yes | File path, permalink, or `memory://...` URL. Aliases: `file_path`, `filepath`, `file` | +**bm-delete** — delete a note or a directory -### `view_note` +### SYNOPSIS -Render a note as a formatted artifact for display in MCP clients. Returns the note content in a presentation-friendly format. +``` +bm_delete(identifier=None, path=None, recursive=False, + expected_checksum=None, output_format="text", project=None) +``` -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `identifier` | string | Yes | Note title, permalink, or `memory://...` URL | +### DESCRIPTION -### `open_basic_memory` (Cloud) +Deletes a note (`identifier`) or a directory (`path`). A directory delete +removes every file under it and needs `recursive=true`; without it the error +says how many entries the directory holds. The project root cannot be deleted. -Open the interactive Pocketbook in a compatible client. Use this when the user wants to see, browse, navigate, or interact with Basic Memory visually. Use `read_note`, `search_notes`, or `list_directory` instead when the assistant only needs data for its answer. +Pass `expected_checksum` (from bm_read) to delete a note only if it is still +the revision you read. A note that does not exist is an error. A delete cannot +be undone. -The default workspace and project resolve automatically. Do not call `list_memory_projects` first unless the user asks for project metadata or wants a non-default location. +### PARAMETERS -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `view` | `notes`, `note`, `folders`, `search`, or `graph` | No | Default `notes`. Destination screen | -| `workspace` | string | No | Workspace slug, name, or tenant ID. Omit for the default | -| `project` | string | No | Project name or qualified workspace/project name. Omit for the default | -| `project_id` | string | No | Exact external project UUID. Takes precedence over `project` | -| `directory` | string | No | Initial folder for `notes`, `folders`, `note`, or `search` views | -| `identifier` | string | Conditional | Required for `view="note"`; optional for `view="graph"` to focus a note. Accepts a title, permalink, `memory://` URL, or exact note UUID | -| `query` | string | No | Initial query for `view="search"` only | -| `graph_mode` | `overview` or `full` | No | Default `overview`. Used only with `view="graph"` | -| `note_mode` | `view` or `edit` | No | Default `view`. Use `edit` to open a note directly in the editor; used only with `view="note"` | +- **identifier** (string | null, optional, default: None) — The note to delete: a path, permalink, memory:// URL or exact title. +- **path** (string | null, optional, default: None) — The directory to delete, with everything in it. +- **recursive** (boolean, optional, default: False) — Required true to delete a directory and everything under it. +- **expected_checksum** (string | null, optional, default: None) — Delete the note only while it is still this revision (from bm_read). +- **output_format** (optional, default: "text") +- **project** (string | null, optional, default: None) — Project name, 'workspace/project', or project external id. With several projects, pass an explicit scope or a project-qualified target. -Examples: +### EXAMPLES -```text -open_basic_memory() -open_basic_memory(view="search", query="authentication") -open_basic_memory(view="folders", directory="research") -open_basic_memory(view="note", identifier="memory://main/plans/api", note_mode="edit") -open_basic_memory(view="graph", identifier="Architecture", graph_mode="full") ``` +bm_delete(path="old", project="demo") +# → error: INVALID_ARGUMENTS: 'old' is a directory with 1 entries at its top level. +# Deleting it removes everything under it. +# Try instead: bm_delete(path='old', recursive=true) -See [Pocketbook](/cloud/mcp-app) for the user workflow. +bm_delete(path="old", recursive=True, project="demo") +# → Deleted directory old (1 files) ---- +bm_delete(identifier="plans/launch-plan.md", expected_checksum="stale", project="demo") +# → error: REVISION_CONFLICT: 'plans/launch-plan.md' changed since you read it +# (current checksum 77a457af…). Nothing was deleted. +``` -## Search and context tools - -### `search_notes` - -Main search tool with text, vector, and hybrid modes plus structured filters. - -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `query` | string | No | Search query. Optional for metadata-only searches. Supports `tag:` shorthand (e.g., `"tag:security"`) | -| `page` | integer | No | Default `1` | -| `page_size` | integer | No | Default `10` | -| `search_type` | string | No | Default `None` — resolves to `default_search_type` from config if set, otherwise `hybrid` (`text` on a local host where the vector runtime cannot load). Queries using `AND`, `OR`, or `NOT` run as `text`. Options: `text`, `title`, `permalink`, `vector`, `semantic`, `hybrid` | -| `note_types` | list[string] or string | No | Case-insensitive frontmatter `type` filter (e.g., `["person", "meeting"]`). Aliases: `note_type`, `types` | -| `entity_types` | list[string] or string | No | Knowledge graph result filter: `entity`, `observation`, `relation`. Alias: `entity_type` | -| `categories` | list[string] or string | No | Exact observation category filter (e.g., `["decision", "rule"]`). When provided without `entity_types`, results default to observations. | -| `after_date` | string | No | Date/time filter (ISO format) | -| `metadata_filters` | object or JSON string | No | Structured frontmatter filters. See [operators](#metadata-filter-operators) below | -| `tags` | list[string] or string | No | Tag filter shorthand; comma-separated string accepted | -| `status` | string | No | Status shorthand | -| `min_similarity` | float | No | Overrides global `semantic_min_similarity` threshold per query (vector and hybrid only) | -| `valid_at` | string | No | Date (`2026-07-28`) or RFC 3339 instant. Returns sources whose authored valid range contains it. Aliases: `as_of`, `valid_on` | -| `valid_overlaps` | string | No | Range literal such as `[2026-06-10,2026-07-27)`, `(,2026-07-27]`, `[2026-06-10,)`. Mutually exclusive with `valid_at`. Aliases: `overlaps`, `valid_during` | -| `time_kind` | string | No | `effective`, `valid`, `occurred`, `due`, or `mentioned`. Narrows valid-time matching to one kind; usable on its own. Alias: `kind` | -| `compact` | boolean | No | Default `false`. Omit note bodies and matched excerpts; keep identifiers, metadata, relation targets, scores, and pagination | -| `search_all_projects` | boolean | No | Default `false`. Search every accessible project and workspace. Ignored when `project` or `project_id` is given | -| `projects` | list[string] | No | Search a chosen subset of projects by name (as `list_memory_projects` reports it) or external id. An unknown name is an error. Ignored when `project` or `project_id` is given | - -The `search_type` parameter controls the search strategy. `hybrid` is the default — it combines keyword and semantic search. `text` is keyword-only. `vector` and `semantic` are equivalent — pure meaning-based similarity. See [Semantic Search](/concepts/semantic-search) for details on each mode. +### SEE ALSO -::note -**Semantic search is always on in v0.24.** The `semantic_search_enabled` setting is removed and ignored if present. On hosts where the vector runtime cannot load (for example python.org Python on macOS), search falls back to keyword-only and a `vector` or `hybrid` query reports that semantic search is unavailable. See [Upgrade to v0.24](/whats-new/v0-24-upgrade). -:: +- [bm_move](#bm_move) +- [bm_read](#bm_read) +- [bm_list](#bm_list) -**Boolean queries.** A query containing uppercase `AND`, `OR`, or `NOT` without an explicit `search_type` runs as full-text, because the vector half of hybrid search cannot honor them. `NOT` excludes a term found anywhere in the note. +## `bm_move` -**Cross-project search.** `search_all_projects=true` and `projects=[...]` run one scoped query per database (one for a local install, one per cloud workspace) and rank results across projects together. Every hit on a page spanning projects carries `project` (JSON) or a `- project:` line (text), so follow-up calls can be routed to the right project. +### NAME -**Valid-time filters** query when a note *says* a claim holds — observation qualifiers like `- [decision] @effective:2026-06-10 The cache layer will use Redis.` — which is a different axis from `after_date` (when the note was indexed). Sources with no temporal qualifier are excluded from any valid-time query, and results default to observations. A malformed filter is refused rather than ignored. +**bm-move** — move or rename a note or a directory within its project -**Result fields.** Search results expose each note's stable `external_id` in JSON and Markdown output. Use it for web-app deep links or exact follow-up operations instead of parsing a title or permalink. Results also carry `content_length` and `content_truncated` so you can tell when a content preview is partial, and metadata values keep their JSON types (numbers, booleans, lists). +### SYNOPSIS -#### Metadata filter operators +``` +bm_move(destination, identifier=None, path=None, expected_checksum=None, + output_format="text", project=None) +``` -| Form | Example | Meaning | -|---|---|---| -| Equality | `{"status": "draft"}` | Field equals value | -| Null | `{"owner": null}` | Key absent or explicitly null | -| List | `{"tags": ["security", "oauth"]}` | Array contains all values | -| `$in` | `{"priority": {"$in": ["high", "critical"]}}` | Any of the listed values | -| `$gt` `$gte` `$lt` `$lte` | `{"schema.confidence": {"$gt": 0.7}}` | Comparison | -| `$between` | `{"score": {"$between": [0.3, 0.8]}}` | Inclusive range | -| `$contains` | `{"tags": {"$contains": "security"}}` | Array contains value (or list of values) | -| `$exists` | `{"owner": {"$exists": true}}` | Key has a non-null value | +### DESCRIPTION -The leading `$` is optional (`{"started": {"gte": "2026-01-01"}}` works), and several operators on one field AND together: `{"started": {"$gte": "2026-01-01", "$lt": "2026-02-01"}}`. Nested keys use dot notation. An unknown operator's error lists the valid ones. See [Metadata Search](/concepts/metadata-search). +Moves a note (`identifier`) or a directory (`path`). `destination` is the new +project-relative path; ending it with `/` moves into that folder under the +current name (`archive/`). A destination that names only the project +(`demo/`) is its root. -Cloud search projects reviewed notes as clean prose rather than CriticMarkup. JSON note results include `review_summary` counts (`open_comments`, `resolved_comments`, `pending_suggestions`, and `total_pending`). If a stale search fragment splits or exposes review markup during asynchronous index reconciliation, Cloud omits that hit instead of returning ambiguous storage bytes. +A note keeps its file extension (`.markdown` may become `.md`). A folder that +differs from an existing one only in case or Unicode form lands in the existing +folder, and the result names it. -Use `categories` for observation categories such as `[decision]`, `[rule]`, or `[follow-up]`. `metadata_filters` only checks note frontmatter, so `metadata_filters={"category": "decision"}` matches a frontmatter field named `category`, not observation categories. The singular `category` is accepted as an alias, and comma-separated strings work (`categories="decision,rule"`). Matching is exact, and categories only exist on observations — explicitly passing `entity_types=["entity"]` alongside `categories` returns nothing. +Pass `expected_checksum` (from bm_read) to move a note only if it is still the +revision you read. Moving into another project is refused: bm_read the note, +bm_write it there, then bm_delete the original. -::note -**Parameter aliases.** `search_notes` accepts `q`, `search`, or `text` as aliases for `query`; `all_projects` for `search_all_projects`; `page_number` for `page`; and `limit` / `per_page` for `page_size`. Search responses also include a result total for pagination. -:: +### PARAMETERS -### `build_context` +- **destination** (string, required) — New path, e.g. 'archive/plan.md'. A trailing '/' ('archive/') moves the note or directory into that folder under its current name. +- **identifier** (string | null, optional, default: None) — The note to move: a path, permalink, memory:// URL or exact title. +- **path** (string | null, optional, default: None) — The directory to move, with everything in it, e.g. 'drafts/2025'. +- **expected_checksum** (string | null, optional, default: None) — Move the note only while it is still this revision (from bm_read). +- **output_format** (optional, default: "text") +- **project** (string | null, optional, default: None) — Project name, 'workspace/project', or project external id. With several projects, pass an explicit scope or a project-qualified target. -Build context graph from a memory URL. Traverses the knowledge graph from a starting entity, following relations to a configurable depth. +### EXAMPLES -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `url` | string | Yes | `memory://` URL or path | -| `depth` | string or integer | No | Traversal depth, `1`–`5` (default `1`). Use `2` or `3` for broader context | -| `timeframe` | string | No | Time window filter (default `7d`). Accepts formats like `7d`, `1 week`, `30d`, `3 months` | -| `page` | integer | No | Default `1` | -| `page_size` | integer | No | Default `10` | -| `max_related` | integer | No | Maximum related entities per level (default `10`) | -| `compact` | boolean | No | Default `false`. Omit note bodies and observation lists (the server skips loading observations); keep identifiers, relation targets, and pagination. Use `read_note` for the notes you pick | -| `output_format` | string | No | Default `"json"`. Also accepts `"text"` for human-readable output | +``` +bm_move(identifier="plans/release-checklist.md", destination="archive/", project="demo") +# → Moved plans/Release Checklist.md to archive/Release Checklist.md -`build_context` resolves `memory://` URLs exactly: by permalink, title, or file path, with no fuzzy matching. A URL that names no note returns nothing, and a title URL that matches more than one note is refused (as `read_note` does) — pass the permalink instead. Since v0.24, compact JSON has no `observations` key. +bm_move(path="archive", destination="old", project="demo") +# → Moved directory archive to old (1 files) +``` -In text output, relations the primary note does not own name their source, for example `- [[Brewing Notes]] relates_to [[Bean Origins]]`. +### GOTCHAS -**TimeFrame examples:** +- A destination with no file extension is refused for a note; end it with `/` + to move into a folder. +- A directory move is file by file. If some files fail, the error lists which + moved and which did not; bm_list the destination before retrying. -| Value | Meaning | -|-------|---------| -| `7d` | Last 7 days | -| `30d` | Last 30 days | -| `1 week` | Last week | -| `3 months` | Last 3 months | -| `1 year` | Last year | +### SEE ALSO -### `recent_activity` +- [bm_delete](#bm_delete) +- [bm_write](#bm_write) +- [bm_list](#bm_list) -Recent activity in one project or cross-project discovery mode. When no project can be resolved at all (no parameter, no default project), it returns activity across all projects (discovery mode); otherwise it uses the resolved project. +## `bm_search` -Entity rows include `external_id` so clients can address the exact note returned. +### NAME -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `type` | string or list[string] | No | Filter by result type: `"entity"`, `"relation"`, `"observation"` | -| `depth` | integer | No | Relation traversal depth for context, `1`–`5` (default `1`) | -| `timeframe` | string | No | Time window (e.g., `7d`, `30d`, `1 week`) | -| `page` | integer | No | Default `1` | -| `page_size` | integer | No | Default `10` | +**bm-search** — search a project's notes, ranked by relevance ---- +### SYNOPSIS -## Project and filesystem tools +``` +bm_search(query=None, mode=None, filters=None, note_types=None, items=None, + categories=None, since=None, lines=None, max_matches=10, + identifier=None, path=None, compact=False, valid_at=None, + valid_overlaps=None, time_kind=None, min_similarity=None, + projects=None, all_projects=False, page=1, page_size=10, + output_format="text", project=None) +``` -### `list_memory_projects` +### DESCRIPTION + +Searches notes, observations and relations. `query` supports quoted phrases, +AND/OR/NOT and `tag:name`. `mode` picks `hybrid` (the default when semantic +search is available), `text`, `semantic`, `title` or `permalink` (globs with +`*`). A `memory://` URL as the query searches that permalink. + +Narrow with `filters` (frontmatter), `note_types`, `items` (notes, +observations, relations), `since` and `path` (a folder). `lines` returns each +hit's matching lines with that many lines of context, like grep; `identifier` +searches one note's lines. `projects` or `all_projects` search several projects +at once, and each hit's path names its project. + +Give one scope: `identifier`, `path`, a `memory://` query, `projects` and +`all_projects` each say where to search, and more than one is refused. Results +are paged; read full notes with bm_read. + +The shell counterpart is grep(1). + +### PARAMETERS + +- **query** (string | null, optional, default: None) — What to search for. Omit to search by filters alone. +- **mode** (string | null, optional, default: None) — Search mode. +- **filters** (object | null, optional, default: None) — Frontmatter filters as {field: condition}. Nested fields use dot notation ("schema.confidence"). A condition is a value for equality ({"status": "draft"}), null for absent-or-null ({"owner": null}), a list for contains-all ({"tags": ["a", "b"]}), or an operator object with $gt, $gte, $lt, $lte, $in, $between, $contains or $exists, e.g. {"priority": {"$in": ["high"]}}. Several operators on one field AND together. +- **note_types** (array | null, optional, default: None) — Frontmatter `type` values, e.g. ['person', 'meeting']. +- **items** (array | null, optional, default: None) — What to return: notes, observations, relations, or a mix. Default: notes. +- **categories** (array | null, optional, default: None) — Observation categories to match exactly, e.g. ['decision']. +- **since** (string | null, optional, default: None) — How far back to look: '7d', '24h', '2 days ago', 'last week', or a date. Windows shorter than one day are widened to one day. +- **lines** (integer | null, optional, default: None) — Return each hit's matching lines with this many lines of context (0-10), instead of a match excerpt. +- **max_matches** (integer, optional, default: 10) — Matching lines shown per note with `lines`. +- **identifier** (string | null, optional, default: None) — Search only this note; returns its matching lines. +- **path** (string | null, optional, default: None) — Search only this folder and its subfolders. +- **compact** (boolean, optional, default: False) — Omit note bodies and excerpts; keep identifiers and scores. +- **valid_at** (string | null, optional, default: None) — Specialist: only facts whose authored valid time contains this date. +- **valid_overlaps** (string | null, optional, default: None) — Specialist: only facts whose valid range overlaps '[start,end)'. +- **time_kind** (string | null, optional, default: None) — Specialist: effective, valid, occurred, due or mentioned. +- **min_similarity** (number | null, optional, default: None) — Override the semantic similarity floor (0-1). +- **projects** (array | null, optional, default: None) — Search these projects together. +- **all_projects** (boolean, optional, default: False) — Search every project you can access. +- **page** (integer, optional, default: 1) — Page number. +- **page_size** (integer, optional, default: 10) — Results per page (1-100). +- **output_format** (optional, default: "text") +- **project** (string | null, optional, default: None) — Project name, 'workspace/project', or project external id. With several projects, pass an explicit scope or a project-qualified target. + +### EXAMPLES -List projects and project stats. Returns name, path, default status, note count, external project ID, and sync/workspace metadata for each project. In cloud mode, this discovers projects across **every** accessible workspace, not just the current one — so a team's projects show up without switching workspaces first. +``` +bm_search(query="freeze", lines=0, mode="text", project="demo") +# → Results for 'freeze' in project 'demo': +# - plans/launch-plan.md | launch-plan +# 9: - [decision] freeze on Friday + +bm_search(query="launch", note_types=["plan"], compact=True, project="demo") +# → Results for 'launch' in project 'demo': +# - plans/launch-plan.md | launch-plan | score 1.212 + +bm_search(query="release", mode="text", page_size=1, output_format="json", project="demo") +# → {"results": [{"title": "release-checklist", "file_path": "plans/release-checklist.md", +# ...}], "current_page": 1, "page_size": 1, "total": 2, "has_more": true} +``` -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `output_format` | `"text"` or `"json"` | No | Use `"json"` when an agent needs exact `project_id` values for later tool calls | +### GOTCHAS -### `create_memory_project` +- `max_matches` bounds matching lines; without `lines` or `identifier` it is + refused. +- A search across projects reaches at most result 1000 (`page * page_size`). +- `hybrid` mode also returns notes that are only near in meaning. With `lines`, + use `mode="text"` when you want only notes that contain the words. -Create a project. +### SEE ALSO -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `project_name` | string | Yes | Name for the new project | -| `project_path` | string | Yes | Filesystem path for the project | -| `set_default` | boolean | No | Default `false`. Set to `true` to make this the default project | -| `workspace` | string | No | Cloud workspace name or slug to create the project in (cloud only) | +- see_also [[grep(1)]] +- [bm_find](#bm_find) +- [bm_read](#bm_read) +- [bm_context](#bm_context) -### `delete_project` +## `bm_context` -Remove a project from Basic Memory. Local projects keep their note files by default; cloud projects always have their files deleted. +### NAME -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `project_name` | string | Yes | Name of the project to remove | -| `delete_notes` | boolean | No | Default `false`. **Local projects only:** set to `true` to also delete the note files from disk. Ignored for cloud projects | -| `workspace` | string | No | Cloud workspace selector (slug preferred; tenant ID or unique name also accepted). Implies cloud routing: without cloud credentials the call fails fast | +**bm-context** — follow the knowledge graph from a note -::warning -**Cloud deletes always remove files (v0.24).** Deleting a cloud-routed project removes its cloud files whether or not `delete_notes` is set. They can be recovered only from a cloud snapshot (`bm cloud snapshot list`). See [Upgrade to v0.24](/whats-new/v0-24-upgrade). -:: +### SYNOPSIS -Cloud deletion applies when the MCP session is hosted or routed to cloud, or given a `workspace` selector. Hosted deletion is asynchronous: the tool response reports the project deletion status and background job ID when the cloud backend queues the work. The background job removes indexed and unindexed objects under the exact project prefix before completing the hard delete. Existing snapshots follow their separate retention lifecycle. +``` +bm_context(identifier, depth=1, since="7d", max_related=10, compact=False, + page=1, page_size=10, output_format="json", project=None) +``` -### `list_directory` +### DESCRIPTION -List directory contents with optional depth, glob filter, and sorting. +Returns a note, its observations, and the notes its relations reach, up to +`depth` hops (1-5). `identifier` is a path, permalink, `memory://` URL, or a +pattern such as `plans/*`. `since` limits related results to recent changes and +`max_related` caps them. -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `dir_name` | string | No | Directory path to list (root if omitted) | -| `depth` | integer | No | How many levels deep to list | -| `file_name_glob` | string | No | Glob pattern to filter returned files (e.g., `*.md`, `schemas/*`). Nonmatching directories are still traversed within `depth` | -| `sort` | string | No | Ordering: `title_asc`, `title_desc`, `updated_asc`, or `updated_desc`. Omit for the default filename ordering | -| `page` | integer | No | One-indexed page; default `1` | -| `page_size` | integer | No | Nodes per page; default `10`, maximum `200`. Aliases: `limit`, `per_page` | -| `output_format` | `"text"` or `"json"` | No | JSON includes structured pagination metadata | +`compact` returns the graph without note bodies or observations; read chosen +notes with bm_read. Output defaults to JSON because the result is a graph; text +output names each note's path and ends with the next-page call when there is +one. -Large listings are bounded. Continue with the next `page` instead of assuming one response contains every file. File nodes include `external_id` in both text and JSON output. +### PARAMETERS -Glob filtering applies to returned nodes, not traversal. For example, `depth=2` with `file_name_glob="*.md"` still finds Markdown files inside a folder whose own name does not match `*.md`. +- **identifier** (string, required) — Where to start: a note path, permalink, memory:// URL, or a pattern such as 'specs/*'. +- **depth** (integer, optional, default: 1) — Relation hops to follow (1-5). +- **since** (string, optional, default: "7d") — How far back to look: '7d', '24h', '2 days ago', 'last week', or a date. Windows shorter than one day are widened to one day. +- **max_related** (integer, optional, default: 10) — Most related results to return (0-100). +- **compact** (boolean, optional, default: False) — Omit note bodies and observations; keep the graph shape. +- **page** (integer, optional, default: 1) — Page number. +- **page_size** (integer, optional, default: 10) — Primary results per page (1-50). +- **output_format** (optional, default: "json") +- **project** (string | null, optional, default: None) — Project name, 'workspace/project', or project external id. With several projects, pass an explicit scope or a project-qualified target. -Explicit sorts (v0.23) order folders before files, apply deterministically before pagination, and use note titles for `title_*` modes. Folders have no canonical update timestamp, so `updated_*` modes keep folders name-ascending while still listing them first. +### EXAMPLES -### `list_workspaces` +``` +bm_context(identifier="plans/launch-plan.md", compact=True, output_format="text", + project="demo") +# → # Context: launch-plan +# +# ## launch-plan +# permalink: demo/plans/launch-plan +# path: plans/launch-plan.md +# +# ### Relations +# - depends_on [[Release Checklist]] +# +# ### Related +# - [[Release Checklist]] (plans/Release Checklist.md) +``` -List available cloud workspaces. Returns workspace names and tenant IDs for the authenticated user. +### SEE ALSO ---- +- [bm_read](#bm_read) +- [bm_search](#bm_search) -## POSIX read tools +## `bm_list` -v0.24 turns on six read-only tools modeled on familiar shell commands: `ls`, `find`, `grep`, `cat`, `tail`, and `man`. They sit alongside the rich tools above and return compact JSON, which makes them cheap for an agent to navigate with. They never write. +### NAME -::note -The POSIX tools are on by default. Set `enable_posix_tools=false` in config (or `BASIC_MEMORY_ENABLE_POSIX_TOOLS=false`) to hide them; the rich tools (`read_note`, `search_notes`, `list_directory`) cover the same ground. -:: +**bm-list** — list one folder: its subfolders, then its files -**Projects are mount points.** `ls(path="/")` with no project lists your projects as directories. A path whose first segment names a project routes there, so `ls(path="research/notes")` and `cat(identifier="research/notes/topic.md")` read from the `research` project. The paths these tools return are project-qualified, so you can pass them straight back. An explicit `project` must agree with any path prefix. When more than one project is addressable, an unqualified path is refused instead of silently defaulting, so qualify the path or pass `project` (`grep` and `tail`, which take no path, need `project` in that case). +### SYNOPSIS -Every POSIX tool also accepts `project` and `project_id`. +``` +bm_list(path="/", glob=None, sort=None, page=1, page_size=10, + output_format="text", project=None) +``` -### `ls` +### DESCRIPTION -List one directory level. +Lists one level of a folder: subfolders first, then files with their title, +date and id. `bm_list(path="/")` with no project lists the projects you can +address; `/path` lists inside another project, and the paths that come +back carry the same prefix. -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `path` | string | No | Default `/`. `/` with no project lists projects; `/path` routes into that project | -| `page` | integer | No | Default `1` | -| `page_size` | integer | No | Default `10`, maximum `200` | +Filter files with `glob` and order them with `sort`. Results are paged; the text +output ends with the call for the next page. For a recursive search by name or +frontmatter, use bm_find. -### `find` +The shell counterpart is ls(1). -Recursively list files by name glob, or query notes by frontmatter metadata. +### PARAMETERS -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `path` | string | No | Default: project root. With `meta`, scopes results to this subtree | -| `name` | string | No | File-name glob such as `*.md`. Cannot combine with `meta` | -| `depth` | integer | No | Levels to recurse, `1`–`10` (default `10`). Cannot change alongside `meta` | -| `meta` | list[string] | No | Metadata predicates that must all hold (see below) | -| `fields` | list[string] | No | Frontmatter fields to return per hit (dot-paths allowed). Requires `meta`; replaces the note body with the note's identity plus these values | -| `page` | integer | No | Default `1` | -| `page_size` | integer | No | Default `10` | +- **path** (string, optional, default: "/") — A directory in the project, e.g. 'specs' or 'specs/active'. '/' is the project root; '/path' addresses another project. +- **glob** (string | null, optional, default: None) — File-name glob, e.g. '*.md' or '*meeting*'. +- **sort** (string | null, optional, default: None) — File order. Folders always come first. +- **page** (integer, optional, default: 1) — Page number. +- **page_size** (integer, optional, default: 10) — Results per page (1-100). +- **output_format** (optional, default: "text") +- **project** (string | null, optional, default: None) — Project name, 'workspace/project', or project external id. With several projects, pass an explicit scope or a project-qualified target. -Predicate forms: `status=active` (equality), `confidence>0.6` (also `>=`, `<`, `<=`), `priority in high,critical`, `tags has security,oauth` (array contains all), `score between 0.3,0.8` (inclusive), `owner=null` (missing or null). Keys accept dot-paths, and `note_type` aliases the frontmatter `type` key. Quote a value to force a literal string (`status="true"`). +### EXAMPLES -```text -find(path="research", meta=["status=active", "confidence>0.6"], fields=["title", "priority"]) +``` +bm_list(path="/") +# → Projects: +# 📁 demo /demo +# 📁 main /main + +bm_list(path="plans", project="demo") +# → Contents of 'plans': +# 📄 launch-plan.md plans/launch-plan.md | launch-plan | 2026-10-23 | id: 686e696d… +# 📄 Release Checklist.md plans/Release Checklist.md | Release Checklist | 2026-10-23 | id: 7bf40fbe… + +bm_list(path="demo/plans", sort="title_asc", output_format="json") +# → {"nodes": [{"name": "launch-plan.md", "file_path": "demo/plans/launch-plan.md", +# "type": "file", "title": "launch-plan", ...}, ...], "page": 1, "has_more": false} ``` -### `grep` +### GOTCHAS -Search note content in one project. `pattern` is matched as full-text keywords, not a regex, and a pattern found in no note returns no results. +- `glob` and `sort` apply to files in a folder; on the project listing at `/` + they are refused. -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `pattern` | string | Yes | Text to search for | -| `semantic` | boolean | No | Default `false`. Rank by meaning (hybrid semantic plus full-text) instead of keywords. Cannot combine with `context_lines` | -| `context_lines` | integer | No | `0`–`10`. Return case-insensitive matching lines with surrounding context and line numbers, merged into windows, instead of whole notes | -| `max_matches` | integer | No | Default `10` (`1`–`100`). Matching lines shown per note; requires `context_lines` | -| `page` | integer | No | Default `1` | -| `page_size` | integer | No | Default `10` (maximum `100` with `context_lines`) | +### SEE ALSO -When a note has more matches than `max_matches`, the result carries `next_match_line` for a targeted `cat` or `read_note` range read. +- see_also [[ls(1)]] +- [bm_find](#bm_find) +- [bm_read](#bm_read) -### `cat` +## `bm_find` -Print a note's content, optionally sliced. Returns the `read_note` JSON payload, including `checksum`. +### NAME -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `identifier` | string | Yes | Title, permalink, `memory://` URL, or `/path` (resolved exactly) | -| `start_line` | integer | No | First line (1-based, inclusive) | -| `end_line` | integer | No | Last line (inclusive) | -| `section` | string | No | Heading to read: `Decisions`, path form `Auth/Decisions` to disambiguate, or `Heading[1]` for the second duplicate. Cannot combine with `start_line` / `end_line` | -| `max_tokens` | integer | No | Approximate token budget. Longer content is cut at a section or paragraph boundary; the response carries `truncated` and `continue_line` | -| `include_frontmatter` | boolean | No | Default `true` | +**bm-find** — find files by name or notes by frontmatter, recursively -```text -cat(identifier="research/specs/auth.md", section="Decisions") -cat(identifier="research/specs/auth.md", max_tokens=800) +### SYNOPSIS + +``` +bm_find(path="/", name=None, filters=None, fields=None, depth=10, page=1, + page_size=10, output_format="text", project=None) ``` -### `tail` +### DESCRIPTION -Show the most recently changed notes in a project, newest first. Rows carry `type`, `title`, `permalink`, `file_path`, `created_at`, and `updated_at`. +Searches a folder and everything under it. With `name`, matches file names +against a glob (`*meeting*`). With `filters`, matches notes by frontmatter, +e.g. `{"status": "active"}` or `{"priority": {"$in": ["high"]}}`; `fields` +returns just those frontmatter values per note. `path` limits the search to a +folder, and `/` searches another project. -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `timeframe` | string | No | Default `7d`. Accepts `yesterday`, `2 days ago`, and similar | -| `lines` | integer | No | Default `10`, maximum `100` | +For ranked text or meaning search, use bm_search. -### `man` +The shell counterpart is find(1). -Read the Basic Memory manual: one page per MCP tool, with verified examples and gotchas. +### PARAMETERS -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `page` | string | No | Page reference. Any common spelling works: `search-notes(3)`, `3/search-notes`, `search_notes` | -| `query` | string | No | Search the manual. Mutually exclusive with `page`; needs a `manual` project | +- **path** (string, optional, default: "/") — A directory in the project, e.g. 'specs' or 'specs/active'. '/' is the project root; '/path' addresses another project. +- **name** (string | null, optional, default: None) — File-name glob, e.g. '*.md'. Not with `filters`. +- **filters** (object | null, optional, default: None) — Frontmatter filters as {field: condition}. Nested fields use dot notation ("schema.confidence"). A condition is a value for equality ({"status": "draft"}), null for absent-or-null ({"owner": null}), a list for contains-all ({"tags": ["a", "b"]}), or an operator object with $gt, $gte, $lt, $lte, $in, $between, $contains or $exists, e.g. {"priority": {"$in": ["high"]}}. Several operators on one field AND together. +- **fields** (array | null, optional, default: None) — Frontmatter fields to return per note (dot paths allowed), e.g. ["title", "priority"]. Needs `filters`. +- **depth** (integer, optional, default: 10) — Folder levels to search (1-10). +- **page** (integer, optional, default: 1) — Page number. +- **page_size** (integer, optional, default: 10) — Results per page (1-100). +- **output_format** (optional, default: "text") +- **project** (string | null, optional, default: None) — Project name, 'workspace/project', or project external id. With several projects, pass an explicit scope or a project-qualified target. -With no arguments, `man` returns the manual index. The same pages are MCP resources (see below) and print from the CLI with `bm man `. +### EXAMPLES ---- +``` +bm_find(path="demo/", name="*plan*") +# → Files under 'demo/' matching '*plan*': +# 📁 plans /demo/plans +# 📄 launch-plan.md demo/plans/launch-plan.md | launch-plan | … + +bm_find(path="demo/", filters={"status": "active"}, fields=["status"]) +# → 1 notes under 'demo/' match: +# - demo/plans/launch-plan.md | launch-plan | status='active' +``` -## MCP resources +### GOTCHAS -Basic Memory also answers the standard MCP `resources/read` request, so clients that browse resources can read notes and the manual without a tool call. +- A `name` glob matches folders as well as files, so `*plan*` also returns the + `plans` folder. -| URI | Returns | -|---|---| -| `memory:///` | A note's raw Markdown, frontmatter included. The path can be a permalink, title, or file path. Unknown notes point at `search_notes`; binary files point at `read_content` | -| `memory://man` | The manual index | -| `memory://man/` | One manual page, for example `memory://man/search-notes(3)`. Every page is also listed in `resources/list` with its summary | -| `memory:////info` | Project info as JSON | -| `memory://ai_assistant_guide` | A condensed guide to using Basic Memory well | +### SEE ALSO -Every `memory://` URL Basic Memory hands out in tool results is readable this way. See [Memory URLs](/concepts/memory-urls). +- see_also [[find(1)]] +- [bm_list](#bm_list) +- [bm_search](#bm_search) ---- +## `bm_project` -## Schema tools +### NAME -Tools for defining, validating, and evolving note structure. See [Schema System](/concepts/schema-system) for concepts and workflow. +**bm-project** — list, create, and show recent activity in projects -### `schema_validate` +### SYNOPSIS -Validate notes against their schema. Pass `note_type` to validate all notes of a type, or `identifier` to validate a specific note. +``` +bm_project(command, name=None, path=None, set_default=False, workspace=None, + since="7d", items=None, page=1, page_size=10, + output_format="text", project=None) +``` -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `note_type` | string | Conditional | Note type to validate (e.g., `person`). One of `note_type` or `identifier` required | -| `identifier` | string | Conditional | Specific note path or permalink to validate | -| `output_format` | `"text"` or `"json"` | No | Machine-readable validation report | +### DESCRIPTION -### `schema_infer` +`command` picks what to do: -Analyze existing notes of a type and suggest a schema based on common patterns. +- `list` — the projects you can address, grouped by workspace. +- `create` — add a project: `name`, `path`, optional `set_default` and + `workspace`. +- `recent` — what changed lately: `since`, `items`, paging. `project` picks the + project, else the default project; with no default, every project. JSON + output carries `page`, `page_size` and `has_more`, plus `guidance` for any + project that was never indexed. -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `note_type` | string | Yes | Note type to analyze (e.g., `person`) | -| `threshold` | float | No | Minimum field frequency for inclusion (default `0.25`) | -| `output_format` | `"text"` or `"json"` | No | Machine-readable inference report | +bm_project never deletes; bm_project_delete does, and only when the server +enables it. -### `schema_diff` +The shell counterpart for `recent` is tail(1). -Compare a schema definition against actual note usage to detect drift. +### PARAMETERS -| Parameter | Type | Required | Notes | -|---|---|---|---| -| `note_type` | string | Yes | Note type to compare (e.g., `person`) | -| `output_format` | `"text"` or `"json"` | No | Machine-readable drift report | +- **command** (required) — What to do. +- **name** (string | null, optional, default: None) — For create: the new project's name. +- **path** (string | null, optional, default: None) — For create: the folder that holds the project's notes. +- **set_default** (boolean, optional, default: False) — For create: make the new project the default. +- **workspace** (string | null, optional, default: None) — In Cloud: the workspace slug, name or id that holds the project. +- **since** (string, optional, default: "7d") — How far back to look: '7d', '24h', '2 days ago', 'last week', or a date. Windows shorter than one day are widened to one day. +- **items** (array | null, optional, default: None) — What to return: notes, observations, relations, or a mix. Default: notes. +- **page** (integer, optional, default: 1) — Page number. +- **page_size** (integer, optional, default: 10) — Results per page (1-100). +- **output_format** (optional, default: "text") +- **project** (string | null, optional, default: None) — Project name, 'workspace/project', or project external id. With several projects, pass an explicit scope or a project-qualified target. ---- +### EXAMPLES -## Diagnostics +``` +bm_project(command="create", name="demo", path="/Users/me/demo", set_default=True) +# → ✓ Project 'demo' added successfully +# ... +# Project is now available for use in tool calls; indexing completed. + +bm_project(command="list") +# → Available projects: +# - demo (local) [b2a21302…] +# - main (local) [9b4d5944…] + +bm_project(command="recent", since="1d") +# → ## Recent Activity: demo (1d) +# **📄 Recent Notes & Documents (1):** +# • launch-plan (plans) [id: 686e696d…] +``` -### `basic_memory_diagnostics` +### SEE ALSO -Return a read-only Markdown report for support and installation troubleshooting. It takes no parameters and includes: +- see_also [[tail(1)]] +- see_also [[bm-project-delete(3)]] +- [bm_list](#bm_list) -- Basic Memory package and API versions; -- Python, operating-system, and architecture details; and -- the config path and current config contents with secrets and URL credentials redacted; and -- the `BASIC_MEMORY_*` environment variables that override `config.json`, redacted the same way. +## `bm_schema` -::note -v0.23 removes the `canvas`, `cloud_info`, and `release_notes` MCP tools. Use the Cloud documentation, GitHub release notes, and your editor's native visualization features instead. See the [v0.23.0 release notes](https://github.com/basicmachines-co/basic-memory/releases/tag/v0.23.0). -:: +### NAME ---- +**bm-schema** — validate notes against schemas, infer schemas, find drift -## ChatGPT compatibility tools +### SYNOPSIS -These are compatibility wrappers for ChatGPT's MCP implementation, which uses a simplified two-tool interface by default. v0.23 gates them by MCP client identity: only OpenAI clients can call them. +``` +bm_schema(command, note_type=None, identifier=None, threshold=0.25, + output_format="text", project=None) +``` -- **`search(query)`** — Search across the knowledge base. Equivalent to `search_notes` with default parameters. -- **`fetch(id)`** — Retrieve full document content by permalink. Equivalent to `read_note`. +### DESCRIPTION -Non-OpenAI MCP clients receive a clear rejection and must call `search_notes` and `read_note` directly. +Works with Picoschema note schemas. A schema is a note with `type: schema` +whose `entity` field names the note type it describes. `command` picks what to +do: -See the [ChatGPT integration guide](/integrations/chatgpt) for usage details and limitations. +- `validate` — check notes against their schema: one `note_type`, one note by + `identifier`, or every type that has a schema. +- `infer` — suggest a schema from the notes of a `note_type`; `threshold` is + the share of notes a field must appear in. +- `diff` — compare a `note_type`'s notes with its schema to find drift. ---- +A type with no schema, or no notes, is a `NOT_FOUND` error that says how to +create one. + +### PARAMETERS + +- **command** (required) — What to do. +- **note_type** (string | null, optional, default: None) — The frontmatter `type:` to check. Required for infer and diff. +- **identifier** (string | null, optional, default: None) — For validate: one note, instead of a whole note type. +- **threshold** (number, optional, default: 0.25) — For infer: the share of notes a field must appear in to be suggested. +- **output_format** (optional, default: "text") +- **project** (string | null, optional, default: None) — Project name, 'workspace/project', or project external id. With several projects, pass an explicit scope or a project-qualified target. + +### EXAMPLES + +``` +bm_schema(command="infer", note_type="plan", project="demo") +# → # Schema Inference: plan +# Notes analyzed: 1 +# ... +# - **goal** (observation) — 100% (1/1) [required] + +bm_schema(command="validate", note_type="plan", project="demo") +# → # Schema Validation: plan +# Notes: 1 | Valid: 1 | Warnings: 1 | Errors: 0 +# - **launch-plan** — valid +# - warning: Missing required field: owner (expected [owner] observation) + +bm_schema(command="diff", note_type="plan", project="demo") +# → # Schema Drift: plan +# ## New Fields (in notes but not in schema) +# - **decision** (observation) — 100% (1/1) +``` + +### SEE ALSO + +- [bm_find](#bm_find) +- [bm_write](#bm_write) + +## `bm_man` + +### NAME + +**bm-man** — read the Basic Memory manual + +### SYNOPSIS + +``` +bm_man(page=None, query=None, output_format="text") +``` + +### DESCRIPTION + +Reads the manual bundled with Basic Memory, so it works with no project and no +network. With no arguments, the index of every page. `page` reads one page: +`bm-search(3)` for an MCP tool, `grep(1)` for a shell command; a tool name such +as `bm_search` works too. `query` lists the pages that mention every word given, +like `man -k`; pages whose name or summary match come first. + +Section 3 documents the MCP tools, section 1 the `bm` shell commands, and +section 7 the concepts. The index marks pages for tools this server does not +register. + +The shell counterparts are `bm man` and apropos(1). + +### PARAMETERS + +- **page** (string | null, optional, default: None) — The page to read, e.g. 'bm-search(3)', 'grep(1)' or 'bm_search'. +- **query** (string | null, optional, default: None) — Words to find in the manual; lists the pages that mention them all. +- **output_format** (optional, default: "text") + +### EXAMPLES + +``` +bm_man(page="bm_search") +# → # bm-search(3) +# ## NAME +# **bm-search** — search a project's notes, ranked by relevance +# ... + +bm_man(query="frontmatter filters") +# → Manual pages for 'frontmatter filters': +# - apropos(1) — search the Basic Memory manual +# - bm-find(3) — find files by name or notes by frontmatter, recursively +# - bm-man(3) — read the Basic Memory manual +# - bm-search(3) — search a project's notes, ranked by relevance +# - search-notes(3) — search the knowledge base by text, similarity, or metadata + +bm_man(page="nope(3)") +# → error: NOT_FOUND: No manual page 'nope(3)'. +# Try instead: bm_man(query='nope(3)'), or bm_man() for the index +``` + +### GOTCHAS + +- `topic`, `name`, `command` and `tool` are accepted as spellings of `page`. + +### SEE ALSO + +- see_also [[apropos(1)]] + +## Resources and hosted extensions + +`memory://man` lists the built-in manual; `memory://man/bm-read(3)` reads one page. `bm man bm-read` reads the same page in the terminal. `memory:///` reads a note resource, and `memory://ai_assistant_guide` provides usage guidance. -## Related pages +Cloud-only tools such as `review_note` and `open_basic_memory` are separate extensions. See [Comments and Suggestions](/cloud/comments-and-suggestions) and [Pocketbook](/cloud/mcp-app) for their hosted contracts. Their rollout is independent of the core 1.0 tools. ChatGPT's `search` and `fetch` compatibility tools remain client-specific wrappers. -- [What's New in v0.24](/whats-new/v0-24) -- [Upgrade to v0.24](/whats-new/v0-24-upgrade) -- [CLI Reference](/reference/cli-reference) -- [AI Assistant Guide](/reference/ai-assistant-guide) -- [Memory URLs](/concepts/memory-urls) -- [Schema System](/concepts/schema-system) -- [Semantic Search](/concepts/semantic-search) +See also [AI Assistant Guide](/reference/ai-assistant-guide), [CLI Reference](/reference/cli-reference), and [Metadata Search](/concepts/metadata-search). diff --git a/content/10.reference/3.ai-assistant-guide.md b/content/10.reference/3.ai-assistant-guide.md index 8161ec0..d2eae37 100644 --- a/content/10.reference/3.ai-assistant-guide.md +++ b/content/10.reference/3.ai-assistant-guide.md @@ -3,6 +3,10 @@ title: AI Assistant Guide description: Teach your AI assistant when and how to use Basic Memory — skills, project instructions, and CLAUDE.md/AGENTS.md. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + Connecting Basic Memory over MCP gives your assistant the tools. It doesn't teach it *when* to reach for them. A few standing instructions are the difference between an assistant that occasionally writes a note and one that actually maintains your knowledge base — searching before it answers, capturing decisions as they happen, and linking new notes into the graph. There are three ways to give those instructions, from least to most effort. @@ -43,19 +47,18 @@ Paste this and adapt it to your workflow: You have persistent memory through Basic Memory's MCP tools. - Before answering questions about prior work or decisions, search first: - `search_notes`, then `build_context` on relevant `memory://` URLs. + `bm_search`, then `bm_context` on relevant identifiers. - Capture important decisions, findings, and context as notes with - `write_note` during the conversation — don't wait to be asked. + `bm_write` during the conversation — don't wait to be asked. - Structure notes semantically: observations as `- [category] fact #tag` and relations as `- relates_to [[Other Note]]`. Use exact titles of existing notes in wikilinks so they resolve. -- Update existing notes with `edit_note` instead of creating duplicates. - If `write_note` reports "Similar existing notes", decide whether to merge +- Update existing notes with `bm_edit` instead of creating duplicates. + If `bm_write` reports "Similar existing notes", decide whether to merge into one of them, link them, or keep the new note. -- Calls without `project` use the default project (the POSIX tools refuse - unqualified paths when several projects exist). If the target project is +- With several addressable projects, note and search calls require `project` or a project-qualified target. If the target project is ambiguous, ask once, then pass `project` on every call. -- For quick navigation, use `ls`, `find`, `grep`, and `cat` (sections and +- For quick navigation, use `bm_list`, `bm_find`, `bm_search`, and `bm_read` (sections and line ranges keep reads small). Read a tool's manual page (`memory://man/(3)`) when a call fails or its use is unclear. - A refused write is a tool error and nothing was written. Read the error @@ -88,31 +91,25 @@ Your assistant can even write a note about *how you like your notes* — and fin ## What good usage looks like -- **Search before answering.** Questions like "what did we decide about X?" should trigger `search_notes`, not a guess from the conversation so far. +- **Search before answering.** Questions like "what did we decide about X?" should trigger `bm_search`, not a guess from the conversation so far. - **Capture as you go.** Decisions, requirements, and findings get recorded when they happen, structured with observations and relations. -- **Build context on follow-ups.** `build_context` with a `memory://` URL pulls in a note *and* its connected notes, so continuation conversations start warm. -- **Edit, don't duplicate.** Existing notes grow with `edit_note`; new notes link back to what they extend. When `write_note` flags similar existing notes, that's the cue to merge or link. -- **Read only what you need.** `search_notes(compact=True)` and `build_context(compact=True)` return identifiers without bodies so the agent can pick what to open. `cat` reads one section, a line range, or a token budget instead of a whole note. -- **Name the project.** There's no session "active project" — a call without `project` goes to the default project. With several projects, pass `project` or use project-qualified paths like `research/notes/topic.md`. +- **Build context on follow-ups.** `bm_context` with a `memory://` URL pulls in a note *and* its connected notes, so continuation conversations start warm. +- **Edit, don't duplicate.** Existing notes grow with `bm_edit`; new notes link back to what they extend. When `bm_write` flags similar existing notes, that's the cue to merge or link. +- **Read only what you need.** `bm_search(query="topic", compact=True)` and `bm_context(identifier="notes/topic", compact=True)` return identifiers without bodies so the agent can pick what to open. `bm_read` reads one section, a line range, or a token budget instead of a whole note. +- **Name the project.** There's no session "active project" — unqualified note/search calls are refused when several projects are addressable. With several projects, pass `project` or use project-qualified paths like `research/notes/topic.md`. --- -## What changed for assistants in v0.24 - -If you wrote instructions for an earlier version, a few behaviors are worth updating: +## Preparing instructions for 1.0 -- **POSIX read tools are on by default.** Assistants now see `ls`, `find`, `grep`, `cat`, `tail`, and `man` next to the rich tools. Projects act as mount points: `ls(path="/")` lists them, and a path starting with a project name routes there. Set `enable_posix_tools=false` to hide them. -- **Refusals are tool errors.** A refused `write_note`, `edit_note`, `delete_note`, or `move_note` comes back with `isError` set, never as an ordinary result. Nothing is written when a call is refused. -- **Guard concurrent edits.** Pass `expected_checksum` (the `checksum` from a JSON `read_note`, `write_note`, or `edit_note` result) to `edit_note`, or to `write_note` with `overwrite=True`, so a write only lands on the revision the assistant read. A conflict returns `NOTE_REVISION_CONFLICT` with the current checksum; `read_note(include_content=False)` refreshes it cheaply. -- **`replace_section` needs the exact heading.** It fails instead of appending a duplicate section when the heading is missing. -- **`grep` matches keywords.** A pattern found in no note returns nothing. Pass `semantic=True` to rank by meaning. -- **The manual is built in.** `memory://man` lists a page per tool, and notes themselves are readable as resources at `memory:///`. - -::tip -A one-line instruction like "Read `memory://man` before using an unfamiliar Basic Memory tool" goes a long way: each page has verified examples and the common mistakes for that tool. -:: +- Use the twelve `bm_*` core tools. `bm_project(command="recent", since="7d")` replaces recent-activity calls; its JSON result contains a `results` array. +- `bm_edit` requires an existing note. Create with `bm_write` after a `NOT_FOUND` refusal when creation is intended. +- A JSON refusal has `error`, `message`, and optional `try_instead`. Re-read after `REVISION_CONFLICT`; inspect state before retrying `OUTCOME_UNKNOWN` or `PARTIAL_FAILURE`. +- Pass `expected_checksum` from `bm_read` to guard changes. Metadata-only reads use `include_content=False`. +- `bm_read` includes frontmatter by default. Use `section`, line bounds, or `max_tokens` for smaller reads. +- Read `bm_man(page="bm-edit")` or `memory://man` for exact signatures. -See [What's New in v0.24](/whats-new/v0-24) for the full release, and [Upgrade to v0.24](/whats-new/v0-24-upgrade) for breaking changes. +See [Migrating to 1.0](/reference/migrating-to-1-0). These instructions target the upcoming surface; check the connected server's tool list before switching. For the full tool surface — parameters, aliases, defaults — see the [MCP Tools Reference](/reference/mcp-tools-reference). diff --git a/content/10.reference/4.technical-information.md b/content/10.reference/4.technical-information.md index b146c28..e880c87 100644 --- a/content/10.reference/4.technical-information.md +++ b/content/10.reference/4.technical-information.md @@ -3,6 +3,10 @@ title: Technical Information description: Technical details about Basic Memory implementation, architecture, licensing, and Model Context Protocol integration --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + ::note This page describes the architecture of the open-source [Basic Memory](https://github.com/basicmachines-co/basic-memory) project. [Basic Memory Cloud](/cloud/cloud-guide) builds on this foundation with hosted infrastructure and additional features. :: @@ -202,8 +206,8 @@ code: | KnowledgeFiles["Markdown Files - Source of Truth"] KnowledgeIndex[(Knowledge Graph Index)] - BMCP <-->|"write_note() read_note()"| KnowledgeFiles - BMCP <-->|"search_notes() build_context()"| KnowledgeIndex + BMCP <-->|"bm_write() bm_read()"| KnowledgeFiles + BMCP <-->|"bm_search() bm_context()"| KnowledgeIndex KnowledgeFiles <-.->|Sync Process| KnowledgeIndex KnowledgeFiles <-->|Direct Editing| Editors((Text Editors & Git)) diff --git a/content/10.reference/5.troubleshooting.md b/content/10.reference/5.troubleshooting.md index 5ac03c5..de800b2 100644 --- a/content/10.reference/5.troubleshooting.md +++ b/content/10.reference/5.troubleshooting.md @@ -3,6 +3,10 @@ title: Troubleshooting description: Common issues and solutions for Basic Memory. --- +::note +MCP examples on this page target the upcoming 1.0 tools. Check your server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). +:: + This guide covers common issues and their solutions. For live help, visit our [Discord server](https://discord.gg/tyvKNccgqN). --- @@ -73,13 +77,13 @@ The official Docker image already passes `--host 0.0.0.0`, so containers built f ### Client Treats a Refused Write as an Error -**Problem:** After upgrading to v0.24, an agent or script reports a tool error from `write_note` or `edit_note` where it used to report success. +**Problem:** After upgrading to v0.24, an agent or script reports a tool error from `bm_write` or `bm_edit` where it used to report success. -**Cause:** A refused write is now an MCP tool error (`isError`), as a failed `delete_note` or `move_note` already was. This covers writing to an existing note without `overwrite`, a revision conflict on `expected_checksum`, a note that moved, a directory outside the project, and an `edit_note` that rolled back, such as a "modified concurrently" conflict when two clients append to one note. Nothing is written in any of these cases. Before v0.24 these came back as ordinary results, so clients counted them as written. +**Cause:** A refused write is now an MCP tool error (`isError`), as a failed `bm_delete` or `bm_move` already was. This covers writing to an existing note without `overwrite`, a revision conflict on `expected_checksum`, a note that moved, a directory outside the project, and an `bm_edit` that rolled back, such as a "modified concurrently" conflict when two clients append to one note. Nothing is written in any of these cases. Before v0.24 these came back as ordinary results, so clients counted them as written. **Solution:** Treat the error as a real refusal. Read the note again, then retry, merge, or pass `overwrite=True`. In JSON mode the error message carries the same payload as before (`action: "conflict"`, `error: "NOTE_ALREADY_EXISTS"`, `error: "NOTE_REVISION_CONFLICT"` with `currentChecksum`, and so on). On the CLI, `bm tool write-note` and `bm tool edit-note` exit with status `1`. -Similarly, `edit_note` with `replace_section` now fails when the exact heading isn't in the note, instead of appending a duplicate section. Give the heading in full, or use `append`. +Similarly, `bm_edit` with `replace_section` now fails when the exact heading isn't in the note, instead of appending a duplicate section. Give the heading in full, or use `append`. ### MCP Endpoint Connection Fails (Cloud) @@ -179,7 +183,7 @@ bm cloud login ### Duplicate Notes on macOS -**Problem:** The same file appears twice — duplicate search results, `-1`-suffixed permalinks, or `edit_note` failing on an affected note. Typically triggered by cross-platform sync tools that rewrite Unicode filename forms ([#1275](https://github.com/basicmachines-co/basic-memory/issues/1275)) or by case-only renames on case-insensitive APFS ([#1281](https://github.com/basicmachines-co/basic-memory/issues/1281)). +**Problem:** The same file appears twice — duplicate search results, `-1`-suffixed permalinks, or `bm_edit` failing on an affected note. Typically triggered by cross-platform sync tools that rewrite Unicode filename forms ([#1275](https://github.com/basicmachines-co/basic-memory/issues/1275)) or by case-only renames on case-insensitive APFS ([#1281](https://github.com/basicmachines-co/basic-memory/issues/1281)). **Solution:** v0.24 fixes case-only renames on case-insensitive filesystems: the rename sticks, and the next index pass removes the stale entry instead of leaving a ghost note. For duplicates left by an earlier version, or by a sync tool that rewrites Unicode filename forms, collapse them with a full rebuild: @@ -187,7 +191,7 @@ bm cloud login basic-memory reindex --full -p ``` -Folder casing is handled separately: since v0.23.2, `write_note` and `move_note` reuses a uniquely matching existing folder regardless of case, preventing a new `schemas/` folder beside `Schemas/`. It does not repair existing duplicates. +Folder casing is handled separately: since v0.23.2, `bm_write` and `bm_move` reuses a uniquely matching existing folder regardless of case, preventing a new `schemas/` folder beside `Schemas/`. It does not repair existing duplicates. ### Ignored Files Still Show Up in Search @@ -272,7 +276,7 @@ The [Cloud Sync Guide's troubleshooting section](/cloud/cloud-sync#troubleshooti Find notes about [topic] ``` -2. **Check exact title/permalink** - Titles are case-sensitive. If a `memory://` title URL matches more than one note, `build_context` and `read_note` refuse it; pass the permalink instead. +2. **Check exact title/permalink** - Titles are case-sensitive. If a `memory://` title URL matches more than one note, `bm_context` and `bm_read` refuse it; pass the permalink instead. 3. **List directory contents**: ``` diff --git a/content/10.reference/7.migrating-to-1-0.md b/content/10.reference/7.migrating-to-1-0.md new file mode 100644 index 0000000..fca42fe --- /dev/null +++ b/content/10.reference/7.migrating-to-1-0.md @@ -0,0 +1,87 @@ +--- +title: Migrating to 1.0 +description: Update MCP clients, agent instructions, and integrations for the upcoming Basic Memory 1.0 tools. +--- + +::note +Preparation guide for the upcoming 1.0 tool surface. Verify that your installed or hosted server advertises the new tools before switching a client. This page does not announce a release or deployment. +:: + +## MCP tools: migrate to the bm_* surface + +**Status:** implemented on the development branch for 1.0 (SPEC-35.2). Upgrade your +server and its agent packages together, then restart clients to refresh cached tool +schemas and permission lists. This does not rename the CLI's `bm tool` commands. + +| Previous MCP tool | 1.0 replacement | +| --- | --- | +| `read_note`, `read_content`, `view_note`, `cat` | `bm_read` | +| `write_note` | `bm_write` | +| `edit_note` | `bm_edit` | +| `search_notes`, `grep` | `bm_search` | +| `build_context` | `bm_context` | +| `list_directory`, `ls` | `bm_list` for one level; `bm_find` for recursive inventory | +| `find` | `bm_find` | +| `recent_activity` | `bm_project(command="recent")` | +| `list_memory_projects`, `list_workspaces` | `bm_project(command="list")` | +| `create_memory_project` | `bm_project(command="create", name=..., path=...)` | +| `delete_project` | `bm_project_delete` (opt-in) | +| `schema_validate`, `schema_infer`, `schema_diff` | `bm_schema(command="validate"/"infer"/"diff")` | +| `move_note` | `bm_move` | +| `delete_note` | `bm_delete` | +| `man` | `bm_man` | + +### Change arguments and response handling too + +- Pass names, workspace-qualified names, or external UUIDs through `project`. + Remove `project_id`; calls do not retain a selected project between requests. +- Search uses `mode`, `filters`, `items`, `since`, and `all_projects` instead of + `search_type`, `metadata_filters`, `entity_types`, `after_date`, and + `search_all_projects`. Use `items=["note"]` for whole notes. Put `tags` and + `status` inside `filters`; `note_types` still filters frontmatter types. +- Edit uses `command` instead of `operation`. `set_metadata` edits frontmatter; + edits never create missing notes. +- Context uses `identifier` instead of `url` and `since` instead of `timeframe`. + It defaults to JSON and a seven-day window. Depth is bounded to 1–5. +- Recent activity uses `command="recent"` and `since`. JSON returns an object + with `results` and paging fields, rather than a bare array. +- Project discovery returns project rows with workspace fields. It does not return + the old standalone workspace role/subscription response. +- Reads use `start_line`, `end_line`, `section`, or `max_tokens`; `page` and + `page_size` do not slice note content. JSON reads include frontmatter by default; + pass `include_frontmatter=False` when a consumer needs the body alone. +- Move uses `destination`. End a folder destination with `/` to preserve the file + name. JSON move/delete receipts identify success through `action` (`moved` or + `deleted`), rather than boolean `moved`/`deleted` fields. +- Refusals set MCP `isError`. JSON error text contains `error`, `message`, and + sometimes `try_instead`. Handle `NOT_FOUND`, `ALREADY_EXISTS`, and + `REVISION_CONFLICT`; do not treat them as successful empty results or expect + legacy `NOTE_*` payload fields. Read again to obtain the current checksum. + +For an overwrite, prefer the exact returned `file_path` as `identifier` and pass +`expected_checksum` from a fresh read. Do not reconstruct a filename from a title. + +```python +note = await bm_read(identifier="notes/Plan.md", project="research", output_format="json") +await bm_write( + identifier=note["file_path"], + content="Updated plan.", + overwrite=True, + expected_checksum=note["checksum"], + project="research", +) +await bm_search(filters={"status": "active", "tags": ["planning"]}, project="research") +await bm_project(command="recent", since="7d", project="research", output_format="json") +``` + +### Update callers and installed instructions + +Update custom agents, hooks, MCP allowlists, tool routers, recorded request fixtures, +and test fakes as well as prompts and skills. Native Hermes and OpenClaw wrappers +may retain their host-facing arguments while translating to the new MCP contract. +Tau preserves the core `bm_` prefix; there is no `bm_bm_write` tool. + +Use `bm_man(page="bm-search(3)")` or `bm man bm-search` for the installed reference. +Re-run benchmark baselines after upgrading; historical results describe the tool +surface they were measured against and should not be relabeled as 1.0 results. + From 43092fe55aea722e61f3ddc81c70a5a074726abf Mon Sep 17 00:00:00 2001 From: phernandez Date: Sat, 24 Oct 2026 00:26:03 -0500 Subject: [PATCH 2/5] docs: correct 1.0 routing and refusal examples Signed-off-by: phernandez --- content/06.local/2.getting-started.md | 10 +++---- content/06.local/4.mcp-tools-local.md | 2 +- content/06.local/5.user-guide.md | 28 +++++++++---------- content/07.concepts/2.projects-and-folders.md | 4 +-- content/07.concepts/4.memory-urls.md | 4 +-- content/10.reference/5.troubleshooting.md | 8 +++--- 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/content/06.local/2.getting-started.md b/content/06.local/2.getting-started.md index b6a98f2..b666c40 100644 --- a/content/06.local/2.getting-started.md +++ b/content/06.local/2.getting-started.md @@ -40,7 +40,7 @@ Create a new project called "my project" in the "/Users/yourname/Documents/Notes Then: ```text -Set the default project to "my project" +Use "my project" for subsequent notes and searches. ``` Or use the command line: @@ -54,7 +54,7 @@ basic-memory project default "my project" ``` ::warning -If you change default projects from the command line, new notes will be saved in your chosen folder after restarting Claude Desktop. +With the upcoming 1.0 tools, multiple addressable projects require the assistant to pass `project` or a project-qualified target on note and search calls. Changing the CLI default does not replace that explicit scope. :: **Want to use Obsidian?** Just open your folder location as a vault. See the [Obsidian Integration](/integrations/obsidian) guide. @@ -75,7 +75,7 @@ When you start a conversation, the AI will: 1. Check your available projects 2. Suggest the most active project based on recent activity 3. Ask which project to use for this conversation -4. Remember your choice throughout the session +4. Pass your chosen project on subsequent tool calls **Example:** ```text @@ -99,13 +99,13 @@ You: "Create a new project called 'work-notes' in ~/Documents/work" **For users who primarily work in one project:** -Set a default fallback project — it's the same setting the command above writes: +Set a default for CLI commands that support fallback — it's the same setting the command above writes: ```bash basic-memory project default "main" ``` -With this set, the AI uses your default project when no project is specified. +For 1.0 MCP note and search calls, the assistant still names the project when several are addressable. To constrain an MCP session to one project, start the server with `basic-memory mcp --project main`; see the [User Guide](/local/user-guide#single-project-mode-locked). --- diff --git a/content/06.local/4.mcp-tools-local.md b/content/06.local/4.mcp-tools-local.md index a1d9bd9..5708e04 100644 --- a/content/06.local/4.mcp-tools-local.md +++ b/content/06.local/4.mcp-tools-local.md @@ -35,7 +35,7 @@ bm_search(query="retry", project="main", mode="text", lines=3) bm_read(identifier="research/specs/auth.md", section="Decisions") ``` -Pass `project` as a name, workspace-qualified name, or UUID. Otherwise calls use the configured default. A server constrained with `BASIC_MEMORY_MCP_PROJECT` stays in that project. The legacy `enable_posix_tools` setting does not hide the new `bm_*` tools. +Pass `project` as a name, workspace-qualified name, or UUID, or use a project-qualified target such as `research/notes/topic.md`. When several projects are addressable, unqualified note and search calls are refused even if a default project is configured. With only one addressable project, the tools can use it implicitly. A server constrained with `BASIC_MEMORY_MCP_PROJECT` stays in that project. The legacy `enable_posix_tools` setting does not hide the new `bm_*` tools. ## Semantic search diff --git a/content/06.local/5.user-guide.md b/content/06.local/5.user-guide.md index cbf0f04..b6abfa7 100644 --- a/content/06.local/5.user-guide.md +++ b/content/06.local/5.user-guide.md @@ -189,7 +189,7 @@ memory://main/docs/auth → error: project is constrained to "research" ### 2. Explicit project prefix -If no constraint is set, the URL is checked for a project prefix. The first path segment is always compared against known project names; when it matches, that segment is stripped and used as the project context: +If no constraint is set, the URL is checked for a project prefix. The longest matching known project prefix is stripped and used as the project context: ```text memory://main/specs/api-design @@ -197,14 +197,14 @@ memory://main/specs/api-design ^^^^^^^^^^^^^^^^ → path = "specs/api-design" ``` -If the first segment doesn't match any known project, the entire path is treated as a note path. +If no known project prefix matches, the entire path is treated as a note path and still needs project scope. -### 3. Default project fallback +### 3. Explicit scope or a single addressable project -If no constraint exists and no project prefix matches, the URL resolves in the default project: +If no constraint exists and no project prefix matches, pass `project` explicitly when several projects are addressable. A configured default does not remove this requirement for 1.0 note and search tools. With only one addressable project, the tools can use it implicitly. -```text -memory://docs/auth → resolves in default project (typically "main") +```python +bm_read(identifier="memory://docs/auth", project="main") ``` ::note @@ -250,7 +250,7 @@ Deleting a note keeps the links that pointed at it as unresolved references inst ## Multi-Project Workflows -Basic Memory supports multiple projects for organizing different knowledge bases. The AI discovers your projects with `bm_project(command="list")` and names the project on each tool call; a call without a project always goes to the default project — there's no per-session "active project". Project setup, creation commands, and the default-project fallback are covered in [Set Up Local Projects](/local/getting-started). +Basic Memory supports multiple projects for organizing different knowledge bases. The AI discovers your projects with `bm_project(command="list")` and names the project on each tool call; unqualified note and search calls are refused when several projects are addressable, even if a default exists. There's no per-session "active project". Project setup and CLI default-project commands are covered in [Set Up Local Projects](/local/getting-started). ### Single Project Mode (Locked) @@ -260,7 +260,7 @@ For focused sessions or automation, lock the MCP server to one project: basic-memory mcp --project work-notes ``` -This **locks** the entire MCP session - the `project` parameter in tool calls will be ignored. +This **locks** the entire MCP session to that project. Unqualified calls use it; targets naming a different known project are refused. **When to use:** - Automation workflows that should only access one project @@ -269,7 +269,7 @@ This **locks** the entire MCP session - the `project` parameter in tool calls wi ::note **Key difference:** -- **Default project fallback**: Uses `default_project` when no project is specified, but can still switch +- **Unconstrained MCP server**: With several addressable projects, pass `project` or a project-qualified target on note and search calls - **Single Project Mode**: Locked to one project, cannot switch :: @@ -405,11 +405,11 @@ Move or delete entire folders: ```bash You: "Move the old-projects folder to archive" -Claude: [Uses bm_move with is_directory=true] +Claude: [Uses bm_move with path="old-projects", destination="archive/old-projects/", project="main"] "Moved old-projects/ → archive/old-projects/ (15 files)" -You: "Delete the empty temp folder" -Claude: [Uses bm_delete with is_directory=true] +You: "Delete the temp folder and its contents" +Claude: [Uses bm_delete with path="temp", recursive=True, project="main"] "Deleted temp/ and all 3 contained files" ``` @@ -439,7 +439,7 @@ You can also search purely by metadata — no text query needed: ```bash You: "What notes have status draft?" -Claude: [Uses bm_search with status="draft"] +Claude: [Uses bm_search with filters={"status": "draft"}] ``` --- @@ -454,7 +454,7 @@ You: "I've been writing a lot of person notes. Can you help me standardize them? Claude: Let me analyze your existing person notes to find common patterns. -[Uses schema_infer with note_type="person"] +[Uses bm_schema with command="infer", note_type="person"] Based on your notes, here's what most of them include: - name (in 95% of notes) diff --git a/content/07.concepts/2.projects-and-folders.md b/content/07.concepts/2.projects-and-folders.md index 0611b6e..9287bd7 100644 --- a/content/07.concepts/2.projects-and-folders.md +++ b/content/07.concepts/2.projects-and-folders.md @@ -15,7 +15,7 @@ A project is a separate knowledge base. Each project maps to a folder on disk (o Think of projects the way you think of separate notebooks, not separate pages in the same notebook. -When you run a command or an AI tool like `bm_write`, it targets the project you name — each call carries a `project` parameter or CLI argument. If you don't specify one, it goes to the **default project**, and you can target a different project at any time, including mid-conversation. +AI tools such as `bm_write` target the project supplied through `project` or a project-qualified path. When several projects are addressable, note and search calls require that explicit scope, even if a default is configured. With only one addressable project, it can be selected implicitly. CLI commands that support a default still use it when their project argument is omitted. You can target a different project at any time, including mid-conversation. ## Creating and managing projects @@ -32,7 +32,7 @@ List your projects: bm project list ``` -Set a default so commands go there automatically: +Set a default for CLI commands that support default-project selection: ```bash bm project default "work" diff --git a/content/07.concepts/4.memory-urls.md b/content/07.concepts/4.memory-urls.md index 7d95b6b..2b60c3f 100644 --- a/content/07.concepts/4.memory-urls.md +++ b/content/07.concepts/4.memory-urls.md @@ -82,7 +82,7 @@ Two other resource families share the scheme: | URL | Returns | |---|---| | `memory://man` | Index of Basic Memory's built-in manual | -| `memory://man/` | One manual page, such as `memory://man/search-notes(3)` | +| `memory://man/` | One manual page, such as `memory://man/bm-search(3)` | | `memory:////info` | Project information as JSON | Each MCP tool has a section-3 manual page with its parameters, verified examples, and gotchas, and clients that browse `resources/list` see every page with its summary. From the terminal, `bm man ` prints the same pages. See the [CLI Reference](/reference/cli-reference). @@ -91,7 +91,7 @@ Each MCP tool has a section-3 manual page with its parameters, verified examples ## Resolution behavior -URLs resolve to a project by explicit prefix first, then fall back to the default project. The full resolution order — including local-server project constraints — is covered in the [local User Guide](/local/user-guide#memory-url-resolution-local-server); these controls aren't exposed in cloud. +For 1.0 note and search tools, URLs can carry a recognized project prefix. Without that prefix, pass `project` when several projects are addressable; a configured default does not supply implicit scope. A single addressable project can be selected implicitly. The full resolution order — including local-server project constraints — is covered in the [local User Guide](/local/user-guide#memory-url-resolution-local-server); these controls aren't exposed in cloud. --- diff --git a/content/10.reference/5.troubleshooting.md b/content/10.reference/5.troubleshooting.md index de800b2..a53aff0 100644 --- a/content/10.reference/5.troubleshooting.md +++ b/content/10.reference/5.troubleshooting.md @@ -77,13 +77,13 @@ The official Docker image already passes `--host 0.0.0.0`, so containers built f ### Client Treats a Refused Write as an Error -**Problem:** After upgrading to v0.24, an agent or script reports a tool error from `bm_write` or `bm_edit` where it used to report success. +**Problem:** After switching to the 1.0 tools, an agent or script reports a tool error from `bm_write` or `bm_edit`. -**Cause:** A refused write is now an MCP tool error (`isError`), as a failed `bm_delete` or `bm_move` already was. This covers writing to an existing note without `overwrite`, a revision conflict on `expected_checksum`, a note that moved, a directory outside the project, and an `bm_edit` that rolled back, such as a "modified concurrently" conflict when two clients append to one note. Nothing is written in any of these cases. Before v0.24 these came back as ordinary results, so clients counted them as written. +**Cause:** Refused operations use MCP `isError`. In JSON mode, the payload has `error`, `message`, and an optional `try_instead`. Examples include `ALREADY_EXISTS` for a create that would overwrite a note, `REVISION_CONFLICT` for a failed checksum precondition, and `LOCKED` for a protected note. Do not expect legacy `NOTE_*` codes, `action: "conflict"`, or `currentChecksum` fields. -**Solution:** Treat the error as a real refusal. Read the note again, then retry, merge, or pass `overwrite=True`. In JSON mode the error message carries the same payload as before (`action: "conflict"`, `error: "NOTE_ALREADY_EXISTS"`, `error: "NOTE_REVISION_CONFLICT"` with `currentChecksum`, and so on). On the CLI, `bm tool write-note` and `bm tool edit-note` exit with status `1`. +**Solution:** Inspect the error code and message. For `ALREADY_EXISTS`, read the existing note and decide whether to edit it or deliberately replace it with `overwrite=True`. For `REVISION_CONFLICT`, read the current note again, reconcile your changes, and use the newly read checksum for the next guarded write. An `OUTCOME_UNKNOWN` error does not prove the write failed: read back the target before retrying. See [Migrating to 1.0](/reference/migrating-to-1-0) for the response contracts. -Similarly, `bm_edit` with `replace_section` now fails when the exact heading isn't in the note, instead of appending a duplicate section. Give the heading in full, or use `append`. +`bm_edit(command="replace_section")` also refuses a missing exact heading. Give the heading in full, or use `command="append"` to add a new section. CLI `bm tool write-note` and `bm tool edit-note` retain their separate CLI contracts and exit with status `1` on refusal. ### MCP Endpoint Connection Fails (Cloud) From e8c4a30c2e01b9c91a30a57f5f8dc4d843cc3bf5 Mon Sep 17 00:00:00 2001 From: phernandez Date: Sat, 24 Oct 2026 00:29:05 -0500 Subject: [PATCH 3/5] docs: correct directory move destination semantics Signed-off-by: phernandez --- content/06.local/5.user-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/06.local/5.user-guide.md b/content/06.local/5.user-guide.md index b6abfa7..7f5d650 100644 --- a/content/06.local/5.user-guide.md +++ b/content/06.local/5.user-guide.md @@ -405,7 +405,7 @@ Move or delete entire folders: ```bash You: "Move the old-projects folder to archive" -Claude: [Uses bm_move with path="old-projects", destination="archive/old-projects/", project="main"] +Claude: [Uses bm_move with path="old-projects", destination="archive/", project="main"] "Moved old-projects/ → archive/old-projects/ (15 files)" You: "Delete the temp folder and its contents" From 6a45aae33392b72af5e53487b1f047c90af63144 Mon Sep 17 00:00:00 2001 From: phernandez Date: Sat, 24 Oct 2026 00:32:02 -0500 Subject: [PATCH 4/5] docs: use new recent activity command in saved prompt Signed-off-by: phernandez --- content/07.concepts/0.vs-built-in-memory.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/07.concepts/0.vs-built-in-memory.md b/content/07.concepts/0.vs-built-in-memory.md index b1d0ceb..335e07b 100644 --- a/content/07.concepts/0.vs-built-in-memory.md +++ b/content/07.concepts/0.vs-built-in-memory.md @@ -17,8 +17,8 @@ Save this to your memory: Use Basic Memory as my long-term knowledge store — record durable decisions, research, and context there as notes. Keep your built-in memory for short-term working context, and have your memories reference Basic Memory notes for the details. Use Basic -Memory's bm_search, recent_activity, and bm_context tools to find -information before answering questions about past work. +Memory's bm_search, bm_project(command="recent"), and bm_context +to find information before answering questions about past work. ``` Built-in memory becomes the short-term cache; Basic Memory becomes the long-term store — and each knows about the other. For fuller standing instructions (skills, project settings, CLAUDE.md/AGENTS.md), see the [AI Assistant Guide](/reference/ai-assistant-guide). From f80ca488d824d7bfc849c3e85101eef6abd134dd Mon Sep 17 00:00:00 2001 From: phernandez Date: Sat, 24 Oct 2026 00:36:20 -0500 Subject: [PATCH 5/5] docs: replace remaining legacy MCP navigation guidance Signed-off-by: phernandez --- content/01.start-here/1.what-is-basic-memory.md | 3 ++- content/08.integrations/02.claude-code.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/content/01.start-here/1.what-is-basic-memory.md b/content/01.start-here/1.what-is-basic-memory.md index 2645807..357e798 100644 --- a/content/01.start-here/1.what-is-basic-memory.md +++ b/content/01.start-here/1.what-is-basic-memory.md @@ -344,7 +344,8 @@ Basic Memory uses the [Model Context Protocol (MCP)](https://modelcontextprotoco - `bm_edit` - Incremental editing - `bm_context` - Load related notes - `bm_project(command="list")` - List your projects -- `cat`, `grep`, `ls`, `find`, `tail`, `man` - Familiar read-only tools for browsing notes like files +- `bm_list` and `bm_find` - Browse directories and discover paths +- `bm_man` - Read or search the built-in manual - ...and many more **Compatible assistants:** diff --git a/content/08.integrations/02.claude-code.md b/content/08.integrations/02.claude-code.md index 71333bb..245ef61 100644 --- a/content/08.integrations/02.claude-code.md +++ b/content/08.integrations/02.claude-code.md @@ -44,7 +44,7 @@ claude mcp add basic-memory basic-memory mcp Run `/mcp` in Claude Code to confirm the tools are available. ::note -As of v0.24, the server also exposes the read-only POSIX-style tools `cat`, `grep`, `ls`, `find`, `tail`, and `man`, so `/mcp` lists six more tools than before. Set `BASIC_MEMORY_ENABLE_POSIX_TOOLS=false` (or `enable_posix_tools: false` in `config.json`) to hide them. +The upcoming 1.0 MCP surface uses `bm_read` for full or sliced reads, `bm_search` for ranked results and matching lines, `bm_list` and `bm_find` for navigation, and `bm_man` for the manual. Check your installed server’s tool list before switching; see [Migrating to 1.0](/reference/migrating-to-1-0). The legacy `enable_posix_tools` setting does not hide the new `bm_*` tools. :: ---