How the codebase-memory-mcp Configuration System Handles .cbmignore and File Filtering

The codebase-memory-mcp configuration system uses a deterministic five-layer ignore pipeline that processes files from built-in exclusions through Git ignore patterns to project-specific .cbmignore rules, where the last matching pattern wins within each layer.

The discovery engine in codebase-memory-mcp implements a sophisticated file filtering mechanism that determines which paths enter the index by evaluating ignore rules in strict hierarchical order. This configuration system combines hard-coded exclusions with dynamic pattern matching to give developers granular control while maintaining predictable indexing behavior across large repositories.

The Layered Ignore Pipeline in codebase-memory-mcp

The system processes potential paths through five distinct layers, stopping immediately when any layer rejects a path. Within each layer, the last matching rule wins, allowing subsequent patterns to override earlier ones at the same precedence level.

Layer 1: Built-In Skip List

The foundation consists of hard-coded directory names that cannot be overridden by any configuration file. According to src/discover/discover.c lines 514–516, these include .git, node_modules, dist, and other common build artifacts. These exclusions are enforced via the is_safety_core_dir check before any pattern matching occurs, making them absolute barriers in the pipeline.

Layers 2–3: Git ignore Integration

The next layers process standard Git ignore patterns. First, the repository-level .gitignore combined with .git/info/exclude is evaluated. During the directory walk, the engine discovers and applies nested .gitignore files relative to their containing directories. These follow standard gitignore syntax and precedence, with patterns evaluated in standard Git order.

Layer 4: Project-Specific .cbmignore

The fourth layer introduces the project-specific .cbmignore file, loaded only from the repository root (<repo>/.cbmignore). As specified in docs/cbmignore.md line 5, nested .cbmignore files are explicitly ignored. This file supports full gitignore syntax including wildcards, ** globstars, and character classes, parsed by the cbm_gitignore_load function in src/discover/gitignore.c.

Layer 5: Global Git Excludes

The final layer applies the user-wide exclude file configured via Git's core.excludesFile setting. This represents the broadest scope of user-specific ignores and is the only layer that .cbmignore negations can potentially override.

How .cbmignore Rules Are Processed

Understanding the specific behavior of .cbmignore requires examining how negations interact with the layered pipeline and directory traversal constraints.

Root-Only Configuration

Unlike Git ignore files, the codebase-memory-mcp configuration system restricts .cbmignore to the repository root only. The implementation in src/discover/discover.c lines 1038–1043 explicitly constructs the path as "%s/.cbmignore" and loads it once at startup:

char gi_path[PATH_MAX];
snprintf(gi_path, sizeof(gi_path), "%s/.cbmignore", repo_path);
cbm_gitignore_t *cbmignore = cbm_gitignore_load(gi_path);

This design choice simplifies precedence calculations but means subdirectories cannot maintain their own .cbmignore files.

Negation Patterns and Precedence

Positive matches (e.g., generated/) immediately exclude the path. Negated patterns using !pattern can re-include paths, but with critical limitations. As documented in lines 99–104 of docs/cbmignore.md, a negation can only rescue a path from the global-exclude layer (Layer 5). It cannot override the built-in skip list, the repository's .gitignore, or file suffix/size filters that run earlier in the pipeline.

Within the .cbmignore file itself, the last matching rule determines the outcome, as noted in line 36 of the documentation.

The Parent Directory Constraint

A critical edge case involves directory traversal. If a parent directory is excluded by an earlier rule in the pipeline, the engine never descends into it. Consequently, as documented in lines 95–97, a file cannot be rescued by a negation if its ancestor directory remains excluded. This optimization prevents unnecessary filesystem operations but requires careful ordering of ignore patterns to ensure intended files remain accessible.

Implementation: Loading and Matching Patterns

The actual implementation bridges the configuration loading and the directory walk. When processing entries in walk_dir_process_entry, the system calls cbm_gitignore_match_result to evaluate paths against the loaded .cbmignore rules.

A negative return value from cbm_gitignore_match_result indicates exclusion, while a positive return allows the path. Lines 538–540 of src/discover/discover.c demonstrate this logic:

/* In the directory walk */
bool unskipped = cbmignore && !is_safety_core_dir(entry_name) &&
                 cbm_gitignore_match_result(cbmignore, rel_path, true) < 0;
if (unskipped) {
    // path rescued by a .cbmignore negation
}

This code demonstrates that even when .cbmignore suggests inclusion, the built-in safety check (is_safety_core_dir) remains absolute. The rel_path parameter provides the repository-relative path for pattern matching against the rules loaded by cbm_gitignore_load.

Key source files supporting this functionality include:

Summary

  • The codebase-memory-mcp configuration system implements a five-layer ignore pipeline with strict precedence order
  • Built-in exclusions (Layer 1) are immutable and checked first via is_safety_core_dir in src/discover/discover.c
  • .cbmignore (Layer 4) supports full gitignore syntax but is only read from the repository root, as implemented in lines 1038–1043
  • Negation patterns (!) can only rescue files from Layer 5 (global Git excludes), not from built-in skips or .gitignore
  • Parent directory exclusion prevents file rescue if ancestors are filtered, optimizing the directory walk according to lines 95–97 of the specification
  • The matching logic resides in cbm_gitignore_match_result, called during walk_dir_process_entry with negative return values indicating exclusion

Frequently Asked Questions

Can .cbmignore override .gitignore rules?

No. According to the codebase-memory-mcp source code documentation (lines 99–104), negated patterns in .cbmignore cannot rescue paths excluded by the repository's .gitignore (Layers 2–3). Negations only affect paths excluded by Layer 5 (Git global excludes). The layered pipeline processes .gitignore before .cbmignore, and earlier layer rejections are final unless they come from the global exclude file.

Why isn't my negated pattern working?

Your negated pattern (!pattern) likely fails for one of three reasons: it attempts to override the built-in skip list or .gitignore, it targets a file whose parent directory remains excluded (preventing directory descent), or it is not the last matching rule in the file. Remember that within .cbmignore, the last matching rule wins, and parent exclusions block access to all children regardless of negation patterns.

Where should I place my .cbmignore file?

Always place .cbmignore in the repository root only. The discovery engine explicitly loads %s/.cbmignore relative to the repository path and ignores nested .cbmignore files, as specified in docs/cbmignore.md line 5. Placing the file in subdirectories has no effect on the indexing behavior.

How do I exclude specific file types?

Add standard gitignore patterns to your .cbmignore file in the repository root. For example, use *.log to exclude log files or build/ to exclude directories. These patterns support wildcards, ** for recursive matching, and character classes. However, note that built-in suffix filters and size limits may run before ignore file evaluation according to the pipeline architecture.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →