How ai-memory Handles Auto-Scoping on Shared Servers: Isolation by Design

ai-memory isolates concurrent work sessions on shared servers by deriving a unique scope identifier from the current working directory, ensuring that hand-offs, observations, and wiki pages remain invisible to clients operating outside the same workspace-project-path tuple.

When multiple developers or AI agents operate on shared servers, preventing cross-contamination of session data becomes critical. The ai-memory project solves this through an auto-scoping system that automatically binds every session to a derived context based on filesystem location. According to the source code in akitaonrails/ai-memory, the server constructs a scope tuple from the workspace, project, and path—effectively creating invisible boundaries that keep each user's data compartmentalized without manual configuration.

How the Auto-Scoping Mechanism Works

Deriving the Scope Identifier from the Working Directory

The foundation of auto-scoping lies in filesystem introspection. When a client connects, the server reads the current working directory (or respects an explicit --cwd flag) and resolves the active project configuration. In crates/ai-memory-core/src/active_project.rs, the ai_memory_core::active_project module computes a scope tuple consisting of (workspace_id, project_id, path). This tuple serves as the unique identity for the session's data boundary.

The resolution logic searches for an .ai-memory.toml file in the directory hierarchy to determine project boundaries, falling back to repository root heuristics when necessary. You can observe this resolution programmatically:

use ai_memory_core::active_project::ActiveProject;

let active = ActiveProject::from_cwd()?;   // reads .ai-memory.toml or defaults
println!("workspace: {}", active.workspace_id);
println!("project: {}", active.project_id);
println!("path: {}", active.path);

Session Ownership and the Scope Tuple

Once derived, the scope tuple becomes the session's owner identifier. As documented in docs/users.md at line 26, the server records this identifier at session start. Legacy sessions that contain a NULL owner field are treated as shared resources and do not benefit from automatic isolation. This distinction ensures that new sessions are private by default while preserving backward compatibility for older data.

Automatic Hand-Off Inheritance

Hand-offs—structured data exchanges between sessions—automatically inherit the creating session's scope. When the server generates automatic hand-offs at SessionStart or SessionEnd events, it invokes ai_memory_core::routing_snippet to attach the current scope identifier. As noted in docs/users.md at line 570, this means a hand-off created in /tmp/project_a will only appear to clients whose derived scope matches that specific workspace-project-path combination.

The server creates these scoped hand-offs using the internal API:

use ai_memory_core::handoff::Handoff;

let handoff = Handoff::new_auto(&session_id, "session_start")?;
ai_memory_mcp::admin::store_handoff(&handoff)?;

Isolation Guarantees on Shared Infrastructure

Path-Based Separation of Concurrent Sessions

The path-derived scope ensures that two agents running simultaneously on the same server under the same user account remain isolated if they operate from different directories. The test suite in crates/ai-memory-mcp/tests/autoscope_multiuser.rs validates this behavior by spawning separate sessions with distinct working directories and asserting that hand-offs created in one scope are inaccessible from another.

This filesystem-level boundary is verified through automated testing:

#[tokio::test]
async fn autoscope_isolation() {
    let sess_a = start_session_with_cwd("/tmp/project_a").await;
    let sess_b = start_session_with_cwd("/tmp/project_b").await;
    // sess_a creates a hand‑off
    let h = handoff_create(&sess_a, "test").await;
    // sess_b cannot fetch it
    assert!(handoff_fetch(&sess_b, h.id).await.is_err());
}

Legacy Session Handling and Fallback Behavior

If a client fails to provide a session ID or if the working directory cannot be resolved to a valid project configuration, the server falls back to a global scope. This fallback preserves system operability but triggers a warning that data will be shared across all global-scope clients. The global scope acts as a compatibility layer for pre-scoping deployments while encouraging migration to isolated sessions.

Configuration and Customization

Operators can tune auto-scoping behavior through the auto_scope section in ai-memory.toml. As documented in docs/mcp-install.md between lines 140 and 157, the default mode = "per_session" instructs the server to derive unique scopes for every connection. While the configuration allows adjustment of scoping modes, the core algorithm always prefers an explicit scope over the global fallback, ensuring that intentional isolation takes precedence.

Summary

  • ai-memory derives session isolation from the filesystem path, creating a scope tuple of (workspace_id, project_id, path).
  • The ActiveProject::from_cwd function in crates/ai-memory-core/src/active_project.rs computes this tuple by inspecting .ai-memory.toml or repository roots.
  • Sessions with valid scopes cannot access hand-offs from other scopes, even when sharing the same server and user account.
  • Legacy sessions with NULL owners default to shared behavior for backward compatibility.
  • The system falls back to a global scope only when path resolution fails, warning operators of potential data sharing.

Frequently Asked Questions

How does ai-memory prevent data leakage between users on the same server?

ai-memory prevents leakage by binding every session to a unique scope identifier derived from the working directory. Because the ai_memory_core::routing_snippet module filters all hand-off and observation queries by this scope tuple, a session running in /home/user/project-a cannot retrieve data from /home/user/project-b, regardless of operating system user permissions.

What happens if a client connects without a session ID?

When a client omits a session ID or provides an unresolvable path, the server falls back to a global scope. This mode maintains system functionality but removes isolation guarantees, logging a warning that subsequent data will be visible to all other global-scope clients.

Can I disable auto-scoping for legacy compatibility?

While you cannot fully disable scope checking, you can configure legacy-like behavior by omitting .ai-memory.toml configurations and allowing sessions to default to the global scope. Alternatively, adjusting settings in the auto_scope section of ai-memory.toml can relax isolation, though the system always prefers explicit scope definitions where detected.

How is the workspace and project ID determined from the filesystem?

The server traverses the directory hierarchy from the current working directory upward, searching for .ai-memory.toml files that define project boundaries. If found, the file contents determine the workspace_id and project_id; otherwise, the system uses the repository root name and directory path as identifiers, as implemented in crates/ai-memory-core/src/active_project.rs.

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 →