# File Ignore Patterns in Codebase Memory MCP: How .cbmignore, .gitignore, and Hardcoded Rules Work

> Explore Codebase Memory MCP's ignore system: .cbmignore, .gitignore, and hardcoded rules for efficient file management. Understand how these patterns work together.

- Repository: [Martin Vogel/codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp)
- Tags: how-to-guide
- Published: 2026-07-20

---

**Codebase Memory MCP (CBM) implements a deterministic seven-layer ignore system where hardcoded safety rules, fast-mode filters, hierarchical .gitignore files, and project-specific .cbmignore patterns are evaluated in sequence, with later layers overriding earlier matches except for non-negatable safety-core directories.**

Codebase Memory MCP is a repository indexing engine that relies on sophisticated file ignore patterns to exclude irrelevant artifacts from memory. Understanding how `.cbmignore`, `.gitignore`, and hardcoded rules interact is critical for configuring optimal indexing coverage. The system evaluates exclusion criteria in strict priority order, ensuring that safety-critical directories remain protected while allowing fine-grained project customization.

## The Seven-Layer Ignore Architecture

CBM processes file ignore patterns through seven distinct layers defined in [`src/discover/discover.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/discover/discover.c). The evaluation order guarantees deterministic behavior:

1. **Hardcoded skip directories** – Always excluded (e.g., `.git`, `node_modules`)
2. **Hardcoded ignored suffixes** – File extensions blocked in all modes (e.g., `.pyc`, `.exe`)
3. **Fast-mode skip filenames** – Specific filenames excluded in `MODERATE` and `FAST` modes
4. **Fast-mode substring patterns** – Generic patterns excluded in non-`FULL` modes
5. **`.gitignore` hierarchy** – Repository root, nested, global, and per-clone exclusions
6. **`.cbmignore` overrides** – Project-specific ignores with negation support
7. **Safety-core enforcement** – Non-negatable protection for critical directories

## Layer 1 – Hardcoded Safety Directories and Suffixes

The base layer consists of static arrays compiled into the binary. These rules apply universally unless specifically bypassed by the indexing mode.

### Non-Negatable Directories (ALWAYS_SKIP_DIRS)

The `cbm_should_skip_dir()` function checks directories against `ALWAYS_SKIP_DIRS` at lines 31-51 of [`src/discover/discover.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/discover/discover.c). This list includes `.git`, `node_modules`, `venv`, and other build artifacts.

```c
bool cbm_should_skip_dir(const char *dirname, cbm_index_mode_t mode) {
    if (str_in_list(dirname, ALWAYS_SKIP_DIRS)) return true;
    if (mode != CBM_MODE_FULL && str_in_list(dirname, FAST_SKIP_DIRS)) return true;
    return false;
}

```

### File Extension Filters (ALWAYS_IGNORED_SUFFIXES)

Binary and generated file extensions are filtered by `cbm_has_ignored_suffix()` at lines 64-71. This checks `ALWAYS_IGNORED_SUFFIXES` (e.g., `.png`, `.exe`) and conditionally `FAST_IGNORED_SUFFIXES` based on mode.

```c
bool cbm_has_ignored_suffix(const char *filename, cbm_index_mode_t mode) {
    for (int i = 0; ALWAYS_IGNORED_SUFFIXES[i]; i++)
        if (ends_with(filename, ALWAYS_IGNORED_SUFFIXES[i])) return true;
    if (mode != CBM_MODE_FULL)
        for (int i = 0; FAST_IGNORED_SUFFIXES[i]; i++)
            if (ends_with(filename, FAST_IGNORED_SUFFIXES[i])) return true;
    return false;
}

```

## Layer 2 – Fast-Mode Optimizations (MODERATE and FAST)

When operating in `CBM_MODE_MODERATE` or `CBM_MODE_FAST`, CBM applies additional exclusions to improve performance. These are bypassed only in `CBM_MODE_FULL`.

### Additional Directories and Filenames

The `FAST_SKIP_DIRS` array expands directory exclusions, while `FAST_SKIP_FILENAMES` (checked at lines 80-87) filters specific files like `LICENSE`, `CHANGELOG`, and lock files.

### Substring Pattern Matching

At lines 91-99, `cbm_matches_fast_pattern()` searches for substrings indicating generated code (e.g., [`.d.ts`](https://github.com/DeusData/codebase-memory-mcp/blob/main/.d.ts), `.generated.`, `.test.`). These patterns are only active when `mode != CBM_MODE_FULL`.

## Layer 3 – Gitignore Hierarchy

CBM integrates deeply with Git's ignore semantics, supporting the complete `.gitignore` specification including negation and directory-specific rules.

### Repository Root and Nested Files

The discovery routine loads the repository-root `.gitignore` at lines 989-1016, then dynamically loads nested `.gitignore` files during directory traversal via `try_load_nested_gitignore()`. Later patterns in the hierarchy override earlier ones.

### Global Excludes and Per-Clone Exclusions

Global excludes are resolved from `core.excludesfile` (typically configured in `~/.gitconfig`) through `resolve_global_excludes_path()`. Per-clone exclusions are loaded from the Git common directory's `info/exclude` file.

```c
/* Load repo-root .gitignore */
char gi_path[CBM_SZ_4K];
snprintf(gi_path, sizeof(gi_path), "%s/.gitignore", repo_path);
cbm_gitignore_t *gitignore = cbm_gitignore_load(gi_path);

/* Merge global excludes if available */
if (has_git_config && resolve_global_excludes_path(gi_path, sizeof(gi_path)))
    global_gi = cbm_gitignore_load(gi_path);

```

## Layer 4 – Project-Specific .cbmignore

The `.cbmignore` file provides project-level control, loaded from `<repo>/.cbmignore` or a custom path specified in `opts->ignore_file` at lines 1037-1044.

### Loading and Syntax

`.cbmignore` uses standard gitignore syntax (globs, wildcards, directory anchors). The implementation in [`src/discover/gitignore.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/discover/gitignore.c) handles pattern matching through `cbm_gitignore_match_result()`.

### Negation Rules and Safety Restrictions

Negation patterns (e.g., `!obj/`) can un-skip paths excluded by `.gitignore` or earlier layers. However, **safety-core directories**—`.git`, `node_modules`, `.worktrees`, and `.claude-worktrees`—are immune to negation as enforced by `is_safety_core_dir()` at lines 22-25.

Lines 514-525 implement the negation logic:

```c
/* Directory-skip with possible negation */
bool unskipped = cbmignore && !is_safety_core_dir(entry_name) &&
                 cbm_gitignore_match_result(cbmignore, rel_path, true) < 0;
if (!unskipped) return true;       // keep the hard-coded skip

```

## How Mode Selection Affects Ignore Rules

The **indexing mode** controls whether fast-mode exclusions are active:

- **`CBM_MODE_FULL`**: Ignores only `ALWAYS_SKIP_DIRS` and `ALWAYS_IGNORED_SUFFIXES`, providing raw repository visibility
- **`CBM_MODE_MODERATE`** and **`CBM_MODE_FAST`**: Enable all fast-mode filters (`FAST_SKIP_DIRS`, `FAST_SKIP_FILENAMES`, `FAST_PATTERNS`)

This behavior is implemented in `cbm_should_skip_dir()` at lines 53-60 and `cbm_has_ignored_suffix()` at lines 64-71.

## Skip Reason Tracking

The `file_skip_reason()` function (lines referenced in the skip logic) returns a string identifier for why a file was excluded. Possible values include:

- `"gitignore"` – Matched a `.gitignore` pattern
- `"cbmignore"` – Matched a `.cbmignore` pattern
- `"ignored-suffix"` – Matched hardcoded extension filters
- `"skip-list"` – Matched fast-mode filename filters
- `"fast-pattern"` – Matched fast-mode substring patterns
- `"size-cap"` – Exceeded `opts->max_file_size`

## Summary

- CBM applies **seven layers** of file ignore patterns in strict priority order, from hardcoded safety rules to project-specific `.cbmignore` files.
- **Hardcoded directories** (`.git`, `node_modules`) and **suffixes** (`.pyc`, `.exe`) are filtered first and cannot be bypassed by negation patterns.
- **Fast-mode filters** (filenames, substring patterns) are only active outside `CBM_MODE_FULL`, allowing performance tuning.
- **Gitignore hierarchy** supports repository root, nested, global (`core.excludesfile`), and per-clone (`info/exclude`) exclusion files.
- **`.cbmignore`** supports standard gitignore syntax including negations (`!pattern`), but cannot un-skip safety-core directories (`.git`, `node_modules`, `.worktrees`, `.claude-worktrees`).

## Frequently Asked Questions

### What is the difference between .cbmignore and .gitignore?

`.cbmignore` is specific to Codebase Memory MCP and can override `.gitignore` exclusions through negation patterns (e.g., `!build/` to index a directory ignored by Git). However, unlike `.gitignore`, `.cbmignore` cannot override hardcoded safety-core directories like `.git` or `node_modules`. Both files use identical syntax rules as implemented in [`src/discover/gitignore.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/discover/gitignore.c).

### Can I override hardcoded directory exclusions like node_modules?

No. The directories `.git`, `node_modules`, `.worktrees`, and `.claude-worktrees` are designated as **safety-core** and are non-negatable. The `is_safety_core_dir()` function at lines 22-25 of [`src/discover/discover.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/discover/discover.c) prevents any pattern (including `.cbmignore` negations) from including these directories, protecting against OOM errors and duplicate indexing.

### How does the indexing mode affect which files are ignored?

The indexing mode determines whether **fast-mode** exclusions apply. In `CBM_MODE_FULL`, only `ALWAYS_SKIP_DIRS` and `ALWAYS_IGNORED_SUFFIXES` are active. In `CBM_MODE_MODERATE` or `CBM_MODE_FAST`, additional filters from `FAST_SKIP_DIRS`, `FAST_SKIP_FILENAMES`, and `FAST_PATTERNS` are evaluated, excluding files like `LICENSE`, `CHANGELOG`, and generated artifacts ([`.d.ts`](https://github.com/DeusData/codebase-memory-mcp/blob/main/.d.ts), `.test.`).

### Where should I place my .cbmignore file?

Place `.cbmignore` in your repository root to apply project-wide rules. Alternatively, specify a custom path via the `ignore_file` option in `cbm_discover_opts_t`. The file is loaded at lines 1037-1044 of [`src/discover/discover.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/discover/discover.c), defaulting to `<repo_path>/.cbmignore` if no custom path is provided. Nested `.cbmignore` files are not supported; use a single root file with path-specific patterns instead.