# What Is the Nearest-Marker Capture Policy in ai-memory?

> Discover the nearest marker capture policy in ai-memory. Learn how this client-side filter efficiently ignores files using .ai-memory.toml rules, optimizing your AI memory operations.

- Repository: [Fabio Akita/ai-memory](https://github.com/akitaonrails/ai-memory)
- Tags: deep-dive
- Published: 2026-08-21

---

**The nearest-marker capture policy in ai-memory is a client-side filtering mechanism that walks upward from the current working directory to locate the closest [`.ai-memory.toml`](https://github.com/akitaonrails/ai-memory/blob/main/.ai-memory.toml) file and applies its `[capture]` ignore_paths rules to drop matching file-tool events before they reach the spool, network transport, or server storage.**

The `akitaonrails/ai-memory` repository implements this deterministic configuration hierarchy to give developers granular control over privacy and data capture. By enforcing that only the nearest marker file is authoritative, the system prevents accidental inheritance of exclusion rules from parent directories while ensuring sensitive files never leave the local machine.

## How the Nearest-Marker Policy Locates Configuration

When an ai-memory hook executes, it must determine which capture rules apply to the current working context. The resolution follows a strict upward traversal algorithm.

### Walking the Directory Tree

The hook begins at the current working directory (`cwd`) and walks upward toward the user's home directory. It stops immediately upon encountering the first [`.ai-memory.toml`](https://github.com/akitaonrails/ai-memory/blob/main/.ai-memory.toml) file—this becomes the *nearest marker* as documented in [[`docs/marker-file.md`](https://github.com/akitaonrails/ai-memory/blob/main/docs/marker-file.md)](docs/marker-file.md#where-to-put-it). If the `cwd` resides outside any version-controlled checkout, the traversal terminates at the nearest Git repository root instead.

If no marker exists in the ancestry, the system falls back to examining only the `cwd` itself with no exclusion rules applied.

### Fallback to Git Repository Roots

When the directory tree walk reaches a Git repository boundary before finding a marker file, that repository root serves as the stopping point. This design ensures that repository-specific configurations remain scoped to their respective codebases, preventing leakage of capture policies across unrelated projects.

## Applying Capture Rules from the Nearest Marker

Once identified, the nearest marker's `[capture]` section dictates which file-tool events are discarded locally. This filtering occurs entirely on the client side, meaning excluded paths never traverse the network or persist to server storage.

### The ignore_paths Array

The marker file defines exclusions through the `ignore_paths` array within the `[capture]` section. Any file-tool event whose path matches one of these glob patterns is **dropped locally** before reaching the spool or queue.

```toml

# .ai-memory.toml in repository root

[capture]
ignore_paths = ["private/**", "~/personal-notes/**", "*.secret"]

```

Pattern syntax supports standard globs including `*`, `?`, and `**` for recursive matching. Paths normalize lexically before comparison, with `~/` expanding to the home directory. Platform behavior differs: POSIX systems perform case-sensitive matching, while Windows uses ASCII case-insensitive comparison.

### Client-Side Event Dropping

The implementation in `src/ai_memory_hooks/` enforces these exclusions immediately upon event generation. When a file-tool event matches an `ignore_paths` pattern, the hook discards it before any spool or network activity occurs. Non-file-tool events—such as prompts or metadata—remain unaffected by the capture policy.

If the nearest marker lacks a `[capture]` section or specifies an empty `ignore_paths` array, ai-memory retains the default behavior: no paths are excluded.

## Why Markers Do Not Merge

The nearest-marker policy enforces **single-source authority**. Unlike configuration systems that cascade or merge settings from multiple files, ai-memory uses only the closest [`.ai-memory.toml`](https://github.com/akitaonrails/ai-memory/blob/main/.ai-memory.toml) file and ignores any outer markers. This design guarantees deterministic capture behavior in complex directory structures such as monorepos or multi-client setups.

By preventing policy merging, the system eliminates ambiguity about which rules apply to a given file operation. An inner marker completely overrides parent configurations, ensuring that developers working within nested subdirectories control their own capture boundaries without inheriting unintended exclusions from organizational root directories.

## Pattern Syntax and Operational Limits

The capture policy enforces strict resource boundaries to prevent performance degradation:

| Property | Specification |
|----------|---------------|
| **Maximum patterns** | 128 entries in `ignore_paths` |
| **Pattern length** | ≤ 1,024 characters per pattern |
| **Path candidates** | 32 direct candidates per event |
| **Candidate length** | ≤ 4,096 characters per candidate path |
| **Comparisons** | Up to 1,000,000 pattern/candidate comparisons |

Matching events drop immediately; non-matching events proceed through the standard pipeline. If the policy is malformed or the marker unreadable, the system treats the capture policy as ignored and processes the event as metadata-only.

## Practical Configuration Examples

Create a marker file in your repository root to exclude sensitive directories from all subdirectories:

```bash
cat > .ai-memory.toml <<'EOF'
[capture]
ignore_paths = ["private/**", "~/personal-notes/**"]
EOF

```

Test the policy with specific tool operations:

```bash

# This event is stored (no pattern match)

ai-memory hook --event post-tool-use --agent claude-code \
    --tool_name Edit \
    --tool_input '{"path":"src/main.rs"}' \
    --server-url http://127.0.0.1:49374

# This event is dropped locally (matches private/**)

ai-memory hook --event post-tool-use --agent claude-code \
    --tool_name Edit \
    --tool_input '{"path":"private/secret.txt"}' \
    --server-url http://127.0.0.1:49374

```

Verify capture decisions without affecting the spool:

```bash
printf '{"session_id":"demo","cwd":"/example/workspace","tool_name":"Edit","tool_input":{"path":"private/secret.txt"}}' \
 | ai-memory hook --event post-tool-use --agent claude-code \
   --server-url http://127.0.0.1:49374 --check-capture

# Output: JSON verdict showing the event was discarded due to capture policy

```

## Implementation Architecture

According to the akitaonrails/ai-memory source code, the capture policy implementation spans several key components:

- **[`docs/marker-file.md`](https://github.com/akitaonrails/ai-memory/blob/main/docs/marker-file.md)**: Defines the [`.ai-memory.toml`](https://github.com/akitaonrails/ai-memory/blob/main/.ai-memory.toml) format, nearest-marker resolution algorithm, and capture exclusion semantics.
- **`src/ai_memory_hooks/`**: Contains the hook implementation that performs client-side path matching against the nearest marker's `ignore_paths`.
- **[`docs/windows.md`](https://github.com/akitaonrails/ai-memory/blob/main/docs/windows.md) and [`docs/macos.md`](https://github.com/akitaonrails/ai-memory/blob/main/docs/macos.md)**: Document platform-specific hook commands that enforce the nearest-marker `[capture]` policy on their respective operating systems.

The hook implementation performs lexical path normalization and glob matching before spooling, ensuring that excluded paths never generate network traffic.

## Summary

- **The nearest-marker capture policy** traverses upward from `cwd` to find the first [`.ai-memory.toml`](https://github.com/akitaonrails/ai-memory/blob/main/.ai-memory.toml) file and uses it exclusively, ignoring parent markers.
- **Client-side dropping** occurs when file-tool paths match the `ignore_paths` globs defined in the marker's `[capture]` section.
- **Pattern syntax** supports standard globs with platform-specific case sensitivity (POSIX case-sensitive, Windows ASCII case-insensitive).
- **Hard limits** enforce maximums of 128 patterns, 1,024 characters per pattern, and 1,000,000 comparisons to maintain performance.
- **No merging** occurs between nested markers; the closest configuration wins completely, ensuring deterministic behavior in monorepos.

## Frequently Asked Questions

### What happens if no .ai-memory.toml file is found?

If the upward traversal from `cwd` reaches the home directory (or filesystem root if `$HOME` is unset) without finding a marker, the hook examines only the `cwd` itself and applies no capture exclusions. If the directory lies within a Git repository but outside any marked subtree, the walk stops at the repository root, and the event proceeds with default capture behavior.

### Does the nearest-marker capture policy affect all ai-memory events?

No. The `ignore_paths` filtering applies exclusively to file-tool events—operations involving file system paths such as edits, reads, or writes. Non-file-tool events including prompts, chat messages, and metadata transmissions bypass the capture policy entirely and process normally regardless of marker configuration.

### How do nested repositories handle conflicting capture policies?

Nested structures enforce strict hierarchy: the innermost [`.ai-memory.toml`](https://github.com/akitaonrails/ai-memory/blob/main/.ai-memory.toml) file completely overrides any outer markers. Subdirectories do not inherit `ignore_paths` from parent directories. When working in a subdirectory with its own marker, that marker's `[capture]` section governs exclusively, preventing accidental exclusion leaks from organizational root configurations while allowing sub-projects to define stricter privacy boundaries.

### What is the maximum number of ignore patterns allowed?

The system enforces a hard limit of **128 patterns** per marker file, with each pattern restricted to **1,024 characters**. Additionally, the implementation limits processing to 32 direct path candidates per event (each ≤ 4,096 characters) and caps pattern-matching computations at 1,000,000 comparisons. Exceeding these limits results in the capture policy being ignored, with events treated as metadata-only to prevent performance degradation.