codebase-memory-mcp (CMM) is the core. This repo is the hook-based enforcement and tracking layer that makes Claude Code actually use CMM's persistent code knowledge graph instead of re-reading files — saving ~99% of tokens on code exploration. Two add-ons are optional and auto-detected at install time; each layers on top only when present, and CMM works fully without either:
- codebase-memory-mcp (by DeusData) — core, always installed. Persistent code knowledge graph across 158 languages with cross-repo intelligence and gRPC/GraphQL/tRPC service detection; replaces file-reading with precise graph queries, saving ~99% of tokens on code exploration.
- Context Mode MCP (optional, auto-detected) — execution sandboxing + SQLite session persistence; routes tool outputs through isolated subprocesses to keep large outputs out of the context window (~98% context reduction). Registered automatically when detected; pass
--skip-context-modeto opt out. Its hooks no-op gracefully when it is absent. - VBW (Vibe Better with Claude Code) (optional, auto-detected) — a structured planning/agent workflow. When a VBW plugin tree is resolvable, setup generates CMM-aware agent overrides; without VBW the bundled agent delta files stay inert and CMM runs on its own.
CMM alone eliminates the biggest token sink in long Claude Code sessions — redundant file reads. Context Mode adds a second layer for bloated tool output; VBW adds structured planning. Neither add-on is required.
Credit where it's due: The hook-based enforcement approach and repository structure are adapted from jmunch-claude-code-setup by Shachar Bard. This repo does not contain the MCP servers — it provides the enforcement and tracking layer that makes Claude actually use them. All the clever indexing, knowledge graph construction, and execution sandboxing is the MCP authors' work.
Indexes your codebase into a persistent knowledge graph so Claude fetches precise structural results — functions, call chains, architecture overviews — instead of reading entire files. Supports 158 languages (vendored tree-sitter grammars), Cypher-like queries, dead code detection, cross-service HTTP/gRPC/GraphQL/tRPC linking, channel detection (EMITS/LISTENS_ON) across 8 languages, infrastructure-as-code indexing (Dockerfile, Kubernetes), cross-repo CROSS_* edges, Hybrid LSP type resolution (Python, TS/JS/JSX/TSX, PHP, C#, Go, C/C++, Java, Kotlin, Rust, Perl), and git diff impact analysis. A single graph query returns what would take dozens of Grep/Read calls.
Runs commands and processes files in isolated sandboxes so only relevant output enters the conversation. Also persists all tool calls (file edits, git ops, errors) to a local SQLite database indexed with FTS5 full-text search — enabling session resume after context compaction without re-reading history.
Real-world compression examples: Playwright snapshots 56 KB → 299 bytes; GitHub issues (batch of 20) 59 KB → 1.1 KB; access logs 45 KB → 155 bytes.
CMM and Context Mode are complementary, not competing:
| Layer | Tool | When to use |
|---|---|---|
| Code exploration | CMM (search_graph, get_code_snippet, trace_path) |
Finding functions, call chains, architecture — always |
| Command execution | Context Mode (ctx_execute) |
Any Bash command producing large output (logs, tests, API responses) |
| Web content | Context Mode (ctx_fetch_and_index + ctx_search) |
URLs referenced more than once in a session |
| Indexed doc search | Context Mode (ctx_search) |
Querying content previously indexed by Context Mode |
| File search (non-indexed) | Native Grep/Glob | Source code, config, unindexed content |
Ordering enforced by hooks: CMM gate fires first (ensures index is ready), then Context Mode gate (routes execution to sandboxes). CMM indexes the codebase; Context Mode sandboxes what happens next.
| Layer | What | Effect |
|---|---|---|
| CLAUDE.md rules | Instructions | Tells Claude when to use CMM and ctx_* tools |
| Session gate (CMM) | Blocking (PreToolUse) | Blocks ALL tools until CMM index is refreshed at session start |
| Session gate (Context Mode) | Blocking (PreToolUse) | Gates tool calls until Context Mode is initialized (if installed) |
| Agent spawn gate | Blocking (PreToolUse) | Blocks Agent spawns whose prompt lacks MCP instructions — Workflow agent() spawns bypass it; per-project exempt list in .claude/cmm-agent-passthrough.txt (see Subagent Instructions Template) |
| PreToolUse nudge | Non-blocking | Reminds Claude when it tries Read on indexed code files |
| PostToolUse logger | Passive | Logs tool calls to SQLite for session resume (if Context Mode installed) |
| PostToolUse tracker | Passive | Tracks CMM call counts per tool |
| PreCompact snapshot | Passive | Captures session state before context compression (if Context Mode installed) |
# 1. Clone this repo
git clone https://github.com/halindrome/cmm-claude-code-setup
cd cmm-claude-code-setup
# 2. Install CMM binary (macOS/Linux)
curl -fsSL https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/scripts/setup.sh | bash
# Or download from: https://github.com/DeusData/codebase-memory-mcp/releases/latest
# Or via npm: npm install -g codebase-memory-mcp
# Or via pip: pip install codebase-memory-mcp
# Or via Homebrew: brew install codebase-memory-mcp
# 3. Run the setup script from your target project directory
cd /path/to/your-project
bash /path/to/cmm-claude-code-setup/setup.sh --allSetup handles the rest automatically: it installs global hooks and rules (to $CLAUDE_CONFIG_DIR/ or ~/.claude/), project hooks and rules (to .claude/), detects whether CMM is registered with Claude Code and creates .mcp.json if needed, writes the CMM (+ Context Mode) tool allowlist to settings.json, and optionally sets up Context Mode — all interactively with prompts at each step.
Tool allowlist (and where it lives):
The allowlist pre-approves the MCP tool calls so Claude Code doesn't prompt on each use (important for the hooks and subagents that auto-call CMM). It is not required for the tools to function — without it they still work, just with a permission prompt.
- Policy — "complete minus destructive": every CMM + Context Mode tool is pre-approved except the irreversible/system-mutating ones, which must always prompt: CMM
delete_project, Context Modectx_purgeandctx_upgrade. That's 13 CMM tools and 9 Context Mode tools (written in both the plugin and legacy registration forms).--skip-context-modeomits the Context Mode entries. - Scope: Claude Code unions
permissions.allowacross scopes, so--globalwrites the allowlist once to the globalsettings.jsonand every project inherits it — you never need to re-allowlist per project.--projectwrites to.claude/settings.json, and is skipped automatically when the global allowlist already covers every tool (no duplication). Detection is likewise merged (project + global), so a global allowlist suppresses the per-project "not allowlisted" warning.
Core vs. optional at install time:
- CMM (core) — hooks, rules, statusline, and the tool allowlist are always installed. This is the enforcement layer's reason for being.
- Context Mode (optional, auto-detected) — registered automatically when detected via
detect_context_mode(); pass--skip-context-modeto opt out. Its hooks are installed unconditionally and no-op gracefully when Context Mode is absent, so you can enable it later without re-running setup. - VBW (optional, auto-detected) — setup resolves an active VBW plugin tree (
hooks/lib/vbw-source.sh) and generates CMM-aware agent overrides only when one is found. The bundledagents/vbw-*.mddelta files are installed either way but stay inert without VBW; the SessionStart hook self-heals and generates the overrides automatically if VBW is added later.
Non-VBW setup state (Context Mode migration sentinels, optional CMM config) lives under .claude/.cmm-setup/, so a CMM-only project needs no .vbw-planning/ directory (legacy .vbw-planning/ copies are still read for back-compat).
# setup.sh options
bash setup.sh --help
--project Install project hooks, rules, and settings into current directory
--global Install global hooks and rules into ~/.claude/
--all Install both
--force Overwrite existing files
--dry-run Preview changes without writing anything
--skip-mcp-check Skip MCP availability prompts (for CI/automation)
--force-local-cmm Register CMM in project .mcp.json even if globally installed--project is global-scope-aware: if codebase-memory-mcp is already registered in
${CLAUDE_CONFIG_DIR:-~/.config/claude-code}/settings.json, the project .mcp.json
entry is skipped to avoid redundancy. Use --force-local-cmm for an explicit
per-project pin (e.g., version isolation or CI environment).
See docs/setup-guide.md for the full step-by-step walkthrough.
CMM (upstream v0.6.1+) supports a team-sharing bootstrap artifact at .codebase-memory/graph.db.zst. When this file is present in a repo, CMM's index_repository auto-imports it as a starting point instead of indexing from scratch — so teammates who clone the repo can hydrate a fresh local graph from the snapshot in seconds rather than waiting through a full first-time index. The artifact is produced and consumed by CMM itself; this project does not generate or manage it. See the CMM upstream docs for snapshot creation, retention, and CI publishing patterns.
CBM_SQLITE_MMAP_SIZE— overrides the SQLite mmap size used by CMM; useful for very large repos. See CMM upstream docs for default and recommended values.
hooks/
global/ # Install to ~/.claude/hooks/ (all projects)
cmm-nudge.sh # PreToolUse:Read — reminds Claude to use CMM on code files
reindex-after-edit.sh # PostToolUse:Write|Edit — prompts re-index after edits
project/ # Install to .claude/hooks/ (per project)
cmm-session-start.sh # SessionStart — injects index refresh prompt (agent-aware)
cmm-session-gate.sh # PreToolUse:* — blocks all tools until CMM index ready
cmm-sentinel-writer.sh # PostToolUse — marks index as refreshed
reindex-after-commit.sh # PostToolUse:Bash — marks sentinel stale after git commit; calls touch_project to nudge watcher (5–60s reindex)
agent-cmm-gate.sh # PreToolUse:Agent — blocks agents without MCP instructions
track-cmm-calls.sh # PostToolUse — tracks call counts per CMM tool
context-mode-sentinel-writer.sh # PostToolUse:mcp__context-mode__ctx_* — writes sentinel so session-gate unblocks
# context-mode upstream hooks (PostToolUse capture, PreToolUse cache-redirect,
# PreCompact snapshot, SessionStart inject, UserPromptSubmit intent) are
# registered directly in .claude/settings.json via the `context-mode hook
# claude-code <event>` CLI dispatcher — see "Upstream hook registration
# (phase 51+)" below.
rules/
cmm-rules.md # CMM tool guidance (installed globally and per-project)
ctx-rules.md # Context Mode tool guidance (ctx_search retrieval protocol)
project-settings-example.json # Example .claude/settings.json with all hooks registered
mcp-example.json # Example .mcp.json for project-scoped MCP registration
allowed-tools.txt # CMM + Context Mode tool allowlist for settings.local.json
benchmarks/
run.sh # Benchmark runner (baseline / cmm-cold / cmm-cache)
README.md # Benchmark documentation
docs/
setup-guide.md # Full step-by-step setup guide
Session starts
-> cmm-session-start.sh injects "run index NOW" prompt (or richer agent init if spawned agent)
-> cmm-session-gate.sh blocks ALL tools until CMM index done
-> Claude runs index_repository / index_status
-> cmm-sentinel-writer.sh marks session as ready
-> context-mode-session-gate.sh checks Context Mode sentinel (no-op if not installed)
-> All tools unblocked
Claude explores code
-> Tries Read on a code file
-> cmm-nudge.sh fires: use search_graph / get_code_snippet instead
-> Claude uses CMM graph tools
-> track-cmm-calls.sh logs the call
-> context-mode upstream PostToolUse hook captures the event into the session FTS5 index
Claude runs a command
-> With Context Mode: uses ctx_execute (output sandboxed, only relevant portion enters context)
-> Without Context Mode: uses Bash (full output enters context)
Claude spawns a subagent
-> agent-cmm-gate.sh checks prompt for CMM keywords (or ctx_* keywords if Context Mode in use)
-> Missing? BLOCKED with copy-paste instructions
-> Present? Allowed
Context window approaches limit
-> context-mode upstream PreCompact hook fires (if installed)
-> Snapshots last 20 events + git HEAD into SQLite
-> After compaction: Claude can query history via ctx_search
The track-cmm-calls.sh hook tracks how many times each CMM tool is called. Accumulates across sessions at ~/.cache/codebase-memory-mcp/_call-counts.json.
{
"total_calls": 87,
"by_tool": {
"mcp__codebase-memory-mcp__search_graph": 32,
"mcp__codebase-memory-mcp__get_code_snippet": 19,
"mcp__codebase-memory-mcp__trace_path": 14,
"mcp__codebase-memory-mcp__get_architecture": 8,
"mcp__codebase-memory-mcp__query_graph": 6,
"mcp__codebase-memory-mcp__index_repository": 4
}
}Display CMM call stats in your Claude Code statusline:
Automated install: Run
bash setup.sh --global(or--project) — setup now offers to install the statusline automatically. Use--skip-statuslineto bypass.
- Global install generates a standalone script showing CMM stats only.
- Project install generates a wrapper that runs your existing global statusline and appends CMM stats (e.g.,
my-branch +3 -1 | CMM:5 (sg:3 cs:1 tr:1)).
#!/bin/bash
COUNTS_FILE="$HOME/.cache/codebase-memory-mcp/_call-counts.json"
if [ -f "$COUNTS_FILE" ]; then
TOTAL=$(jq -r '.total_calls // 0' "$COUNTS_FILE")
SEARCH=$(jq -r '.by_tool["mcp__codebase-memory-mcp__search_graph"] // 0' "$COUNTS_FILE")
SNIPPET=$(jq -r '.by_tool["mcp__codebase-memory-mcp__get_code_snippet"] // 0' "$COUNTS_FILE")
TRACE=$(jq -r '.by_tool["mcp__codebase-memory-mcp__trace_path"] // 0' "$COUNTS_FILE")
echo "CMM:${TOTAL} (sg:${SEARCH} cs:${SNIPPET} tr:${TRACE})"
else
echo "CMM:0"
fiRegister in ~/.claude/settings.json:
{
"statusLine": {
"type": "command",
"command": "bash \"$HOME/.claude/hooks/statusline-cmm.sh\""
}
}When spawning subagents, include CMM/ctx instructions in the prompt to ensure they use CMM. The canonical, installable block lives in rules/cmm-agent-preamble.md (installed to .claude/rules/cmm-agent-preamble.md) — paste the region between its copy markers into every subagent prompt. Abbreviated:
**Code navigation (MANDATORY):** Use codebase-memory-mcp MCP tools for all code exploration.
- Use search_graph to find functions/classes by name pattern — NEVER grep through files to find definitions
- Use get_code_snippet to fetch specific function source code by qualified name
- Use trace_path to understand call chains and dependencies (downstream-consumer checks)
- Use get_architecture for codebase orientation (languages, packages, hotspots, routes)
- Full Read only when: file <50 lines, need imports/globals, or non-code files
**Large output (when Context Mode is available):** route large diffs / test runs / multi-file scans
through ctx_execute / ctx_batch_execute / ctx_search so findings — not raw bytes — enter context.
The two subagent execution models behave very differently — measured, not assumed. The agent-cmm-gate.sh hook (PreToolUse:Agent) blocks a main-thread or nested Agent spawn whose prompt lacks CMM/ctx keywords. But the spawn-gate is the author-facing lever; the behavioural enforcement is the inside-child hooks — and whether those fire depends on how the child was spawned:
- Agent-tool subagents (including a manager's nested lens grandchildren): project
PreToolUsehooks do fire on theirRead/Grep/Bash(verified to depth 2), socmm-nudge/grep-cmm-gate/ctx-execute-enforcerredirect them toward CMM/ctx even if their prompt never mentions CMM. Here the spawn-gate is mostly a proactive nudge, not the enforcement. - Workflow-spawned workers (
agent()/parallel()/pipeline()lenses): projectPreToolUsehooks do fire inside them as well (757 gate emissions measured over 120 days), but they bypass the spawn-gate — a Workflow spawn surfaces as aWorkflowcall, whichPreToolUse:Agentcannot match (163Workflowcalls, 0 gated). So the behavioural gates reach them; only the author-facing prompt check does not.
So: for a Workflow panel, bake the preamble into the agent() prompt (rules/cmm-agent-preamble.md) — nothing checks the prompt for you. For Agent-tool panels you can instead exempt purpose-built agent types from the spawn-gate via .claude/cmm-agent-passthrough.txt (one agent-type per line, # comments and shell globs allowed) — the inside-child hooks keep enforcing, so you drop only the prompt-nag. This is the tool-agnostic path: a skill lists its reviewer/manager types and never has to mention CMM.
Reaching an agent is not the same as changing it. Across 1,798 transcripts, 97.2% of subagent transcripts carried a hook emission — yet 52% of gated subagent transcripts making 5+ tool calls issued zero CMM calls, and only 13–25% of blocked code searches were followed by a CMM call. Blocked agents pivot to Read/Bash rather than to search_graph. Treat the hooks as a floor, and the prompt as the lever.
Context Mode MCP reduces context window usage by ~98% by routing tool outputs through sandboxes and persisting session state via SQLite. CMM works fully without it — Context Mode is an additive layer for long sessions where context bloat becomes a bottleneck.
All three Context Mode hooks are included in this repo and gracefully no-op when Context Mode is not installed — so you can install them unconditionally and enable Context Mode later.
Recommended — plugin form (upstream v1.0.122+). This enables upstream's slash commands (/context-mode:ctx-doctor, /ctx-upgrade, /ctx-purge, /ctx-insight), automatic hook routing, and the full 11-tool MCP surface. The plugin form exposes Context Mode's MCP tools under the mcp__plugin_context-mode_context-mode__* prefix; our hooks register parallel matchers for both this prefix and the legacy mcp__context-mode__* prefix, with the plugin form listed first.
# Inside a Claude Code session:
/plugin marketplace add mksglu/context-mode
/plugin install context-mode@context-mode
Then run setup.sh --project from a shell; it auto-detects the plugin install via ${CLAUDE_PLUGIN_ROOT} or ~/.claude/plugins/cache/<marketplace>/context-mode/.claude-plugin/plugin.json and writes the canonical upstream-1.0.122 matcher inventory into .claude/settings.json.
If setup.sh --project detects an MCP-server-only install (the legacy alternative below), it interactively prompts to migrate to the plugin form. Reply Y to migrate, n for one-time skip, or keep to suppress the prompt on future runs. Pass --no-migrate for non-interactive / CI use. The opt-out flag --skip-context-mode still works and writes no Context Mode entries to .claude/settings.json.
For installs pinned to a pre-1.0.122 upstream or workflows that cannot use /plugin, register Context Mode as a plain MCP server. This path does not enable the upstream slash commands (/context-mode:ctx-doctor, /ctx-upgrade, /ctx-purge, /ctx-insight); the 11 MCP tools work but you lose the slash-command surface and automatic hook routing.
# 1. Install Context Mode (pin @latest so `npx` re-resolves instead of reusing a stale global)
npm install -g context-mode@latest
# 2. Register with Claude Code — always pin `@latest` so npx fetches the newest
# version each launch rather than reusing whatever version is cached globally.
# Project-scoped (only activates in this project):
claude mcp add --scope project context-mode -- npx -y context-mode@latest
# Or globally (activates in all projects):
claude mcp add context-mode -- npx -y context-mode@latest
# 3. Hooks are already installed by setup.sh — no extra copy step needed
# If you installed manually, they're in hooks/project/context-mode-*.sh
# 4. The settings example already includes Context Mode hook entries
# IMPORTANT: cmm-session-gate must appear before context-mode-session-gate in PreToolUse
# See rules/project-settings-example.json
# 5. Context Mode rules are enforced by hooks — no manual CLAUDE.md edits neededBoth CMM and Context Mode can be activated for a single project only. The claude mcp add --scope project command (step 2 above) writes to .mcp.json in the project root. You can also edit .mcp.json directly:
{
"mcpServers": {
"codebase-memory-mcp": {
"command": "codebase-memory-mcp",
"args": [],
"type": "stdio"
},
"context-mode": {
"command": "npx",
"args": ["-y", "context-mode@latest"]
}
}
}The MCP executables live wherever they're installed globally — only the registration is project-scoped.
- Context Mode session gate — fires after CMM gate in PreToolUse; no-ops if not installed
- PostToolUse event logger to
.claude/context-mode.db— captures file edits, git ops, tool calls - PreCompact snapshot — records session state before context compression for later resume via
ctx_search - CLAUDE.md rules for
ctx_execute,ctx_search,ctx_fetch_and_index - Agent gate accepts
ctx_*keywords alongside CMM keywords
When setup.sh --project detects context-mode is installed (or installs it via .mcp.json), it also registers context-mode's five upstream hooks in .claude/settings.json so the MCP's core capture/redirect machinery fires automatically:
- PostToolUse — fires on
Bash,Read,Write,Edit,Glob,Grep,Skill,Agent,Task*,EnterPlanMode/ExitPlanMode,EnterWorktree, and the broadmcp__*prefix. Upstreamposttooluse.mjsdelegates toextractEvents()which persists semantic session events (file reads, prompts, rules, subagent completions, task updates, intents, decisions) into a SQLite FTS5 session DB. As of upstream v1.0.122 (PR #532, closes #529), rawmcp__*tool outputs (jira/grafana/sentry/halo responses) are also persisted via the wildcardmcp__PostToolUse matcher — resolving the gap previously tracked as mksglu/context-mode#329. Ongoing regression guard:tests/test-phase-57-mcp-capture.sh. - PreToolUse — cache-redirect for Bash, WebFetch, Read, Grep, Agent, and context-mode's own
ctx_execute*tools when the output of a prior equivalent call is already indexed in the session DB - PreCompact — writes a session snapshot before Claude Code compacts context
- SessionStart — injects prior-session snapshots
- UserPromptSubmit — intent processing for submitted prompts
External-data MCP capture (resolved upstream as of v1.0.122). External-data MCP tool outputs (
mcp__jira__*,mcp__grafana__*,mcp__sentry__*, etc.) are now persisted by upstream'sextractEventsafter PR #532 added a wildcardmcp__matcher toPOST_TOOL_USE_MATCHERS(closes #529; resolves the architectural gap historically tracked as mksglu/context-mode#329). Installs pinned to a pre-1.0.122 upstream still hit the original gap — upgrade with/plugin install context-mode@context-mode(recommended) ornpm install -g context-mode@latest(legacy MCP-server form) to pick up the fix. Field-validated bytests/test-phase-57-mcp-capture.shagainst the canonical 1.0.122 matcher inventory.
Registration uses a small dispatcher helper at hooks/project/context-mode-hook-dispatch.sh (installed into .claude/hooks/ by setup.sh --project). The registered command is bash <abs>/.claude/hooks/context-mode-hook-dispatch.sh <event>; the dispatcher exec's the global context-mode binary when present and falls back to npx -y context-mode@latest only when no global install exists. This ensures hooks fire correctly whether or not context-mode is globally installed and eliminates the ENOTEMPTY race that bare npx -y @latest suffers under rapid concurrent hook fires (see "Why a dispatcher" below). The merge is idempotent — re-running setup.sh --project does not duplicate entries. Pass --skip-context-mode to opt out; no upstream entries are written.
Our own project hooks (session-gate, ctx-execute-enforcer, cmm-nudge, etc.) remain registered ahead of the upstream entries — their additive enforcement runs first.
Why a dispatcher (not bare
npx -y context-mode@latest). Every tool call triggers both PreToolUse and PostToolUse hooks. In active sessions with rapid Bash/Read/mcp__*calls, parallelnpx -y context-mode@latestinvocations race to refresh the~/.npm/_npx/<hash>/cache against@latestand collide during atomic rename withENOTEMPTY. Claude Code reports these as "non-blocking" (session continues) but the losing hook silently skips capture. The dispatcher short-circuits to the globalcontext-modebinary when it's on PATH, avoidingnpxentirely on the hot path and eliminating the race for the vast majority of setups. Users with no global install still work via thenpxfallback — the first invocation primes the cache and subsequent calls hit it serially.
Matcher-drift heal (overwrites user matcher edits on upstream entries). On every
setup.sh --projectrun, the merge finds each upstream entry by substring match on eitherhook claude-code <event>(legacy/npx form) orcontext-mode-hook-dispatch.sh <event>(current form). It rewrites thematcherfield back to the upstream default if the two diverge; this keeps all installs on the same tool-coverage contract. User customizations to thematcherfield on these five entries are overwritten. User customizations appended to the dispatcher command (e.g.bash /path/dispatch.sh posttooluse --verbose) are preserved — the heal only rewrites the command whencontext-mode-hook-dispatch.sh <event>is absent. Early phase-51 installs using the bare-form or npx-launcher commands are rewritten in-place to the dispatcher form on re-run. Matchers on your other (non-upstream) hook entries — including the CMM enforcement hooks and anything you added by hand — are never touched.
VBW is a structured planning/agent workflow. It is optional and auto-detected — CMM is fully functional without it. When VBW is present, this repo makes its agents CMM-aware; when it is absent, nothing about VBW is required and the bundled agent deltas stay inert.
- Auto-detection (installed plugins only).
setup.shuseshooks/lib/vbw-source.sh(resolve_vbw_source) to locate VBW, but only an actual plugin install counts as "available": a marketplace install or an active--plugin-dirlocal symlink. A bare dev-checkout (a VBW source clone sitting in~/Sources) does not count — so a project migrating away from VBW isn't handed VBW agents just because source happens to be on disk. Pass--with-vbwto opt a dev-checkout back in. - Zero VBW footprint when absent. When VBW is not installed, a
--projectinstall writes no VBW files at all: theagents/vbw-*.mddeltas are not injected, and the two VBW-only files —hooks/lib/vbw-source.sh(the detection library) andhooks/project/agent-override-generate.sh(the SessionStart generator) — are not copied and its SessionStart registration is not written. Any VBW artifacts from a prior install (deltas, generated overrides, the two infra files) are moved aside into.claude/.cmm-setup/vbw-agents.bak/(reversible). Install VBW (or pass--with-vbwfor a dev-checkout) and re-runsetup.shto enable the overrides. - No planning directory required. A CMM-only project has no
.vbw-planning/. Setup state that used to live there (Context Mode migration sentinels, optional CMM config) now lives under.claude/.cmm-setup/; legacy.vbw-planning/copies are still read for back-compat. - Migrating an existing install off VBW. If a project was previously set up with VBW and you re-run
setup.sh --projecton a machine where VBW is no longer resolvable, setup moves any stale generated.claude/agents/vbw-*.mdoverrides aside into.claude/.cmm-setup/vbw-agents.bak/(reversible — files are moved, not deleted) so Claude Code stops loading them. The inert delta files and hooks stay in place, so the stack self-heals if VBW returns.
Remove the whole stack from a project or globally with --uninstall (requires an explicit scope):
bash setup.sh --uninstall --project --dry-run # preview what would be removed
bash setup.sh --uninstall --project # remove from this project
bash setup.sh --uninstall --global # remove global install
bash setup.sh --uninstall --all --yes # remove both, no prompt- What it removes: the hooks,
hooks/lib/helpers, rules, skills, VBW agent deltas + generated overrides, the statusline hook, the optional metrics tool, and.claude/.cmm-setup/— plus the stack's hook registrations, permission-allowlist entries, andstatusLineblock fromsettings.json/settings.local.json. - What it preserves: user-owned hooks, agents, skills, and any other
settings.jsonentries the stack did not add are left untouched. - Reversible: removed files are moved into a timestamped
.cmm-setup-uninstall-<ts>/backup dir under the target, and edited JSON files are backed up there first. Delete the backup once you're satisfied. - MCP servers:
.mcp.jsonentries forcodebase-memory-mcpandcontext-modeare left intact by default (they're external tools you may want to keep). Pass--purge-mcpto remove them too. - Honors
--dry-runand--yes. Restart any open Claude Code sessions afterward.
If the enforcement gates feel like they're misfiring — blocking things they shouldn't, or Claude doesn't seem to be using the CMM/Context-Mode tools the way the rules intend — you can capture a token-cost report of the gates and attach it to a problem report.
The tool: scripts/analyze-gate-blocks.py — a standalone, read-only Python CLI (no Claude
session, no network, no writes). It scans your Claude Code session transcripts and reports, per
gate, how often each fired and what it cost in tokens (injected block messages + the follow-up
reasoning), plus high-confidence false-positive blocks.
Two ways to run it:
# A) Straight from a cloned repo (always present):
python3 scripts/analyze-gate-blocks.py --all --share
# B) Installed copy, if you ran setup.sh --with-metrics (opt-in; off by default):
python3 ~/.claude/tools/analyze-gate-blocks.py --all --share # --global install
python3 .claude/tools/analyze-gate-blocks.py --all --share # --project installAlways use
--sharewhen posting publicly. It redacts project identities — the "Top projects by blocks" list shows opaque ordinals (project-01, …) instead of slugs, so no usernames, client/project names, or paths leave your machine. All other rows are aggregate and non-identifying. (Omit--sharefor full, named output for your own local use.)
Attach the --share output to an issue at
https://github.com/halindrome/cmm-claude-code-setup/issues.
Also worth trying first: just ask Claude directly — "why aren't you using your CMM / context-mode rules and tools?" It can often explain (e.g. the repo isn't indexed, a gate is failing open, or a rule is being misread) and self-correct without a report.
The benchmarks/ directory contains a reproducible benchmark suite comparing three variants:
- baseline: No MCP tools (Claude reads files directly)
- cmm-cold: CMM enabled, fresh index each run
- cmm-cache: CMM enabled, pre-warmed index
./benchmarks/run.shSee benchmarks/README.md for prerequisites, configuration, and result interpretation.
- Claude Code CLI
- codebase-memory-mcp binary
python3(required — used by setup.sh for JSON merging and hook input parsing)jq(recommended — used by some hooks for JSON parsing)- Context Mode MCP (optional)
sqlite3(optional — required for Context Mode event logging)
This project uses a two-branch model:
| Branch | Purpose |
|---|---|
main |
Stable releases only. Every merge from develop requires a version bump. Tagged with vX.Y.Z. |
develop |
Active development. All feature branches merge here first. |
feature/* |
Short-lived branches for individual changes. Branch from develop, PR back to develop. |
Release flow: feature/* → develop → main (tagged)
To start new work:
git checkout develop
git pull origin develop
git checkout -b feature/my-feature
# ... make changes ...
git push origin feature/my-feature
# Open PR targeting develop- codebase-memory-mcp by DeusData
- Context Mode MCP by mksglu
- Repository structure and enforcement approach inspired by jmunch-claude-code-setup by Shachar Bard
The hooks, rules, and documentation in this repository are licensed under the MIT License.
This repo does not include either MCP server — only the configuration and enforcement tooling. Each MCP server is a separate project subject to its own license.