pi-cbm
Extension that exposes `codebase-memory-mcp` as native Pi tools, adds auto-indexing and deliberate obtimizations for agent-workflows and token saving.
Package details
Install pi-cbm from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-cbm- Package
pi-cbm- Version
2.0.0- Published
- Oct 25, 2026
- Downloads
- 436/mo · 297/wk
- Author
- alexykn
- License
- MIT
- Types
- extension
- Size
- 229.8 KB
- Dependencies
- 0 dependencies · 4 peers
Pi manifest JSON
{
"extensions": [
"./src/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-cbm
Pi extension that exposes codebase-memory-mcp as native Pi tools. `codebase-memory-mcp provides a fast local code graph. pi-cbm adds auto-indexing and adapts it for Pi agents in a way that is deliberately optimized for agent workflows and token saving.
This package does not implement an MCP client. It uses codebase-memory-mcp cli --json <tool> <args> and registers the core tools directly with Pi. When a Pi session starts, it automatically indexes the current git root, or a safe non-git working directory when enabled, in full mode in the background, then re-indexes it whenever its files change so graph tools stay current.
What makes this different
- Token-saving output by default. Several upstream tools return rich graph metadata, fingerprints, scores, and raw analysis fields.
pi-cbmstrips less-useful metadata by default and returns compact, location-first results. Useinclude_metadata: truewhen you need the full upstream payload. - Source compaction controls. Tools that may return code support
full_outputandmax_symbol_lines. Normal-sized symbols are returned directly; oversized code blocks are compacted and the full uncompacted JSON is saved to a temp file. - Symbol-first helpers. Upstream
get_code_snippetworks best when you already know the exactqualified_name.pi-cbmaddsresolve_symbolandread_symbolso the agent can start from a normal symbol name, disambiguate with file/class/route filters, and only read source when the match is unambiguous. - Safe-by-default symbol reading.
read_symbolfails closed on ambiguity: it returns candidate identities instead of guessing and reading the wrong source. When exactly one symbol matches, it calls upstreamget_code_snippetand can optionally include compact direct callers/callees. - Batch source-reading workflows.
get_code_snippets,read_symbols, andsearch_and_read_symbolslet agents inspect several relevant symbols in one tool call instead of looping through many single-symbol calls. These batch tools keep the same compact metadata defaults while preserving essential locations, per-item ambiguity/error results, and source compaction controls. - Current project stays indexed. On Pi session start, the extension indexes the current git root, or a safe non-git working directory when explicitly enabled, in full mode, then checks it periodically in the background and re-indexes only when files changed since the graph was taken (see Index freshness). A cross-process per-repository lease prevents duplicate indexers for one repository, while a configurable global token queue limits indexing across repositories (
PI_CBM_MAX_CONCURRENT_INDEXES, default1). Root, home, system, and common builtin OS directories are never auto-indexed. - Project inference for cwd workflows. Most tools accept optional
project, but for normal current-repo work the extension infers the indexed project from Pi's current working directory. - Query tools only. The agent gets code-exploration tools, not administrative controls.
index_repositoryandlist_projectsare used internally for background indexing and project inference; destructive/admin MCP tools such as project deletion are not registered as Pi tools.
Security
Pi extensions run with your local user permissions. This extension also shells out to the codebase-memory-mcp binary installed on your machine, so install both this package and codebase-memory-mcp only from sources you trust.
Requirements: install codebase-memory-mcp
Install codebase-memory-mcp first. These are the upstream recommended install paths.
macOS / Linux
curl -fsSL https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.sh | bash
With the optional graph visualization UI:
curl -fsSL https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.sh | bash -s -- --ui
Windows PowerShell
# 1. Download the installer
Invoke-WebRequest -Uri https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.ps1 -OutFile install.ps1
# 2. Optional but recommended: inspect the script
notepad install.ps1
# 3. Run it
.\install.ps1
Useful installer options from upstream:
--ui— install the graph visualization variant.--skip-config— install the binary only, without configuring other agents.--dir=<path>— install to a custom location.
Arch Linux AUR
yay -S codebase-memory-mcp-bin
or:
paru -S codebase-memory-mcp-bin
Manual release archive
Download the archive for your platform from the latest codebase-memory-mcp release:
codebase-memory-mcp-<platform>-<arch>.tar.gzfor macOS/Linux.codebase-memory-mcp-windows-amd64.zipfor Windows.codebase-memory-mcp-ui-...variants include the graph visualization UI.
Then extract and run the included installer:
tar xzf codebase-memory-mcp-*.tar.gz
./install.sh
Windows PowerShell:
Expand-Archive codebase-memory-mcp-windows-amd64.zip -DestinationPath .
.\install.ps1
If the binary is not on PATH, set:
export PI_CBM_BIN="$HOME/.local/bin/codebase-memory-mcp"
Supported versions
This extension requires codebase-memory-mcp >= 0.12 and targets the 0.12.x CLI contract (>=0.12.0 <0.13.0). Captured/tested versions are 0.12.1 (target) and 0.9.0 (old-shape baseline); 0.10.x and 0.11.x were not tested, and the version gate rejects them conservatively. The 0.9.0 fixtures confirm the older shapes differ (search_graph object arrays instead of cols/rows groups, JSON-only list_projects), which this client does not parse; a version with those shapes cannot return useful results.
When a Pi session starts, the extension probes the binary. An unsupported version is shown to you once as an error notification telling you to upgrade, and every graph tool fails with the same message instead of silently returning empty results:
codebase-memory-mcp 0.10.0 is unsupported; pi-cbm requires 0.12.x (>=0.12.0 <0.13.0).
Upgrade codebase-memory-mcp, or reinstall an earlier pi-cbm release (<= 1.2.1) to keep using it.
A newer untested major/minor, or a version string that cannot be read, continues with a one-time warning notification instead of failing. Set PI_CBM_SKIP_VERSION_CHECK=1 to skip the probe (useful for packaged/vendored binaries and for tests).
CLI output is normalized before it reaches the tools, so the 0.12 table shapes (cols/rows, groups with qn_prefix, {cols,rows} label tables, absolute file paths, tree-text list_projects) are converted to the object arrays and project resolution behavior the rest of the extension expects.
Install
pi install npm:pi-cbm
Or test for one run:
pi -e npm:pi-cbm
Tools
Registers:
get_graph_schemaget_architecturesearch_graphresolve_symbolread_symbolread_symbolssearch_codeget_code_snippetget_code_snippetssearch_and_read_symbolstrace_pathquery_graphdetect_changes
Most tools accept optional project. When omitted, the extension infers it from indexed project roots matching Pi's current working directory. Agents should omit project for cwd/current-project work and provide it only when intentionally querying an external indexed project. A project value must be an indexed project name or a path: absolute, or explicitly relative to the current working directory (., .., or containing a /). A bare word such as other-repo is always treated as a project name, never as a directory under the cwd. An unknown value fails with the indexed project list instead of falling back to a guessed name. If the project list itself cannot be read, an explicit name is passed to codebase-memory-mcp unchanged, so its own "project not found" answer still applies.
Matching uses the longest indexed root that contains the working directory, so a git worktree or nested checkout that is not indexed itself resolves to the containing repo's graph. Index the worktree separately to query its own graph. When two indexed projects share one root (the default name plus a custom name), path and cwd resolution picks the default derived name; pass the custom name explicitly to query that one.
Settings
pi-cbm reads these environment variables. Blank counts as unset, and an invalid number falls back to the default.
| Variable | Default | Effect |
|---|---|---|
PI_CBM_BIN |
codebase-memory-mcp on PATH, then ~/.local/bin/codebase-memory-mcp |
Path to the codebase-memory-mcp binary. |
PI_CBM_CACHE_DIR |
CBM_CACHE_DIR, else ~/.cache/codebase-memory-mcp |
Cache directory for cbm's databases and pi-cbm's leases, queue and index records. Forwarded to the CLI as CBM_CACHE_DIR. |
PI_CBM_MAX_CONCURRENT_INDEXES |
1 |
Machine-wide maximum of simultaneous repository indexers. Raise it only when all Pi sessions share the same cache directory and the machine can support the extra load. |
PI_CBM_AUTO_REFRESH_INTERVAL_MS |
60000 |
How often the background refresh checks the session repo. A check that finds no changes runs no index, but each session still pays for it every tick: a git rev-parse, a git ls-files with a stat of each listed file, one list_projects call per 50 indexed projects, and an index_status call when the graph was not taken by pi-cbm. Each cbm call is a process of about a second. |
PI_CBM_FRESH_INDEX_TIMEOUT_MS |
30000 |
How long detect_changes waits for a re-index (lease wait plus the index) before answering from the existing graph. The re-index keeps running in the background. |
PI_CBM_SKIP_VERSION_CHECK |
unset | 1 skips the --version probe. |
CBM_CACHE_DIR is codebase-memory-mcp's own variable, not a pi-cbm alias. pi-cbm follows it when PI_CBM_CACHE_DIR is unset, so its coordination state stays next to the databases the binary writes.
Breaking changes
The CBM_* aliases for pi-cbm's own settings, and the old binary variables, are no longer read. Rename them:
| Removed | Use instead |
|---|---|
CODEBASE_MEMORY_MCP_BIN, CBM_BIN |
PI_CBM_BIN |
CBM_MAX_CONCURRENT_INDEXES |
PI_CBM_MAX_CONCURRENT_INDEXES |
CBM_AUTO_REFRESH_INTERVAL_MS |
PI_CBM_AUTO_REFRESH_INTERVAL_MS |
CBM_FRESH_INDEX_TIMEOUT_MS |
PI_CBM_FRESH_INDEX_TIMEOUT_MS |
CBM_SKIP_VERSION_CHECK |
PI_CBM_SKIP_VERSION_CHECK |
CBM_CACHE_DIR keeps working (see above). When a removed name is set and its replacement is not, the first session start shows a warning naming the replacement; the old value is ignored.
Index freshness
codebase-memory-mcp CLI indexes are not watched, and a full re-index costs the same as the first one (seconds for a small repo, minutes for a large one). pi-cbm therefore re-indexes only when the repo changed since the graph was taken, and it uses one check for both the background refresh and detect_changes.
- When the graph was taken. Each successful pi-cbm index writes a record (project, root, start and finish time) under
<cache dir>/pi-cbm/index-records/, shared by every Pi session using that cache dir. The reference is the index's start time, so an edit made while it ran still counts as a change. When another client (the cbm MCP server, the CLI by hand) indexed the project later, cbm'sindex_status.indexed_atis used instead. With neither, the graph counts as stale. - Changed since then?
git ls-files --cached --others --exclude-standardlists the tracked and untracked, non-ignored files. The global excludes file (core.excludesFile) is left out of that listing, because cbm indexes the files only it hides. The repo has changed when any of them, or any of their parent directories, has an mtime at or after the reference minus 1 s (indexed_athas second precision). A deleted file shows up through its directory's mtime. Gitignored files do not count. A root git cannot list (no git, or not a repository) always counts as changed, so non-git roots are re-indexed on every refresh as before. - Background refresh. On session start and on every
PI_CBM_AUTO_REFRESH_INTERVAL_MStick, an unchanged repo is skipped and the status line showscbm <project> · up to date. A changed repo is indexed through the usual lease and queue. This is not a TTL: the graph is exactly as fresh as with an index on every tick, but an idle repo no longer costs a full index per session per minute. detect_changes. An unchanged project is answered right away. A changed one is re-indexed first, by project name, so a custom-named project sharing a root is the one refreshed. If another session, or this session's background refresh, holds the repo's lease,detect_changeswaits for that index and checks again instead of indexing a second time. Concurrent calls in one session share one re-index; a call whose edits came after that re-index started gets another one. The result carries anindex_freshnessline:fresh: no changes since the graph was taken N s agofresh: re-indexed, graph taken N s agostale: re-index running since <time>; changes after <time> may be missingwhenPI_CBM_FRESH_INDEX_TIMEOUT_MSran out (re-index queued since <time>while it still waits for the lease). The index finishes in the background under its lease and the next call sees it. Cancelling the tool call likewise stops only the wait.stale: index refresh failed: <reason>; ...when the re-index failed; the answer comes from the existing graph.
Known gaps:
- An edit that keeps a file's old mtime (
touch -d,cp -p) and changes inside a nested repository or submodule are not seen as changes. - When another client indexed last, its
indexed_atis when that index finished, so edits made while it ran are missed until the next change. This also applies once after upgrading pi-cbm, to the last index the older version ran. - Deleting the only untracked file in a directory while keeping the empty directory is not seen: git does not list the empty directory, and its parent's mtime does not change. The same holds for a staged deletion (
git add -A) that leaves an empty directory;git rmremoves the directory and is seen.
Commands
/cbm
Open the pi-cbm settings menu:
/cbm menu— show the interactive settings menu./cbm status— show auto-index settings./cbm enable-non-git— auto-index safe non-git working directories./cbm disable-non-git— only auto-index git repositories.
Non-git auto-indexing is disabled by default. Enable it explicitly when working in a non-git project. The unsafe-path guard is always enabled: filesystem roots, home directories, system directories, and common macOS/Linux builtin directories are skipped with a status message explaining why.
Notes:
- Use
search_graphfirst for symbol/workflow/route/class/function discovery and “where is X implemented?” questions. Use a small limit for targeted lookup. - Use
search_and_read_symbolswhen you need to both discover implementation locations and inspect source for the top matches. Prefer it oversearch_graphfollowed by many individual snippet reads. Keepread_limitsmall, usually 3–8. - Use
resolve_symbolwhen you know a symbol name but need the exactqualified_nameor need to disambiguate candidates. - Use
read_symbolwhen you know a symbol name plus enough disambiguators, such asfile_path,parent_class,label,route_path, orroute_method, and want source only if the match is unambiguous. - Use
read_symbolswhen you know multiple concrete symbol names and need their source in one call. Each item fails closed on ambiguity likeread_symbol; retry only ambiguous items with stronger disambiguators. read_symbolfails closed on ambiguity; if it returns candidates, retry with more disambiguators or useget_code_snippetwith an exactqualified_name.read_symbolsupportsneighbors: "callers" | "callees" | "both"plusneighbor_limitfor direct, compact, source-free surrounding call context. Usetrace_pathfor multi-hop workflow or impact tracing.- Use
get_code_snippetwhen you already have an exactqualified_name; preferread_symbolwhen you have a concrete symbol name plus disambiguators but not the exactqualified_name. - Use
get_code_snippetswhen you already have multiple exactqualified_namevalues from search, trace, or query results. Prefer it over repeatedget_code_snippetcalls. - If the query is a symbol name, prefer
resolve_symbol/read_symbol; if it is an exact non-symbol string or you need all textual occurrences, usesearch_code. - Use
search_codefor exact literal text/regex searches such as env vars, config keys, route strings, error messages, constants, template text, comments, and docstrings. - Use
trace_pathafter identifying an anchor symbol when you need callers, callees, workflow, dependency, data-flow, or blast-radius context. Keep depth shallow by default. - Use
get_code_snippetonly aftersearch_graph/search_codeidentifies the exact symbol. Keep snippet retrieval targeted instead of bulk-reading many symbols. - Use
get_architecturefor broad orientation in unfamiliar repos, not targeted implementation lookup. Requested aspects may be absent if the index has no data for them. - Use
get_graph_schemabefore non-trivialquery_graphqueries, and keepquery_graphreturned columns narrow. - Use
detect_changesfor diff review or blast-radius analysis, not ordinary code lookup. - Read obvious README/package/deployment/config manifest paths directly instead of forcing graph tools into file-inspection work.
trace_pathauto-resolves short function/method names when there is a single unambiguous match; otherwise it returns candidatequalified_names. It also supports explicit plugin-sideexclude_pathsfilters.- Exploration tools such as
search_graph,get_code_snippet,trace_path,get_architecture,search_code, anddetect_changesdefault to compact, location-first output. Less-useful upstream graph metadata such as fingerprints, token fields, and raw metrics is hidden unlessinclude_metadata: trueis set. - Batch/source tools such as
get_code_snippets,read_symbols, andsearch_and_read_symbolsuse the same compact metadata defaults: they preserve essential identity such asfile_path,start_line,end_line,qualified_name, signatures, and route fields while stripping less-useful raw graph metadata unlessinclude_metadata: trueis set. - Compact output hides analysis metadata, not edit-critical location identity. Symbol-like outputs preserve
file_path,start_line, andend_linewhen available, and the plugin enriches missing locations for resolver, trace, and architecture outputs where possible. - Code/source-heavy tools support
full_outputandmax_symbol_lines. By default, normal-sized symbols are returned in full and only oversized function/method/class-sized blocks are compacted. search_codedefaults to compact output with small context to avoid flooding the agent context, and oversized per-symbol contexts are compacted unlessfull_output=trueormax_symbol_linesis increased. If a result is compacted/truncated, agents should retry the same codebase-memory tool with a highermax_symbol_linesorfull_output=truebefore falling back to file reads/grep.query_graphnormalizes common numeric metric columns in the returned rows for easier agent consumption, while still relying on upstream for query execution/order.
Typical workflow
Ask Pi:
Give me the architecture overview.
The extension indexes and periodically refreshes the current repo in the background, so the agent should usually go straight to get_architecture, search_graph, get_code_snippet, trace_path, search_code, or query_graph for structural code exploration. Administrative index operations remain available through the codebase-memory-mcp CLI when needed.
Development
npm install
npm run typecheck
npm test
Tests read recorded CLI output from test/fixtures/ instead of running a real binary; the freshness tests drive test/fixtures/fake-cbm.mjs, a stand-in CLI, against real git repos in temp dirs. To refresh the fixtures after a codebase-memory-mcp release, follow test/fixtures/README.md: scripts/capture-fixtures.sh <binary> <version> indexes a neutral copy of src/ in a temp directory and records each case's stdout plus a .meta.json (invocation, args, exit code, stderr). Adding a new version directory means updating the fixture-driven expectations in the matching test/*.test.ts files.