How the .ai-memory.toml Marker File Enables Per-Project Isolation and Custom Routing

The .ai-memory.toml marker file acts as a lightweight filesystem anchor that namespaces all wiki pages, handoffs, and memory queries by declaring workspace and project boundaries, which the ai-memory client discovers by walking up the directory tree from the current working directory.

The ai-memory project implements a hierarchical configuration system to isolate data between different codebases, clients, and consulting engagements without requiring separate installations or global environment variables. By placing a .ai-memory.toml file anywhere in a directory tree, you create an authoritative routing boundary that automatically namespaces all subsequent operations according to the three-tuple (workspace, project, path).

Workspace Isolation and Project Scoping

The marker file defines routing metadata that prevents data collision across different contexts. The system uses three keys—workspace, project, and project_strategy—to construct the namespace for every memory operation.

Workspace isolation separates data between different clients or personal projects. By default, every session uses the workspace "default", but a marker can override this:


# .ai-memory.toml

workspace = "acme-consulting"

According to the marker schema documented at lines 45-48 of docs/marker-file.md, this value forces all child directories to share the same workspace boundary, effectively isolating data without requiring separate ai-memory installations.

Project scoping offers two strategies for deriving the project name. When project = "<name>" is explicitly set, that name applies to all current working directories under the marker. When omitted, the default strategy derives the project from the basename of the current working directory. Alternatively, setting project_strategy = "repo-root" (lines 54-58) forces the system to derive the project name from the main Git repository root, ensuring that subdirectories and linked worktrees share a single project namespace.

Filesystem Discovery Mechanism

The ai-memory CLI discovers markers through an upward filesystem walk implemented in crates/ai-memory-cli/src/marker.rs. The find_marker function (lines 106-138) searches from the current working directory toward the filesystem root until it locates the nearest .ai-memory.toml.

Once found, read_scope parses the configuration keys and returns a MarkerScope struct (lines 26-41). This scope object encapsulates the routing metadata required for all subsequent operations.

The discovery mechanism follows a strict nearest-wins precedence model. As documented at lines 26-31 in docs/marker-file.md, the walk stops at the first marker encountered, making inner markers authoritative over outer ones. The system never merges multiple markers; it always uses a single source of truth to avoid configuration ambiguity.

Routing Implementation and Query Parameters

The parsed marker fields drive server-side routing logic. In crates/ai-memory-cli/src/commands/hook_capture.rs, the hook-capture command converts the MarkerScope into query parameters (lines 247-254) that accompany every HTTP request to the server endpoint.

Because the marker's values are forwarded as query parameters, the server can route requests to the correct workspace and project without additional server-side configuration. This enables complex repository layouts including multi-client trees, mono-repos, and personal/workspace separation—all declared through a simple text file.

The following Rust example demonstrates how the CLI resolves the current scope using the marker discovery logic:

use ai_memory_cli::marker::{read_scope, find_marker};
use ai_memory_cli::env::RuntimeEnv;

fn main() {
    // Assume execution from "/home/dev/projects/acme/api"
    let cwd = std::env::current_dir().unwrap();
    let env = RuntimeEnv::load(); // Loads AI_MEMORY_* environment variables
    
    if let Some(scope) = read_scope(cwd.to_str().unwrap(), &env) {
        println!("Workspace: {}", scope.workspace.unwrap_or_else(|| "default".into()));
        println!("Project:   {}", scope.project.unwrap_or_else(|| "basename".into()));
    } else {
        println!("No marker found – falling back to defaults");
    }
}

Practical Configuration Examples

Place the .ai-memory.toml at the repository root to establish consistent routing for the entire project:


# .ai-memory.toml at repository root

workspace = "client-acme"
project_strategy = "repo-root"

# Optional: explicitly pin project name instead of deriving from repo root

# project = "backend-api"

This configuration ensures that all subdirectories, feature branches, and linked worktrees share the same project namespace while isolating this data from other workspaces.

Summary

  • The .ai-memory.toml marker creates a filesystem-based isolation boundary that namespaces all memory operations through a (workspace, project, path) tuple.
  • Discovery walks upward from the current working directory via find_marker in crates/ai-memory-cli/src/marker.rs, stopping at the nearest marker to establish authority.
  • Project scoping strategies include basename derivation (default) or repository-root derivation via project_strategy = "repo-root".
  • Server routing occurs by converting marker fields to query parameters in hook_capture.rs, enabling multi-client and mono-repo support without server reconfiguration.

Frequently Asked Questions

What happens if no .ai-memory.toml file exists in the directory tree?

If the filesystem walk reaches the root without finding a marker, the system falls back to default values: the workspace becomes "default", and the project name derives from the basename of the current working directory. This ensures the CLI remains functional in unmarked directories while maintaining predictable, isolated defaults.

Can I override a parent marker with a child directory configuration?

Yes. The discovery mechanism stops at the first .ai-memory.toml encountered when walking upward from the current working directory. An inner marker completely overrides any outer markers—the system does not merge configurations, ensuring the nearest configuration file serves as the single source of truth for that directory subtree.

How does project_strategy = "repo-root" differ from the default behavior?

The default strategy derives the project name from the basename of the current working directory, meaning src/ and tests/ would appear as separate projects. Setting project_strategy = "repo-root" forces the system to identify the main Git repository root and use its name as the project identifier, ensuring all subdirectories and worktrees share a unified project namespace.

Where should I place the .ai-memory.toml file in a mono-repo structure?

Place the marker at the repository root to share a single project namespace across all packages, or place individual markers within package subdirectories to create isolated projects for each component. According to the implementation in crates/ai-memory-cli/src/marker.rs, the CLI will respect whichever marker is closest to your current working directory, enabling flexible per-package or per-team isolation within the same repository.

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 →