How to Ignore Files with .cbmignore and Understand Layer Precedence in codebase-memory-mcp
The .cbmignore file lets you exclude specific files and directories from indexing using .gitignore-style patterns, evaluated through five strict layers where the first rejection wins and only negations targeting the global Git exclude layer can be overridden.
The codebase-memory-mcp project (available at DeusData/codebase-memory-mcp) uses a layered discovery system to decide which paths enter the index graph. While the tool respects your existing Git ignore rules, .cbmignore provides an additional project-specific filter with unique precedence semantics. Understanding how these layers interact ensures you configure exclusions correctly without unexpected indexing behavior.
What Is .cbmignore?
.cbmignore is a repository-specific ignore file read once from the repository root (<repo>/.cbmignore). It follows standard .gitignore glob syntax—supporting wildcards, glob-stars (**), character classes, and leading ! for negation. According to the specification in docs/cbmignore.md, this file allows teams to define exclusions that apply only to the memory indexing context, separate from version control rules.
When the discovery walk runs (implemented in src/discover/discover.c), the indexer evaluates every path through a fixed sequence of five filtering layers. The first layer that rejects a path terminates evaluation immediately, making layer precedence critical to effective configuration.
The Five Layers of Discovery Filters
The discovery process applies filters in the following strict order, as defined in the core discovery implementation:
1. Built-in Skip List
The indexer maintains a hard-coded list of approximately 60 entries including .git, node_modules, dist, target, vendor, and common tool caches. These skips are non-negotiable—no ignore file can override them, and they are applied before any file system inspection occurs.
2. Repository Root .gitignore
The repository's root .gitignore merges with the git common-directory info/exclude file. Within this layer, later patterns take precedence over earlier ones, following standard Git conflict resolution semantics.
3. Nested .gitignore Files
During directory traversal, any .gitignore files found in subdirectories are evaluated relative to their containing directory. These nested rules apply dynamically as the walk descends, with patterns later in the traversal capable of overriding earlier definitions.
4. .cbmignore Rules
The .cbmignore file at the repository root applies at this stage. A positive match here skips the path permanently. However, negated patterns (!pattern) in .cbmignore possess limited scope: they can rescue paths only from Layer 5 (Git global excludes). They cannot un-exclude files rejected by the built-in list, root .gitignore, or nested .gitignore files.
5. Git Global Excludes
The final layer references the file specified by Git's core.excludesFile configuration (typically ~/.config/git/ignore or ~/.gitignore_global). This layer applies only when the project is a valid Git repository, and it represents the only layer that .cbmignore negations can override.
Note: Additional fast-mode filters for file suffixes, size caps, and symlinks run before these five layers and are equally non-overridable by
.cbmignore.
How to Create and Configure .cbmignore
Create a file named .cbmignore in your repository root. Add one pattern per line—blank lines and lines starting with # are ignored. The syntax mirrors .gitignore:
# Exclude generated protobuf files anywhere
*.pb.go
# Exclude a top-level directory specifically
/third_party/
# Exclude "snapshots" directories at any depth
snapshots/
# Exclude everything under any fixtures directory
**/fixtures/**
Commit this file to share indexing exclusions with your team, or add it to .gitignore if the rules should remain local. Changes take effect on the next indexing run, which can be triggered manually or will occur automatically depending on your configuration.
Negation Patterns and Their Limitations
Within .cbmignore, patterns evaluate top-to-bottom, and the last matching pattern wins. This allows you to exclude broad categories while re-including specific files:
# Exclude all YAML files
*.yaml
# But keep the CI configuration
!ci.yaml
Critical limitation: Negations can only rescue paths from Layer 5 (Git global excludes). If a file is excluded by the built-in skip list, root .gitignore, or nested .gitignore, a .cbmignore negation cannot save it. Additionally, if a parent directory is excluded, the walk never descends into it, making subdirectory negations ineffective unless you also negate the parent.
Practical Examples
Excluding Build Artifacts
To prevent build outputs from polluting the index while respecting that these might be tracked or ignored differently in Git:
# .cbmignore at repo root
obj/
dist/
*.o
*.a
This skips all obj/ and dist/ directories regardless of .gitignore status, applying at Layer 4.
Overriding Global Git Excludes
Assume your global Git exclude (~/.config/git/ignore) contains *.sql to ignore database dumps across all projects. To ensure SQL files are indexed in this specific repository:
# .cbmignore
!*.sql
This negation operates at Layer 4 to rescue the files from Layer 5, while still respecting built-in skips and repository .gitignore rules.
Selective Directory Inclusion
To ignore a generated directory except for a specific subdirectory you need indexed:
# .cbmignore
# Exclude everything under "generated/"
generated/**
# Rescue only the "keep" subdirectory
!generated/keep/
Because excluding generated/ prevents the walker from descending into it, you must explicitly negate generated/keep/ to re-enable traversal into that path.
Verifying Your Ignore Rules
When running codebase-memory-mcp index_repository, the response includes an excluded field showing which directories were omitted. As implemented in src/mcp/mcp.c, the output format is:
{
"dirs": ["third_party/", "snapshots/"],
"count": 2,
"truncated": false
}
This diagnostic confirms which layers filtered specific paths, allowing you to verify that your .cbmignore patterns apply as expected.
Summary
.cbmignoreresides at the repository root and uses standard glob syntax defined indocs/cbmignore.md.- Five layers evaluate in fixed order: built-in skips, root
.gitignore, nested.gitignore,.cbmignore, and global Git excludes. - First match wins—once a path is rejected by any layer, evaluation stops.
.cbmignorenegations (!pattern) can only rescue files from the global Git exclude layer, not from.gitignoreor built-in rules.- Verify exclusions through the JSON output returned by the indexing command.
Frequently Asked Questions
Can .cbmignore override .gitignore rules?
No. .cbmignore operates at Layer 4, while repository and nested .gitignore files occupy Layers 2 and 3. Because the discovery walk evaluates layers sequentially and stops at the first rejection, a file excluded by .gitignore never reaches the .cbmignore evaluation stage. Only Layer 5 (Git global excludes) can be overridden by .cbmignore negations.
Why isn't my negated pattern re-including files?
Negated patterns in .cbmignore (!pattern) only affect paths caught by the Git global exclude layer. If the file is excluded by the built-in skip list, root .gitignore, or nested .gitignore, the negation cannot rescue it. Additionally, if you exclude a parent directory, the indexer never traverses into it, so negating a child path has no effect unless you also negate the parent directory itself.
Where should I place the .cbmignore file?
Always place .cbmignore in the repository root (<repo>/.cbmignore). The discovery implementation in src/discover/discover.c reads this file exactly once at the beginning of the indexing process and does not search for it in subdirectories. Patterns inside the file can target paths at any depth using relative patterns or glob-stars.
How do I check which files were excluded by which layer?
Run the codebase-memory-mcp index_repository command and inspect the excluded field in the JSON response. This output lists the directories omitted during discovery, though it aggregates results from all layers. For detailed debugging, consult the implementation in src/mcp/mcp.c which handles the diagnostic messaging during the discovery walk.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →