Agents that use `git worktree add` to run parallel branches end up with one
indexed project per worktree. Each is a near-duplicate of the main checkout,
so the cache fills with redundant graphs and project pickers get noisy.
Add an opt-in `ignore_worktrees` config key. When enabled, a linked worktree
is left alone:
- auto-index on connect skips it (logged as autoindex.skip)
- the daemon's background auto-index skips it
- explicit index_repository refuses with an actionable message naming both
ways forward (index_worktree=true, or turn the key off)
- the hook-augment "not indexed" guidance stops telling the agent to run
index_repository in a directory where it would only be refused
Detection is git plumbing, no subprocess: <path>/.git must be a regular file
holding a "gitdir:" pointer AND that gitdir must contain a `commondir` file.
The commondir check is what separates a linked worktree from a submodule,
whose .git is also a gitlink file but whose gitdir has no commondir. The main
checkout of a repo that has worktrees is never affected.
Defaults to false, so behaviour is unchanged unless the key is set.
Signed-off-by: Nohj <vitalnohj@gmail.com>
13 KiB
Configuration Reference
This page documents the configuration files that codebase-memory-mcp reads or writes today.
At a Glance
| Purpose | Path | Format | Notes |
|---|---|---|---|
| Global custom extension mapping | $XDG_CONFIG_HOME/codebase-memory-mcp/config.json |
JSON | Falls back to ~/.config/codebase-memory-mcp/config.json when XDG_CONFIG_HOME is unset. |
| Per-project custom extension mapping | {repo_root}/.codebase-memory.json |
JSON | Overrides conflicting global extra_extensions entries. |
| CLI-managed runtime settings | ${CBM_CACHE_DIR:-~/.cache/codebase-memory-mcp}/_config.db |
SQLite | Written by codebase-memory-mcp config set/reset. |
| UI settings | ${CBM_CACHE_DIR:-~/.cache/codebase-memory-mcp}/config.json |
JSON | Stores ui_enabled and ui_port. |
| Daemon operation log | ${CBM_CACHE_DIR:-~/.cache/codebase-memory-mcp}/logs/cbm-daemon.log |
Structured log | Durable daemon lifecycle, watcher/indexing, UI, resource, and error events. |
| Admission conflict log | ${CBM_CACHE_DIR:-~/.cache/codebase-memory-mcp}/logs/daemon-conflicts.ndjson |
NDJSON | Exact-build, ABI, and canonical-cache conflicts. |
| Activation log | ${CBM_CACHE_DIR:-~/.cache/codebase-memory-mcp}/logs/activation-events.ndjson |
NDJSON | Install/update/uninstall activation progress and outcomes. |
CBM resolves CBM_CACHE_DIR to a canonical per-account path before using any of these locations. The log directory and files are private to the account.
1. Custom File Extension Mapping
Two optional JSON files let you map additional file extensions to built-in languages.
Global config
Default path:
$XDG_CONFIG_HOME/codebase-memory-mcp/config.json
Fallback when XDG_CONFIG_HOME is unset:
~/.config/codebase-memory-mcp/config.json
Per-project config
Place this file in the repository root:
.codebase-memory.json
Format
{
"extra_extensions": {
".blade.php": "php",
".mjs": "javascript",
".twig": "html"
}
}
Notes:
- Extension keys must include the leading dot.
- Language names are case-insensitive.
- Unknown language names are skipped.
- Missing files are ignored.
- If the same extension appears in both files, the per-project file wins.
2. CLI-Managed Runtime Settings
The config subcommand stores runtime settings in a small SQLite database:
${CBM_CACHE_DIR:-~/.cache/codebase-memory-mcp}/_config.db
Inspect or change values with the CLI:
codebase-memory-mcp config list
codebase-memory-mcp config get auto_index
codebase-memory-mcp config set auto_index true
codebase-memory-mcp config set auto_index_limit 50000
codebase-memory-mcp config set watcher_enabled false
codebase-memory-mcp config reset auto_index
Current keys:
| Key | Default | Meaning |
|---|---|---|
auto_index |
false |
Automatically index new projects when an MCP session starts. |
auto_index_limit |
50000 |
Maximum file count allowed for automatic indexing of a new project. |
ignore_worktrees |
false |
Skip linked git worktrees (git worktree add) when indexing automatically. |
auto_watch |
true |
Register the session's project with the background git watcher on connect. Set false to keep a session from registering its project (the watcher still runs for other projects). |
watcher_enabled |
true |
Master switch for the background watcher subsystem. Set false to stop the watcher from starting at all — no poll thread and no project registration. Reindex manually with index_repository when disabled. |
index_max_files |
off |
Optional maximum number of accepted source files in one discovery run. |
index_max_source_mb |
off |
Optional maximum accepted source size in MiB in one discovery run. |
watcher_enabledvsauto_watch.watcher_enabledcontrols whether the watcher subsystem starts at all (the background poll thread).auto_watchis narrower: it only controls whether a connecting session registers its own project with an already-running watcher. Whenwatcher_enabled=false,auto_watchhas no effect — there is no watcher to register with.They also differ in when they are read, which matters because the watcher lives in the background daemon, not in your MCP client:
auto_watchis consulted each time a session would register its project, so a change applies to sessions that connect afterwards.watcher_enabledis read once, when the daemon starts, because it decides whether the watcher is built at all. The daemon is long-lived and outlives individual MCP sessions, so reconnecting your client is not enough — retire the daemon so the next one picks the new value up:codebase-memory-mcp config set watcher_enabled false codebase-memory-mcp daemon stop # next session starts a daemon without the watcher codebase-memory-mcp daemon status # confirmDisabling the watcher does not disable anything else: the daemon still starts,
auto_indexstill runs, andindex_repositorystays available for manual reindexing.
The two index_max_* settings are independent and disabled by default. They
apply to explicit indexing, automatic indexing, and watcher re-indexing, but not
to cross-repo-intelligence, which does not scan repository source files.
Equality is allowed; exceeding either setting fails the complete index request
and preserves any previously serving database. See
Index resource limits for counting, validation, and
error-response details.
ignore_worktrees
Every indexed project is registered under its own absolute root path, so each
linked worktree becomes a separate permanent index. On machines that create many
short-lived worktrees, the automatic paths (auto_index, and the session hook's
"index this project first" guidance) turn every throwaway checkout into another
stored index of what is largely the same repository.
Enable the key to keep those checkouts out of the index:
codebase-memory-mcp config set ignore_worktrees true
With it enabled:
- automatic indexing skips a session whose root is a linked worktree;
- the
hook-augmentcontext says the worktree is unindexed on purpose instead of telling the agent to runindex_repository; - an explicit
index_repositorycall on a linked worktree is refused, and names both ways forward — passindex_worktree=truefor that one call, or turn the key back off.
The main checkout of the same repository is unaffected, as are ordinary clones
and submodules. Detection is git plumbing only: a linked worktree's .git is a
file pointing at a gitdir that contains a commondir entry.
The default is false, so indexing behavior is unchanged unless you opt in.
3. UI Settings
The optional built-in graph UI stores its settings in:
${CBM_CACHE_DIR:-~/.cache/codebase-memory-mcp}/config.json
Current format:
{
"ui_enabled": false,
"ui_port": 9749
}
Notes:
- If a UI-enabled binary finds its verified external asset pack and no UI config file exists yet, the UI auto-enables on first run. Missing or invalid assets leave the MCP/daemon service available and keep the UI disabled.
CBM_CACHE_DIRchanges both the UI config location and the runtime settings database location.- CBM resolves
CBM_CACHE_DIRto one canonical per-account cache root. A process configured with a different root fails while any CBM session or command is active; close them before switching roots.
4. Environment Variables
These environment variables affect runtime behavior:
| Variable | Default | Description |
|---|---|---|
CBM_ALLOWED_ROOT |
(unset) | Confine index_repository to paths within this directory. When set, a repo_path that resolves (after symlink / .. resolution) outside this root is refused, and the same check now applies to the graph UI's POST /api/index route rather than only to the MCP tool. Unset imposes no containment restriction — but see the always-on limits below, which apply whether or not this is set. Useful when the server may be driven by an untrusted caller, e.g. agentic or multi-tenant deployments. |
CBM_CACHE_DIR |
~/.cache/codebase-memory-mcp |
Override the cache directory used for indexes, _config.db, and UI config.json. |
CBM_DIAGNOSTICS |
false |
Enable periodic snapshot.json and retained trajectory.ndjson below a fresh owner-private directory in the system temp directory. The daemon records the randomized paths in the diagnostics.start discovery record (a single JSON line) in ${CBM_CACHE_DIR}/logs/cbm-daemon.log; that one record is emitted even when CBM_LOG_LEVEL suppresses ordinary logging, so the paths always remain discoverable. |
CBM_DOWNLOAD_URL |
GitHub releases | Override the update download URL. |
CBM_LOG_LEVEL |
role-aware | Set the log level to debug, info, warn, error, or none (or 0-4). Thin MCP/CLI/hook frontends default to warn; the detached daemon and supervised index workers default to info. Physical workers retain INFO liveness records because their private logs drive the supervisor's no-progress timeout. Frontend messages use that session's stderr; detached daemon events use ${CBM_CACHE_DIR}/logs/cbm-daemon.log. |
CBM_RUNTIME_DIR |
%LOCALAPPDATA% (Windows), /private/tmp (macOS), /tmp (other) |
Parent directory for the daemon/CLI rendezvous directory, which CBM creates inside it as cbm-daemon-<uid> (cbm-daemon-<key> on Windows). Set it when the default ancestry cannot pass the private-directory check — see below. CBM_CACHE_DIR does not move the rendezvous. |
CBM_WORKERS |
auto-detected | Override the indexing worker count. |
Relocating the daemon rendezvous directory
Before it is used, the rendezvous directory and every ancestor of it are checked:
each ancestor must be owned by you or by root, must not be world-writable (unless
it is the standard root-owned sticky directory such as /tmp), and must carry no
allow-ACL — on Windows, no ACE granting mutation rights to another identity. The
rendezvous directory itself is then forced to owner-only (0700, no extended ACL
/ an owner-only DACL).
That ancestry is not always acceptable in the default location. A Windows profile
that has acquired a capability-SID ACE with WRITE_DAC / WRITE_OWNER / DELETE
on %LOCALAPPDATA% — something an installed packaged app can add — fails the walk,
and so can an unusual /tmp or home directory on POSIX. When that happens every
command fails, config list included, so the settings surface cannot be reached
either:
codebase-memory-mcp: secure daemon endpoint could not be created
CBM_RUNTIME_DIR points the rendezvous at an ancestry you choose:
export CBM_RUNTIME_DIR="$HOME/cbm-runtime" # any directory you own
$env:CBM_RUNTIME_DIR = "D:\cbm-runtime"
The check is not relaxed for the directory you name: it goes through exactly the same validation as the default, and a value that fails it is refused rather than silently ignored. Because the rendezvous is how sessions find each other, every process that should share one daemon must see the same value — set it in the environment of your MCP client and your shell alike, or a CLI invocation without it will coordinate through the default location instead.
Environment used by daemon-owned components—such as diagnostics, daemon logging, and process-wide indexing resource limits—is captured from the first daemon-backed session that starts the daemon. Later sessions join the existing process and cannot replace those values. To change them, close every daemon-backed session, update the relevant agent configurations consistently, and restart a session. CBM_ALLOWED_ROOT remains session-specific, a conflicting CBM_CACHE_DIR is rejected, and one-shot CLI commands use their own current environment without starting the daemon.
Roots that are always refused
Independently of CBM_ALLOWED_ROOT, some directories are refused as an indexing
root because they are too broad or too sensitive to index as a unit:
- a filesystem root, a Windows drive root, or a UNC share root;
- a top-level system tree —
/etc,/var,/usr,/home,/Users, and on WindowsC:\Windows,C:\Users,C:\ProgramData,C:\Program Files; - your home directory itself (directories below it are fine);
- a credential directory at any depth —
.ssh,.aws,.gnupg,.kube,.docker,.netrc,.git-credentials,.password-store, macOSKeychains.
Two limits are worth stating plainly. This constrains scope, not sensitivity: inside a root that is allowed, every file the process can read may be indexed and later returned. And the credential list is a denylist, so it raises the cost of a mistake rather than closing the class — a directory it does not name is permitted.
5. Agent and Editor Integration Files
The install command can also write MCP entries and instruction blocks into agent/editor config files such as Claude Code, Codex, Gemini, VS Code, Cursor, Zed, and others.
Those target paths vary by tool and platform, so the easiest way to inspect the exact files for your machine is:
codebase-memory-mcp install --dry-run
That prints the specific config files the installer would modify without writing anything.