# How ai-memory Manages Multi-Session and Multi-User Access to Projects

> Discover how ai-memory handles multi-session and multi-user project access using per-actor tracking, session-scoped identity, and a single-writer SQLite actor for atomic updates and versioning.

- Repository: [Fabio Akita/ai-memory](https://github.com/akitaonrails/ai-memory)
- Tags: how-to-guide
- Published: 2026-09-11

---

**ai-memory isolates concurrent sessions through per-actor active-project tracking, session-scoped identity resolution, and a single-writer SQLite actor that enforces atomic updates and versioned supersession chains.**

The `ai-memory` project (github.com/akitaonrails/ai-memory) implements a robust concurrency model that allows multiple users and independent sessions to work simultaneously on shared projects without data corruption or cross-contamination. By combining strict session identity management with per-actor state tracking and atomic write batches, the system ensures that every read and write operation respects the caller's specific context and project scope.

## Session and User Identity Isolation

Every request to the ai-memory server carries a **session ID** provided by the MCP client. In [`crates/ai-memory-core/src/actor.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-core/src/actor.rs), the server creates a `Session` record that serves as the primary key for all subsequent operations, ensuring that state never leaks between connections.

User authentication is handled in [`crates/ai-memory-mcp/src/auth.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-mcp/src/auth.rs), which maps bearer tokens or database user tokens to a `User` struct containing `UserId`, name, and authorization level. This separation of **session identity** (transient connection) from **user identity** (persistent credentials) allows the system to distinguish between "who is connected" and "who is authorized" for every operation.

## Per-Actor Active Project Tracking

Each session maintains its own project context through the `ActiveProjectMode::PerActor` enumeration defined in [`crates/ai-memory-core/src/active_project.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-core/src/active_project.rs). The `ActiveProject` struct stores the per-actor pointer and resolves it on every incoming request.

This design guarantees that two concurrent sessions can operate on different "current projects" within the same workspace without interference. When Session A sets `project-x` as active and Session B sets `project-y` as active, the `ActiveProject` resolver ensures that subsequent commands from each session target their respective projects exclusively.

## Scope Resolution and Access Control

All read and write routes utilize the `ScopeResolver` helper functions—`lookup_existing_scope`, `create_explicit_scope`, and related utilities—located in [`crates/ai-memory-mcp/src/actor.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-mcp/src/actor.rs). These functions validate the `(workspace_id, project_id, path)` triple exactly once per operation.

By enforcing scope resolution at the actor boundary, the system prevents accidental cross-project leakage. The resolver checks that the requesting session's user has appropriate permissions for the specific workspace-project combination before allowing data access, effectively creating a security sandbox around each request.

## Atomic Writes and Conflict Prevention

Mutations flow through a **single-writer SQLite actor** pattern implemented in [`crates/ai-memory-store/src/writer.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/writer.rs). The `WriterHandle` receives commands via an `mpsc` channel, batches them into a single transaction, and commits both the data rows and accompanying index updates atomically.

This architecture eliminates "lost-update" race conditions that typically occur when several users edit the same page concurrently. Because all writes serialize through the single writer thread, SQLite's transactional guarantees ensure that even under heavy load, commits are processed sequentially without interleaving partial updates.

## Version Safety Through Supersession

When multiple sessions modify the same markdown page simultaneously, ai-memory does not overwrite existing data. Instead, the storage layer creates a **supersession chain** as implemented in [`crates/ai-memory-store/src/page.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/page.rs).

Each new write generates a supersession entry that references the previous version, establishing a linked history where the newest version is the head of the chain while older versions remain reachable. This satisfies the "last write wins" requirement without destroying historical data, allowing users to trace the evolution of content across concurrent editing sessions.

## Exclusive Resource Handoffs

Cross-session work handoffs utilize a double-guard mechanism defined in [`crates/ai-memory-core/src/handoff.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-core/src/handoff.rs). Handoff objects maintain a database row with `state = 'open'` and require an `UPDATE … WHERE state='open'` clause to succeed.

Both checks—the initial state query and the atomic update—must succeed for a handoff to be claimed. This guarantees that a handoff transfers work exactly once, even when multiple sessions attempt to claim the resource simultaneously under heavy concurrency.

## Practical Implementation Examples

The following examples demonstrate the multi-session API in practice.

Creating a new session with explicit session headers:

```rust
// The client library automatically includes a session header.
// Here we manually craft a request to illustrate the flow.
let client = reqwest::Client::new();
let resp = client
    .post("http://127.0.0.1:49374/api/v1/pages/write")
    .header("X-Session-Id", "sess-1234abcd")
    .header("Authorization", "Bearer <user-token>")
    .json(&serde_json::json!({
        "workspace": "demo-ws",
        "project": "demo-proj",
        "path": "notes/todo.md",
        "content": "# TODO\n- [ ] Refactor"

    }))
    .send()
    .await?;

```

Reading the current active project for a specific session:

```rust
let resp = client
    .get("http://127.0.0.1:49374/api/v1/active_project")
    .header("X-Session-Id", "sess-1234abcd")
    .send()
    .await?
    .json::<serde_json::Value>()
    .await?;
println!("Active project: {}", resp["project"]);

```

Handling concurrent edits that generate supersession chains:

```rust
// Session A writes version 1
write_page(sess_a, "shared.md", "Version 1");

// Session B writes version 2 at the same time
write_page(sess_b, "shared.md", "Version 2");

// After both commits, the store contains a supersession chain:
//   v1 -> v2 (v2 is the head, v1 still reachable)
let history = read_page_history(sess_a, "shared.md");
assert_eq!(history.len(), 2);

```

## Summary

- **Session isolation** is enforced through unique session IDs in [`actor.rs`](https://github.com/akitaonrails/ai-memory/blob/main/actor.rs) and authenticated `User` structs in [`auth.rs`](https://github.com/akitaonrails/ai-memory/blob/main/auth.rs), preventing cross-session data leakage.
- **Per-actor project tracking** via `ActiveProjectMode::PerActor` ensures each session maintains its own working context independently of other connections.
- **Scope resolution** in the MCP actor layer validates workspace-project-path triples before any data access occurs, establishing strict boundaries.
- **Single-writer architecture** serializes all mutations through `WriterHandle` in [`writer.rs`](https://github.com/akitaonrails/ai-memory/blob/main/writer.rs), providing atomic transactions that prevent lost updates.
- **Supersession chains** preserve complete edit history when concurrent writes occur, allowing non-destructive collaboration on shared pages.
- **Double-guard handoffs** guarantee exclusive claiming of transferred work items, ensuring state consistency during inter-session workflows.

## Frequently Asked Questions

### How does ai-memory prevent two users from overwriting each other's changes?

The system routes all write operations through a single-writer SQLite actor (`WriterHandle` in [`crates/ai-memory-store/src/writer.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/writer.rs)) that processes mutations sequentially via an `mpsc` channel. Additionally, instead of overwriting existing content, the storage layer creates supersession chains in [`crates/ai-memory-store/src/page.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/page.rs), linking new versions to previous ones rather than destroying them. This combination ensures that concurrent edits result in versioned history rather than data loss.

### Can different users work on different projects within the same workspace simultaneously?

Yes. The `ActiveProjectMode::PerActor` implementation in [`crates/ai-memory-core/src/active_project.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-core/src/active_project.rs) maintains separate active-project pointers for each session. When User A sets Project X as active and User B sets Project Y as active, the `ActiveProject` resolver ensures that each subsequent command targets the correct project context without requiring explicit project identifiers in every request.

### What happens to session state if the server restarts?

Session state is transient and tied to the active connection, but persistent user identity and project data remain in the SQLite database. Upon reconnection, clients provide their authentication tokens via [`crates/ai-memory-mcp/src/auth.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-mcp/src/auth.rs), which re-establishes the `User` context. The client must then re-select their active project, as the per-actor pointer is maintained in memory during the session lifetime.

### How are permissions enforced across multi-user access?

The `ScopeResolver` utilities in [`crates/ai-memory-mcp/src/actor.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-mcp/src/actor.rs) validate the `(workspace_id, project_id, path)` triple against the authenticated user's permissions before executing any read or write operation. This check occurs at the actor boundary, ensuring that users cannot access projects or workspaces outside their authorized scope regardless of the request parameters they provide.