{
  "markdown": "<!-- markdownlint-disable MD033 MD041 -->\n<div align=\"center\">\n\n<img src=\"docs/media/basemind-banner.svg\" alt=\"basemind — cybernetic core\" width=\"820\">\n\n**The context and communication layer for coding agents.**\n\nbasemind turns any repo into an always-current map of its code, documents, history, and memory —\nso agents answer from **structure and search** instead of burning their context window on `grep` and\nfile reads — and gives a team of agents a **shared channel to coordinate** while they work. One\nserver does both.\n\nCode map across **300+ languages** · documents in **90+ formats** · semantic + full-text search ·\ngit history & blame · shared memory · web crawl · agent-to-agent comms\n\n[![Docs](https://img.shields.io/badge/docs-basemind.ai-965aff?style=flat-square)](https://basemind.ai)\n[![crates.io](https://img.shields.io/crates/v/basemind?style=flat-square)](https://crates.io/crates/basemind)\n[![npm](https://img.shields.io/npm/v/basemind?style=flat-square)](https://www.npmjs.com/package/basemind)\n[![PyPI](https://img.shields.io/pypi/v/basemind?style=flat-square)](https://pypi.org/project/basemind/)\n[![CI](https://img.shields.io/github/actions/workflow/status/Goldziher/basemind/ci.yaml?style=flat-square)](https://github.com/Goldziher/basemind/actions/workflows/ci.yaml)\n[![License: MIT](https://img.shields.io/badge/license-MIT-green?style=flat-square)](LICENSE)\n\n[Docs](https://basemind.ai) · [Install](#installation) · [Features](#what-you-get) · [How it works](#how-it-works) · [Performance](#performance) · [CLI](#cli-reference)\n\n</div>\n\n---\n\n<!-- markdownlint-disable MD013 -->\n<p align=\"center\"><img src=\"docs/media/mcp-demo.gif\" alt=\"An agent answering from a file outline and its call sites in a live Claude Code session\" width=\"820\"></p>\n<p align=\"center\"><em>An agent reasoning from structure — <code>code</code> modes <code>outline</code> and <code>references</code> in a live session, statusline tracking tokens saved.</em></p>\n<!-- markdownlint-enable MD013 -->\n\n<div align=\"center\"><sub><a href=\"#demos\">More demos ↓</a></sub></div>\n\n---\n\n## What you get\n\nbasemind answers with **file paths, line numbers, and signatures — not whole files** — so a question\nabout your code costs a small fraction of the tokens it takes to read the source.\n\n<!-- markdownlint-disable MD013 -->\n\n| Capability | What it does | Key tools |\n|---|---|---|\n| **Code intelligence** | Read the code map instead of opening files: a file's structure (`outline`), find a definition by name (`symbols`), regex content search (`grep`), enumerate or fuzzy-find files (`files` · `find`), resolve a reference position to the definition it binds to (`definition` — **scope- and import-aware**, JS/TS via oxc, Python & Java via in-tree [stack-graphs](#how-it-works)), every call site of a name (`references`, name-only) or of one specific definition (`callers`), implementors of a trait / interface / base class (`implementations`), the reverse import lookup (`dependents`), one symbol's raw body (`expand`), and search by meaning over indexed chunks (`semantic` → `chunk`, needs `--features code-search`). Layered over [300+ languages](#how-it-works). | `code` (`outline` · `symbols` · `grep` · `files` · `find` · `definition` · `references` · `callers` · `implementations` · `dependents` · `expand` · `semantic` · `chunk`) |\n| **Code graph** | Walk the typed code-graph: who calls what and what a function reaches (`calls`), a symbol's n-hop blast radius (`neighbors`), the confidence-weighted shortest route between two symbols (`path`), a readable centrality-cut neighborhood (`subgraph`), the repo's de-facto modules (`communities`), and the whole-repo architecture ranked by PageRank + git churn with its dependency cycles (`map`). Render it as node-link JSON / DOT / Mermaid / GraphML / Cypher / offline interactive HTML / static SVG (`export`), **show it to a human** in their desktop viewer (`display`), or **open the interactive UI** at a live `http://…/ui` URL (`open`, which needs the daemon's opt-in HTTP front-end and otherwise falls back to a `file://` export) — both take `open: false` to return the path or URL without launching anything. Every edge carries provenance + confidence; every result is deterministic and bounded. | `graph` (`calls` · `neighbors` · `path` · `subgraph` · `communities` · `map` · `export` · `display` · `open`) |\n| **Git intelligence** | Ask what changed recently, who last touched a function or a line, where the churn is, when a symbol's body actually changed, how a file's structure differs across commits, and full-text search commit authors + messages at full branch depth. | `git` (`status` · `recent` · `touching` · `by_path` · `churn` · `diff` · `diff_outline` · `blame` · `blame_symbol` · `symbol_history` · `search`) |\n| **Memory & documents** | A per-repo memory agents write to and search by meaning — clones of the same repo share it, unrelated repos stay separate — plus semantic search over PDFs, Office files, HTML, email, and images (OCR included, no extra setup), and a review queue of notes mined from files that change together, which you approve before anything is kept. | `memory` (`put` · `get` · `list` · `search` · `delete` · `audit` · `documents` · `mine` · `proposals` · `accept` · `reject`) |\n| **Web crawl** | Fetch a page or follow links from a starting URL; results join the document search above. | `web` (`scrape` · `crawl` · `map`) |\n| **Agent comms** | Threads addressed by subject, path-glob, and members; scope discovery; inbox delivery; lifecycle status; and dry-run/apply retention cleanup. | `agents` (`register` · `list` · `thread_start` · `thread_list` · `join` · `leave` · `members` · `add_member` · `remove_member` · `archive` · `post` · `history` · `message` · `inbox` · `ack` · `wait` · `cleanup` · `status`) |\n| **Agent shells** | Run headless terminal sessions in the background, capture recent retained output after commands exit, and explicitly stop sessions when their work is done. Visual terminal attachment is opt-in through `[shells].visual`. | `shell` (`spawn` · `send` · `capture` · `kill` · `list` · `broadcast`) |\n| **Admin** | Refresh the index after edits, check index health and repo identity, see what's been queried and how many tokens were saved, inspect or clean the on-disk cache, and shrink what an agent carries: a file's outline instead of its text, a diff instead of a re-read, a checkpoint instead of a transcript, plus a wasteful-tool-use report. | `admin` (`status` · `repo` · `rescan` · `cache_stats` · `gc` · `cache_clear` · `telemetry` · `compress` · `delta` · `checkpoint` · `waste`) |\n| **Machine registry** | Machine-wide repo/worktree/branch coordination, backed by the daemon's always-on registry. Advisory claims let agent sessions avoid colliding on the same worktree. | `workspace` (`workspaces` · `worktrees` · `branches` · `claim` · `release`) |\n\n<!-- markdownlint-enable MD013 -->\n\n---\n\n## Installation\n\nThree ways to run basemind, easiest first. All three share the same local index and are safe to run\nside by side.\n\n> **The plugin downloads the basemind program for you** on first use. The MCP-server and CLI paths\n> need it installed yourself — see [Install the program](#install-the-program).\n\n### 1. As a plugin (recommended)\n\nThe plugin sets up everything for you — the server, the helper skills, the agent-comms features, and\nthe slash commands. Pick your coding tool.\n\n<details>\n<summary><strong>Claude Code</strong></summary>\n\nIn the session (not your shell), run in order:\n\n```text\n/plugin marketplace add Goldziher/basemind\n/plugin install basemind@basemind\n```\n\nRestart, then run `/bm-statusline` once to turn on the live statusline (a one-time step — see\n[Statusline](#install-the-program)). **Turn on auto-update for the `basemind` marketplace**\n(Claude Code's plugin manager): the plugin then tracks each new release automatically, and the\nlauncher resolves the latest *published* release, so you always get the current index format and\ntool set and startup stays reliable even during a release. Prefer to control timing? Update the\nmarketplace regularly by hand instead.\n\n</details>\n\n<details>\n<summary><strong>Codex</strong></summary>\n\n```bash\ncodex plugin marketplace add Goldziher/basemind\ncodex plugin add basemind@basemind\n```\n\nIn the app: open the **Plugins** sidebar and add basemind. The CLI and IDE share one config file.\nThe plugin starts the latest published GitHub release from the project workspace; it never runs from\nthe installed plugin cache or races a shared `npx` install.\n\n</details>\n\n<details>\n<summary><strong>Cursor</strong></summary>\n\nIn Agent chat: `/add-plugin basemind` (once listed), or go to **Dashboard → Settings → Plugins →\nTeam Marketplaces → Import from Repo** and point it at `https://github.com/Goldziher/basemind`.\n\n</details>\n\n<details>\n<summary><strong>Gemini CLI</strong></summary>\n\n```bash\ngemini extensions install https://github.com/Goldziher/basemind\n```\n\nUpdate later with `gemini extensions update basemind`.\n\n</details>\n\n<details>\n<summary><strong>Factory Droid</strong></summary>\n\n```bash\ndroid plugin marketplace add https://github.com/Goldziher/basemind\ndroid plugin install basemind@basemind\n```\n\n</details>\n\n<details>\n<summary><strong>GitHub Copilot CLI</strong></summary>\n\n```bash\ncopilot plugin marketplace add Goldziher/basemind\ncopilot plugin install basemind@basemind\n```\n\n</details>\n\n<details>\n<summary><strong>OpenCode</strong></summary>\n\nAdd to `opencode.json` (project) or `~/.config/opencode/opencode.json` (global):\n\n```json\n{ \"plugin\": [\"basemind-opencode@latest\"] }\n```\n\n</details>\n\n<details>\n<summary><strong>Kimi Code</strong></summary>\n\n```text\n/plugins install https://github.com/Goldziher/basemind\n```\n\nKimi doesn't support the comms auto-notifications, but the chat tools still work.\n\n</details>\n\n<details>\n<summary><strong>Hermes</strong></summary>\n\nHermes exposes MCP servers through config, so basemind's tools are wired there. Two steps — the\nbinary + MCP wiring gives you the tools; a small standalone plugin package adds the helper skills,\nslash commands, and comms notifications.\n\nFirst [install the program](#install-the-program) (Homebrew / npm / cargo / release — **not** pip),\nthen add the server to `~/.hermes/config.yaml` (this is what gives you the nine domain tools):\n\n```yaml\nmcp_servers:\n  basemind:\n    command: basemind\n    args: [serve]\n```\n\nFor the helper skills, slash commands, and agent-comms notifications, install the standalone plugin\ninto the same Python environment Hermes runs in, then enable it (general plugins are opt-in):\n\n```bash\npip install basemind-hermes-plugin\nhermes plugins enable basemind\n```\n\nThe plugin is pure-Python and ships no binary — it shells out to the `basemind` you installed above.\nComms auto-notifications are best-effort; the chat tools work regardless.\n\n</details>\n\n<details>\n<summary><strong>Antigravity &amp; pi</strong></summary>\n\n**Antigravity** uses a shared MCP config — [install the program](#install-the-program), then add the\n[generic MCP block](#2-as-an-mcp-server). If you already use the Gemini extension,\n`agy plugin import gemini` brings it across.\n\n**pi**: `pi install git:github.com/Goldziher/basemind`. pi has no MCP support, so basemind runs\nthrough its [CLI](#3-as-a-cli) here.\n\n</details>\n\n### 2. As an MCP server\n\nIf your tool speaks MCP but you're not using the plugin, [install the program](#install-the-program),\nthen register it:\n\n```json\n{\n  \"mcpServers\": {\n    \"basemind\": { \"command\": \"basemind\", \"args\": [\"serve\"] }\n  }\n}\n```\n\nEach tool says whether it only reads or can change things, so your client can auto-approve the safe\nones and ask before the rest. If `basemind` isn't found, use the full path from `which basemind`.\n\n<details>\n<summary><strong>Per-tool specifics</strong> (Claude Code · Cursor · Windsurf · Codex · Gemini · Copilot · Droid · Cline · Continue · OpenCode · Hermes)</summary>\n\n- **Claude Code** — `claude mcp add basemind -- basemind serve` (add `--scope user` for all\n  projects; the `--` is required). Or commit a `.mcp.json` at the repo root with the block above.\n- **Cursor** — put the block above in `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global).\n- **Windsurf** — `~/.codeium/windsurf/mcp_config.json` (or Cascade → MCP servers → manage), then\n  **Refresh**.\n- **Codex** — `codex mcp add basemind -- basemind serve`, shared by the CLI and IDE.\n- **Gemini CLI** — `gemini mcp add basemind basemind serve`, or the block above in\n  `~/.gemini/settings.json`.\n- **GitHub Copilot CLI** — `/mcp add` in-session, or `~/.copilot/mcp-config.json` with\n  `\"type\": \"local\"` and `\"tools\": [\"*\"]`.\n- **Factory Droid** — `droid mcp add basemind \"basemind serve\"`, or `~/.factory/mcp.json`.\n- **Cline** — MCP Servers icon → Configure → add the block above.\n- **Continue** — `.continue/mcpServers/basemind.yaml` with `command: basemind`, `args: [serve]`.\n- **OpenCode (without the plugin)** — `opencode.json` under key `mcp`, with `command` as an array\n  `[\"basemind\", \"serve\"]`.\n- **Hermes** — `mcp_servers.basemind` in `~/.hermes/config.yaml` (YAML: `command: basemind`,\n  `args: [serve]`). For helper skills + comms notifications, `pip install basemind-hermes-plugin`\n  (a standalone pure-Python plugin, no binary), then `hermes plugins enable basemind` — see the\n  Hermes plugin section above.\n- **Any other tool** — point it at the command `basemind` with the argument `serve`.\n\n</details>\n\n### 3. As a CLI\n\nThe standalone program, for scripts, headless runs, and CI. [Install it](#install-the-program), then:\n\n```bash\nbasemind scan                          # index the project once\nbasemind code symbols \"parseQuery\"     # find a definition by name\nbasemind code references \"processFile\" # find everywhere it's called\nbasemind git blame src/main.rs         # who last changed each line\nbasemind watch                         # keep the index fresh as files change\n```\n\nFull command list in the [CLI reference](#cli-reference).\n\n### Install the program\n\nThe MCP and CLI paths need `basemind` available on your system. (The plugin does this for you.)\n\n<!-- markdownlint-disable MD013 -->\n\n| Channel | Command | Includes |\n|---|---|---|\n| Homebrew | `brew install Goldziher/tap/basemind` | everything |\n| npm | `npm install -g basemind` | everything |\n| pip | `pip install basemind` | everything |\n| cargo | `cargo install basemind --locked` | code + git only |\n| cargo (full) | `cargo install basemind --features full --locked` | everything |\n| GitHub releases | [Download a binary](https://github.com/Goldziher/basemind/releases) | everything |\n\n<!-- markdownlint-enable MD013 -->\n\nThe Homebrew / npm / pip / GitHub downloads include the full feature set — documents, OCR, search,\nweb crawl, shared memory, agent comms, and agent shells — so the first run downloads the models it\nneeds. The plain `cargo install` builds the code-map and git tools only.\n\n### Get started\n\nAfter installing, run **`basemind init`** (CLI) — or **`/bm-init`** if your tool supports slash\ncommands — from the repo root. It's re-runnable and safe to call again later:\n\n- Writes a commented `basemind.toml` scaffold at the repo root, if one doesn't already exist.\n- Lets you pick which capabilities to advertise (interactive prompt in a TTY, or non-interactive\n  with `--yes`, `--with <capability>`, `--without <capability>`). Capability slugs:\n  `code-search-navigation`, `code-mapping-architecture`, `git-history`, `agent-comms`,\n  `documents-rag`, `semantic-search`.\n- Injects a \"prefer basemind over grep/read/git\" rules block into your repo's agent-instructions\n  file — `.ai-rulez/rules/basemind-usage.md` if `.ai-rulez/config.toml` is present (run\n  `ai-rulez generate` afterward), else `CLAUDE.md`, else `AGENTS.md`, else a new `CLAUDE.md`. The\n  block is delimited (`<!-- BEGIN basemind ... -->` / `<!-- END basemind -->`) so re-running\n  replaces it in place instead of duplicating it.\n\nPreview changes without writing with `--print`; skip the rules step with `--no-rules`; steer the\ntarget explicitly with `--rules-target <auto|claude|agents|ai-rulez|none>`.\n\n<details>\n<summary><strong>Statusline</strong> (Claude Code)</summary>\n\nRun `/bm-statusline` once. This is a one-time step because Claude Code doesn't let plugins set the\nmain statusline themselves — so basemind asks the assistant to make the one-line settings change on\nyour behalf, and it sticks from then on.\n\nIt shows two lines:\n\n```text\nOpus · basemind · ⎇ main · 12% ctx\n◆ basemind  ●  1,247 files · 23m ago  │  312 calls · 180 srch · 44 git · 12 docs  │  1.4M saved  │  ✉ 3 @reviewer\n```\n\nThe dot is green when basemind is live and fresh, amber when idle, red when stale. The middle shows\nactivity by type, then tokens saved, then unread messages. Adjust with\n`BASEMIND_STATUSLINE=full|compact|minimal`, or hide the top line with `BASEMIND_STATUSLINE_CONTEXT=0`.\n\n</details>\n\n---\n\n## Demos\n\n<!-- markdownlint-disable MD013 -->\n\n<p align=\"center\"><img src=\"docs/media/demo.gif\" alt=\"basemind CLI: scan, then symbol / reference / call-graph / blame queries\" width=\"760\"></p>\n<p align=\"center\"><em>The same engine from the CLI — <code>scan</code>, then symbol / reference / call-graph / blame queries.</em></p>\n\n<p align=\"center\"><img src=\"docs/media/semantic-demo.gif\" alt=\"Semantic search over the documents store\" width=\"820\"></p>\n<p align=\"center\"><em>Searching documents by meaning, not keywords, across 90+ formats.</em></p>\n\n<p align=\"center\"><img src=\"docs/demos/code-review-panel.gif\" alt=\"Three named reviewer agents posting findings to a shared repo-scoped thread, replying to each other, and an orchestrator synthesizing a verdict over the comms CLI\" width=\"820\"></p>\n<p align=\"center\"><em>Multi-agent code-review panel: named reviewers coordinate in a repo-scoped thread (post, reply, synthesize) — entirely over <code>basemind agents</code>.</em></p>\n\n<!-- markdownlint-enable MD013 -->\n\n---\n\n## How it works\n\n<details>\n<summary><strong>From one scan to instant answers</strong></summary>\n\n`basemind scan` reads your project once, in parallel. It maps your code with\n[tree-sitter] (across [300+ languages][tslp]) and pulls text out of your documents with\n[xberg], then saves the result to a global cache under the XDG data directory, keyed by workspace —\nnothing is written into your repo. After that, `basemind serve` keeps the map in memory and answers\nquestions instantly — no re-reading the project for each one. When files change, it updates only what\nchanged. A single background daemon on the machine is the sole writer to that cache, so multiple\n`serve` sessions on the same repo (or on different worktrees of it) all read and write concurrently\ninstead of one falling back read-only. See [Global cache & the daemon](#how-it-works) below.\n\nNavigation is **scope- and import-aware** for JavaScript/TypeScript, **Python, and Java**: basemind\nresolves each use to the definition it actually binds to, so a shadowed local isn't confused with an\nimport and `code` mode `definition` lands on the right target (including across files for imports). Every\nother language still gets fast tree-sitter scope binding. Precise Python/Java resolution runs GitHub\nstack-graphs-style `.tsg` name-binding rules via an in-tree engine (`crates/`), with no per-language\nLSP server.\n\nResolution **refines, but never shrinks, a result set.** `code` mode `callers` reports every call site\nwhose callee matches the name — the same sound floor mode `references` uses — and marks each hit `resolved`\nwhen resolution proved it binds to that definition (`resolved_total` counts them). It deliberately\ndoes *not* return only the resolved subset: resolution cannot see through a module-object import\n(`from pkg import mod` then `mod.f()`) or an unresolvable path alias, so filtering to it would drop\nreal callers and report the remainder as complete. Filter on `resolved` when you want precision; trust\n`total` when you need completeness.\n\nMarkdown and Obsidian vaults are first-class: headings become navigable symbols (so `code` modes\n`outline` and `symbols` work over a notes vault); `[[wikilinks]]`, `![[embeds]]`, and standard\n`[text](Note.md)` links all become references — so mode `references` on `\"Note\"` returns that note's\nbacklinks regardless of link style; and `#tags` (inline or in YAML frontmatter) become references\ntoo, so mode `references` on `\"#project\"` lists every note carrying that tag.\n\n```mermaid\nflowchart LR\n  A([\"Coding agent\"])\n  R[\"Your project<br/>code · documents · git\"]\n  S[\"basemind scan<br/>map code & read documents\"]\n  D[(\"Global cache<br/>per-OS data dir\")]\n  V[\"basemind serve<br/>answers questions\"]\n  R --> S --> D --> V\n  A <-->|asks questions| V\n  classDef accent fill:#2563eb,stroke:#1e40af,color:#fff\n  class S,V accent\n```\n\nSearch and memory are powered by a vector store ([LanceDB]).\n\n</details>\n\n<details>\n<summary><strong>Index lifecycle &amp; freshness</strong></summary>\n\n`basemind serve` answers the MCP handshake immediately and warms the code map into memory in the\nbackground, so a client never blocks waiting for a large repo to load. The `status` tool reports\n`warming` (still loading) and, once done, `warm_ms`; a first-time index build similarly reports\n`indexing` / `index_build_ms`.\n\nWhile the server isn't fully ready, `status` and every code-map read tool may carry a `notice`\nobject — `{ state, message, retry }` — instead of (or alongside) their normal result:\n\n| `state` | Meaning | `retry` |\n|---|---|---|\n| `warming_up` | Loading an existing index into memory. | `true` |\n| `building_index` | Indexing from scratch (no cache entry for this workspace yet). | `true` |\n| `rescanning` | Incremental rescan after a file change; current results are usable but may be stale. | `false` |\n\nTreat an empty or partial result carrying a `notice` as \"retry shortly,\" not \"no matches\" — poll\n`status` (or just retry the call) until the notice clears.\n\n</details>\n\n<details>\n<summary><strong>Global cache &amp; the daemon</strong></summary>\n\nIndex state lives under a single global cache — `~/.local/share/basemind/` on Linux,\n`~/Library/Application Support/basemind/` on macOS (override with `BASEMIND_DATA_HOME`) — keyed by\nworkspace, never inside your repo. The\ncontent-addressed blob store is machine-wide too: identical file content scanned from different repos\nor worktrees is extracted and stored once.\n\nA workspace root must be a project: a git repository, or a directory containing `basemind.toml`.\nAnything else is refused, because basemind opens a root read-write and indexes every file beneath\nit — so an accidentally inherited root (`/`, your home directory, or wherever an MCP host happened\nto start) would become a whole-filesystem scan. Run `basemind init` to mark a directory you do want\nindexed, or set `BASEMIND_ALLOW_ANY_ROOT=1` to skip the check. A filesystem or volume root is\nrefused unconditionally and cannot be overridden.\n\nA single background daemon per machine is the sole writer to that cache. `basemind serve` opens its\nstore read-only and forwards writes (scan / rescan) to the daemon over a local socket, so N `serve`\nsessions on the same repo — or on different worktrees of it — all read and write concurrently instead\nof a second session silently falling back to a stale, read-only view. The daemon also keeps a cheap,\nalways-on registry of repos, worktrees, and branches (`workspaces` / `worktrees` / `branches`), and\n`worktree_claim` / `worktree_release` give agent sessions an advisory way to avoid colliding on the\nsame worktree.\n\n`basemind statusline` queries the daemon for the workspaces currently active and prints a compact\nline for your shell prompt; it prints nothing when no daemon is running.\n\nThe daemon is started on demand, detached with `setsid(2)`. That changes the session and the process\ngroup but **not** the cgroup, so on Linux an auto-spawned daemon lives in the cgroup of whatever\nshell or editor happened to start it — outside any `MemoryMax` you configured for basemind. No code\nin basemind can change that; a process cannot move its own children into a cgroup it does not\ncontrol. If you want an enforced memory ceiling, your unit has to be the thing that starts the\ndaemon: set `BASEMIND_NO_AUTOSPAWN=1` everywhere (basemind then connects to a running daemon but\nnever starts one; `basemind comms start` deliberately still does) and install the ready-made user\nunit at [`docs/systemd/basemind-comms.service`](docs/systemd/basemind-comms.service), which also\nlists the two commands that verify the ceiling is real rather than merely configured.\n\nThe daemon can additionally serve MCP over streamable HTTP on loopback, but that front-end is\n**opt-in**: it binds only when `BASEMIND_ALLOW_HTTP` is truthy in the daemon's environment, and every\nrequest must then present the bearer token published as the second line of `<comms_dir>/http.addr`\n(mode `0600`). Plugin manifests and the CLI use the stdio transport and need none of this.\n\n</details>\n\n<details>\n<summary><strong>How agents coordinate</strong></summary>\n\nA single shared service in the background lets agents talk to each other — even across different\ntools and different repos on the same machine. Agents coordinate in **threads** — each addressed by\nat least two of subject / path-glob / members, discovered by scope rather than joined globally — and\neach has a personal **inbox**. Messages come in two parts: a short headline (subject and sender)\nthat's cheap to skim, and the full body, fetched only when an agent wants to read it. An agent never\nsees its own posts in its inbox. Idle threads auto-archive.\n\nThe plugin makes sure agents notice messages without being asked — through the built-in instructions,\na notice at session start and each turn, and a quiet background check every few seconds.\n\n```mermaid\nflowchart LR\n  A[\"Agent A<br/>Claude Code · repo X\"]\n  B[\"Agent B<br/>Cursor · repo Y\"]\n  BR[\"Shared comms service<br/>threads · inboxes\"]\n  A <-->|post · read| BR\n  B <-->|post · read| BR\n  classDef accent fill:#2563eb,stroke:#1e40af,color:#fff\n  class BR accent\n```\n\n</details>\n\n<details>\n<summary><strong>Agent shells</strong></summary>\n\nIncluded in every prebuilt download (and in `cargo install --features shells` / `full`): agents can\nopen terminal sessions in the background, type into them, and read what's on screen — no extra tools\nto install. Sessions can be fully headless, or opened in a real terminal tab or window so you can\nwatch along. A spawned session and the agent that started it can message each other over comms.\n\n</details>\n\n---\n\n## Token saving\n\n<details>\n<summary><strong>Good habits the plugin sets up for you</strong></summary>\n\nThe plugin nudges agents toward the cheap path by default:\n\n- Get a file's outline before opening it — then read only the part you need.\n- Search for a definition instead of grepping for it.\n- Look up who calls a function instead of grepping for call sites.\n- Refresh the index after edits instead of restarting the server.\n- Don't re-read a file basemind already mapped.\n\nOptional guardrails enforce this at the moment a tool is used:\n\n- **Guard** — gently redirects `grep`-style searches to the matching basemind tool. On by default;\n  set `BASEMIND_GUARD=off` to disable, or `redirect` to block instead of nudge.\n- **Output compressor** — `BASEMIND_COMPRESS_OUTPUT=1` shrinks long command output. It never touches\n  anything that looks like a credential and leaves output alone if it can't help.\n- **Re-read shortcut** — `BASEMIND_DELTA_READS=1` shows just what changed when an agent re-reads a\n  file it already read this session.\n\n</details>\n\n<details>\n<summary><strong>Compression that understands code</strong></summary>\n\nbasemind shrinks code by keeping the shape and dropping the bodies — function signatures and imports\nstay, the implementations go — because a signature is useless without its shape. For prose it does a\nlight cleanup (extra whitespace, filler, repeated paragraphs). It reports honest before/after token\ncounts, and the code version is exact — nothing is lost, just set aside. `expand` brings any one\nfunction's full body back when an agent actually needs it: compress to an outline, expand only what\nyou need.\n\n</details>\n\n---\n\n## Performance\n\n<details>\n<summary><strong>Scan speed</strong></summary>\n\nMeasured on an Apple M4 (10 cores — 4 performance + 6 efficiency, 16 GB, macOS 26) with the\nhardening harness (`scripts/harden.sh`), which clones each upstream repo fresh and scans its code\nmap. Warm, steady-state numbers; the first scan of a cold project is slower.\n\n| Project | Files | Languages | Scan time |\n|---|---|---|---|\n| gin | 130 | Go | 0.1 s |\n| requests | 128 | Python | 0.1 s |\n| ripgrep | 221 | Rust | 0.6 s |\n| tokio | 861 | Rust | 0.4 s |\n| react | 7 242 | TS / JSX | 2.0 s |\n| django | 7 065 | Python | 2.4 s |\n| TypeScript compiler | 81 324 | TS / JS / JSON | 18 s |\n\nThe TypeScript compiler is the worst case — 81k files in about 18 seconds. Re-scans only look at\nwhat changed, so keeping a project up to date is far faster than the first scan.\n\nOnce running, most code questions answer in **under a millisecond**, symbol and call-graph searches\nin a few milliseconds, and document search in around 200 ms — because the map is held in memory\nrather than read from disk each time.\n\n</details>\n\n<details>\n<summary><strong>Git history queries</strong></summary>\n\nbasemind precomputes a per-repo git-history index (path → commit posting lists, stored newest-first)\nso the history modes — `touching`, `recent`, `churn`, `by_path`, and `symbol_history`'s commit walk\n— are posting-list lookups. Warm in-process query latency on the same M4:\n\n| Repo | Commits | `git` `touching` | `git` `recent` | index build | index size |\n|---|---|---|---|---|---|\n| django | 2 000 | 39 µs | 15 µs | 0.5 s | 1.7 MB (6 % of `.git`) |\n| tokio | 3 984 | 37 µs | 13 µs | 0.9 s | 2.1 MB (12 %) |\n| requests | 6 480 | 38 µs | 15 µs | 1.0 s | 1.9 MB (14 %) |\n| TypeScript | 2 000 | 37 µs | 13 µs | 3.2 s | 30 MB (12 %) |\n\nHistory queries answer in **tens of microseconds**, flat across history depth, because the\nnewest-first posting lists decode only the commits a query returns. The index builds in well under a\nsecond to a few seconds and costs **6–22 % of `.git`** on disk.\n\nIt is a pure accelerator: the tools use it only when it is fresh (`last_indexed_head == HEAD`) and\notherwise walk history directly, so it can never serve stale results — and it rebuilds automatically\nwhen history is rewritten (filter-repo / rebase / force-push). Reproduce with\n`cargo bench --bench git_history` or the git-ops block in `scripts/harden.sh`.\n\n</details>\n\n<details>\n<summary><strong>Measuring query latency (<code>elapsed_us</code>)</strong></summary>\n\nEvery latency-relevant mode — all of `code` and `graph`, all of `git`, the `admin` read modes, and\nthe document / memory search modes — reports its own latency as **`elapsed_us`** on its response.\nDon't wrap the CLI in `time`; ask basemind.\n\nResolution is **microseconds** on purpose: an indexed `git` mode `touching` is ~37 µs, so\nmillisecond granularity would round the hot path to `0`.\n\n**What `elapsed_us` includes** — the tool body's own execution: index and store lookups, git walks,\nranking, and building the response.\n\n**What it excludes** — MCP / JSON-RPC transport (which the server cannot observe), argument\ndeserialization, and serialization of the response itself. Excluding encoding keeps the number\ncomparable across `format: \"json\"` and `format: \"toon\"` and across result-set sizes: it reports\n*query* cost, not *encoding* cost.\n\n**The one caveat, stated plainly:** most read tools begin by awaiting the in-RAM code map, and the\ngit tools lazily build their history index on first use. Both waits happen *inside* the measured\nregion, so a first call against a cold server is much slower than the steady-state call after it.\nWhen the server is still warming or building, the response carries a `notice`\n(`warming_up` / `building_index` / `rescanning`) — **discard any sample carrying a `notice`** if you\nare measuring steady-state latency.\n\nThe CLI adds a second number, `startup_us`, covering process startup: clap parsing, the tokio runtime,\nthe store open, and the config/git-cache load. It is reported separately because it is exactly the\npart of a `time basemind …` measurement that was never the query — and a long-running MCP server pays\nit once at boot, not per call:\n\n```console\n$ basemind code symbols run_workspace_grep --limit 1 --json\n{\n  ...\n  \"elapsed_us\": 90,        # the query\n  \"startup_us\": 957887     # everything else a `time` wrapper would have charged to it\n}\n\n$ basemind code references parse_kind --limit 3\n...\n(6.5 ms query · 852.9 ms startup)\n```\n\nThat first example is the whole point: the query took 90 µs, while the process spent ~0.96 s getting\nready to run it. A `time basemind …` wrapper would have reported the second number and told you\nnothing about the first.\n\n</details>\n\n---\n\n## Configuration\n\n<details>\n<summary><strong>Config file &amp; overrides</strong></summary>\n\nThe config lives at the **repo root** as `basemind.toml` (committed). The cache it drives is derived\nstate — held in the global cache under the XDG data directory, wiped and rebuilt on schema bumps —\nso config never belongs there and nothing basemind-owned is written into your repo. Run\n`basemind init` to drop a fully-commented scaffold (documenting every option) at the root. The legacy\nin-cache path (`.basemind/basemind.toml`, from before the global-cache move) is still read as a\nfallback for older checkouts. The full schema is at `schema/basemind-config-v1.schema.json`:\n\n```toml\n# basemind.toml  (repo root — commit this)\n\"$schema\" = \"v1\"\n\n[scan]\nrespect_gitignore = true\n# Follow symlinks during the walk. Off by default — symlinks often escape the repo (e.g. Bazel's\n# bazel-* convenience symlinks). Turn on for repos that symlink real source into place.\nfollow_symlinks = false\n# `exclude` is ADDED ON TOP of an always-on floor (node_modules, target, dist, build, out, .venv,\n# venv, __pycache__, *.pyc, .pytest_cache/.mypy_cache/.ruff_cache/.tox, .next/.nuxt/.svelte-kit,\n# vendor, .gradle, .terraform, coverage, bazel-*, .git, .basemind, .idea, .DS_Store). You can add to\n# it but not remove a floor entry.\nexclude = []\n# Index directories outside the repo root too — e.g. a Bazel external repo cache — so their\n# symbols resolve in search / references / outlines. External files are keyed by absolute path;\n# (re-)indexed on a full `basemind scan` only (not live-watched). Requires the operator to set\n# BASEMIND_ALLOW_EXTRA_ROOTS=1 in the environment: this file lives inside the repository, so\n# without that opt-in a cloned repo could point basemind at your ~/.ssh. Extra roots count toward\n# max_candidates and follow symlinks only when follow_symlinks is on.\nextra_roots = [\"/private/var/tmp/_bazel_you/abc123/external\"]\n# Ceiling on how many candidate files one scan may keep, across the repo walk and every extra root.\n# Exceeding it aborts before any extraction or index write, and the error names the heaviest\n# contributing directories — so a vendored tree that slipped past .gitignore is a one-line fix\n# instead of an out-of-memory kill. It also bounds how far the walk may travel to find them. It does\n# NOT bound bytes read or index size, and does not apply to `--staged` / `--rev` (those enumerate\n# from git, not from a walk). 0 disables both bounds.\nmax_candidates = 500_000\n\n[code_intel]\n# Precise, scope- and import-aware resolution (JS/TS via oxc; Python/Java via stack-graphs). On by\n# default. Set false to fall back to fast tree-sitter locals binding for every language. Applies to\n# files (re)scanned after the change.\nprecise_resolution = true\n\n[documents]\nenabled = true\n# Embed documents for semantic search (ON — embeddings pay off on real prose / OCR).\nembed = true\n# Model preset: fast | balanced (default, 768-dim) | quality | multilingual.\n# Changing the preset forces a FULL RE-EMBED of the corpus (time + CPU): every document is\n# re-encoded at the new model's dimension.\nembedding_preset = \"balanced\"\n# Documents that are extracted + indexed but never embedded (keyword-only).\nembed_exclude = []\n# Route archives (.zip/.tar/.jar/…) into the recursive extractor. Off by default so one archive\n# can't explode into thousands of embeds; true binaries are always skipped.\nextract_archives = false\n\n[code_search]\nenabled = true\n# Vector embeddings for code are OFF by default — a general English model on code isn't worth the\n# cost, and NL→symbol is already served by the BM25 keyword lane. Chunking + keyword search work\n# regardless. Turn on only for vector search over code (downloads an ONNX model, re-embeds on\n# preset change).\nembed = false\nembed_exclude = []\n# Cap on chunks indexed per source file. A generated parser table or a checked-in bundle otherwise\n# fans one file out into a chunk count bounded only by max_file_bytes, and every chunk costs a\n# keyword posting, a vector row, and (with embed on) an embed. Over-cap files are still chunked and\n# cached — outline and grep are unaffected — they just contribute no postings and no vector rows.\nmax_chunks_per_file = 2000\n\n[resources]\n# Memory ceiling for this process, in MiB. A positive integer is an explicit ceiling; 0 or \"auto\"\n# (the default) derives one — 75% of an enforced cgroup limit, or 50% of machine RAM, floored at\n# 512 MiB; \"off\" disables it. ADVISORY: workers park while over the ceiling and are admitted anyway\n# after five seconds, so it shapes peak memory rather than enforcing a hard limit. To actually cap\n# the daemon's memory, run it from your own resource-controlled unit — see\n# `docs/systemd/basemind-comms.service`.\nmax_footprint_mb = \"auto\"\n# Byte budget (MiB) for the MCP read stack's decoded-outline cache, per workspace. 0 = unbounded.\n# A miss costs one blob read and never changes an answer.\nmax_map_cache_mb = 256\n```\n\nAny tool call can override these settings for that one request, and settings map to environment\nvariables in the obvious way: `--llm-api-key` becomes `BASEMIND_LLM_API_KEY`.\n\n</details>\n\n---\n\n## CLI reference\n\n<details>\n<summary><strong>Full command list</strong> — code · graph · git · memory · admin · cache · web · agents · workspace · shell</summary>\n\nCLI commands mirror the MCP tools 1:1 (enforced by `tests/cli_parity.rs`). Add `--json` for\nmachine-readable output.\n\n<!-- markdownlint-disable MD013 -->\n\n**Code (`basemind code`)**\n\n| Command | Purpose |\n|---|---|\n| `outline <path> [--l2]` | A file's structure: symbols, lines, signatures. `--l2` adds calls + docs. |\n| `symbols <name> [--kind]` | Find a definition by name, optionally filtered by kind. |\n| `grep <pattern> [--language --path-contains]` | Pattern search with filters. |\n| `files [--path-contains --language]` | List indexed files. |\n| `find <fragment>` | Locate a file by a fuzzy fragment of its name or path (fzf/fd-style). |\n| `definition <path> <line> [--column]` | Resolve a reference position to its scope-resolved definition. |\n| `references <name>` | Find everywhere a name is called. |\n| `callers <path> <name> [--kind]` | Find callers of one specific definition. |\n| `implementations <trait>` | Types that implement or inherit from a name. |\n| `dependents <module>` | What imports a given module. |\n| `expand <path> <name> [--kind]` | A symbol's raw source body (the inverse of an outline entry). |\n| `semantic <query> [--limit --lane --format]` | Search code by meaning; returns pointers. Needs `--features code-search`. |\n| `chunk <path> [--chunk-id --byte-start]` | Fetch one code chunk's source body (the `semantic` fetch half). |\n\n**Graph (`basemind graph`)**\n\n| Command | Purpose |\n|---|---|\n| `calls <name> [--direction --max-depth --max-nodes]` | Walk the call chain up (`callers`, default) or down (`callees`). |\n| `neighbors <name> [--direction --depth --edges --max-nodes]` | A symbol's n-hop neighborhood — its blast radius before you change it. |\n| `path <from> <to> [--edges --include-contains]` | Confidence-weighted shortest route between two symbols. |\n| `subgraph <name> [--depth --edges --max-nodes]` | The neighborhood cut to its most central nodes — readable, not a dump. |\n| `communities [--algorithm --max-communities]` | Cluster the graph into de-facto modules with deterministic labels. |\n| `map [--granularity --focus --depth --edges --include-churn]` | Architecture overview: hub modules/symbols ranked by centrality + churn, plus dependency cycles (SCCs). `--edges` selects lanes (`calls`/`imports`/`inherits`/`both`/`all`); every edge carries a provenance tag (`extracted`/`inferred`/`ambiguous`) + confidence. |\n| `export [--format --focus --edges --write]` | Render as node-link JSON / DOT / Mermaid / GraphML / Cypher / HTML / SVG. |\n| `display [--format --no-open]` | Open a rendered view in the human's desktop viewer. `--no-open` writes the artifact and returns its path. |\n| `open [--format --no-open]` | Return a live `http://…/ui` URL for the interactive graph (or a `file://` export). The live page needs the daemon's HTTP front-end, which is opt-in — set `BASEMIND_ALLOW_HTTP=1` in the daemon's environment; without it you get the `file://` export. `--no-open` launches nothing. |\n\n**Git (`basemind git`)**\n\n| Command | Purpose |\n|---|---|\n| `status` | What's staged and unstaged right now. |\n| `recent [--limit] [--no-files]` | Recent commits with their files (a recency window, not a search). |\n| `search <pattern> [--field author\\|message\\|all] [--limit]` | Full-text search over commit history at full branch depth. |\n| `touching <path>` / `by-path <pattern>` | Commits for a path or a changed-path regex. |\n| `churn [--window --top-k]` | The most frequently changed files. |\n| `diff <path> <old> <new>` / `diff-outline <path> [--rev]` | File or structure diff across commits. |\n| `blame <path>` / `blame-symbol <path> <name>` | Who last changed each line / a symbol. |\n| `symbol-history <path> <name>` | When a symbol's body changed over time. |\n\n**Memory (`basemind memory`)**\n\n| Command | Purpose |\n|---|---|\n| `put <key> <value>` / `get <key>` / `delete <key>` | Store, retrieve, or remove a value. |\n| `list [--prefix]` | List keys, optionally by prefix. |\n| `search <query>` | Search stored values by meaning. |\n| `documents <query>` | Search indexed PDFs / Office / HTML / images by meaning. |\n| `mine [--commits --min-count --min-confidence --max-files]` | Suggest notes from files that change together. |\n| `proposals [--kind --limit]` | List pending suggestions. |\n| `accept <id> [--key]` / `reject <id> [--reason]` | Keep a suggestion / dismiss it for good. |\n| `audit [--key --individual --dry-run --include-archived]` | Recompute memory importance, archive stale entries, refresh verdicts. |\n\n**Admin (`basemind admin`)**\n\n| Command | Purpose |\n|---|---|\n| `status` / `repo` | Index health (files, languages, scan state) / git identity (branch, HEAD, origin). |\n| `rescan [PATH…] [--full]` | Re-index the working tree, or only the given paths. |\n| `cache-stats` / `gc` | On-disk footprint + process RAM / reclaimable-blob report. |\n| `cache-clear --component <c> [--confirm]` | Clear one cache component (`views`/`all` need the offline `basemind cache clear`). |\n| `telemetry [--window --tool]` | What's been queried and how many tokens were saved. |\n| `compress` / `delta` / `checkpoint` / `waste` | Outline a file, diff a re-read, summarize a session, flag wasteful tool use. |\n\n**Cache (`basemind cache`)**\n\n| Command | Purpose |\n|---|---|\n| `stats` | Disk footprint (per-component + total, matches `du`) and process RAM. |\n| `gc` | Reclaim unused space (safe while the server runs). |\n| `clear --component <comp>` | Clear part of the cache (`views`, `blobs`, `git-cache`, `all`, …). |\n\n**Web (`basemind web`)**\n\n| Command | Purpose |\n|---|---|\n| `scrape <url>` | Fetch and index a single page. |\n| `crawl <seed-url>` | Follow links from a starting URL. |\n| `map <url>` | Discover a site's pages without fetching bodies. |\n\n**Agents (`basemind agents`, `--features comms`)**\n\nEvery command takes `--as-agent <ID>` to act as a named sub-identity.\n\n| Command | Purpose |\n|---|---|\n| `register [--name --description --version --skill]` / `list [--thread]` | Publish your identity card / list agents the broker knows. |\n| `thread-start [--subject --path --member]` / `thread-list [--subject-contains --include-archived]` | Start a thread (addressed by ≥2 of subject / path / members) / list threads discoverable to you. |\n| `join <thread>` / `leave <thread>` / `members <thread>` | Join, leave, or list the members of a thread. |\n| `add-member <thread> <id>` / `remove-member <thread> <id>` / `archive <thread>` | Manage membership and archive a thread (creator only). |\n| `post <thread> <subject> [--body --reply-to --tag]` | Post a message to a thread. |\n| `history <thread> [--since-hours]` / `inbox [--mark-read]` / `wait [--thread --timeout-secs]` | A thread's history / your cross-thread inbox / block until a peer posts. |\n| `message <id>` | Read one message body in full — the only body path. |\n| `ack [--message-id … \\| --thread <t> --to-seq <n>]` | Clear read messages by advancing per-thread read cursors. |\n| `cleanup [--dry-run \\| --apply] [retention overrides]` / `status` | Preview/apply retention / report lifecycle health. |\n\n**Comms daemon (`basemind comms`, `--features comms`)**\n\n| Command | Purpose |\n|---|---|\n| `daemon` / `start` / `stop [--all]` / `status` | The broker daemon: run it, ensure it, stop it (`--all` stops every live daemon on the machine), or inspect pid / version / uptime. |\n| `doctor` | List every live daemon on the machine (pid / comms dir / version / uptime), pruning dead registry entries, and flag a pile-up over the ceiling (`BASEMIND_MAX_DAEMONS`, default 8). |\n\n**Shell (`basemind shell`, `--features shells`)**\n\n| Command | Purpose |\n|---|---|\n| `spawn <command> [--cwd --env --title]` | Start a detached headless shell session; prints a `session_id`. |\n| `send <session-id> <text> [--no-enter]` | Type into a session's stdin. |\n| `capture <session-id> [--lines]` | Read up to 500 recent non-blank retained-output rows (50 by default). |\n| `kill <session-id>` / `list` | End a session / list live sessions. |\n| `broadcast <text> --session <id>…` | Send the same input to several sessions at once. |\n\n**Other commands (`scan`, `serve`, `watch`, …)**\n\n| Command | Purpose |\n|---|---|\n| `scan` / `rescan <path>` | Full scan / update one path. |\n| `watch` | Keep the index fresh as files change (no server). |\n| `serve [--no-watch]` | Start the server (keeps the index fresh by default). |\n| `init` | Re-runnable onboarding: write `basemind.toml`, select capabilities, inject usage rules. |\n| `lang <list\\|install\\|clean>` | Manage downloaded language grammars. |\n| `hook install` | Add a git pre-commit hook that runs a scan. |\n| `compress-output` / `delta --old <path>` | Backends for the optional guardrails above. |\n| `checkpoint` / `detect-waste` | Summarize a session / flag wasteful tool use. |\n\n<!-- markdownlint-enable MD013 -->\n\n</details>\n\n---\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n\n[tree-sitter]: https://tree-sitter.github.io/tree-sitter/\n[tslp]: https://github.com/Goldziher/tree-sitter-language-pack\n[xberg]: https://github.com/xberg-io/xberg\n[LanceDB]: https://github.com/lancedb/lancedb\n",
  "bytes": 47280,
  "sha": "5bdc5011044845dff0a9b2ef1d386bbb2387e88fc12edfe9eb28bc4c07d8f08d",
  "repo_slug": "goldziher/basemind",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_goldziher_basemind_fe42e03a/readme"
}