# How to Set Up Per-Operator Memory Slots on Shared Servers

> Learn how to set up per operator memory slots on shared servers with ai-memory. Enable private namespaces for each operator while maintaining shared access to common slots.

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

---

**Enable per-operator memory slots in ai-memory by setting `per_user = true` in the `[slots]` section of [`ai-memory.toml`](https://github.com/akitaonrails/ai-memory/blob/main/ai-memory.toml), which automatically isolates each operator into private namespaces while preserving shared access to common slots.**

The `ai-memory` system manages temporary working-context pages under the `_slots/` namespace. On shared servers, operators typically see identical slot contents, but the per-operator memory slots feature creates isolated environments for each user. This configuration ensures sensitive working contexts remain private while allowing collaboration through explicitly shared slots.

## Configuration Setup

Enabling per-operator isolation requires a single configuration change in your [`ai-memory.toml`](https://github.com/akitaonrails/ai-memory/blob/main/ai-memory.toml) file.

### TOML Configuration

Add the following to your configuration file to activate private namespaces:

```toml

# ai-memory.toml

[slots]
per_user = true

```

This boolean flag propagates through the system via the `per_user_slots` parameter. The configuration definition resides in [`crates/ai-memory-cli/src/config.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/config.rs) (lines 816-822), which passes the value to the server builder in [`crates/ai-memory-mcp/src/server.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-mcp/src/server.rs) (lines 443-452) and the CLI serve command in [`crates/ai-memory-cli/src/commands/serve.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/commands/serve.rs) (lines 535-542).

## How Per-Operator Slots Work

When `per_user = true` is active, the system modifies slot visibility and write behavior across three dimensions:

### Namespace Isolation and Visibility

The `SlotVisibility::for_viewer` function in [`crates/ai-memory-core/src/slots.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-core/src/slots.rs) (lines 88-101) implements the access control logic. Each operator sees only:
- Shared slots in the root `_slots/` directory
- Their own private namespace (e.g., `_slots/u-alice/`)

Other operators' private namespaces remain hidden. The visibility check determines whether a specific slot path is accessible to the requesting identity.

### Automatic Write Placement

The `slot_placement` function (lines 64-91 in [`slots.rs`](https://github.com/akitaonrails/ai-memory/blob/main/slots.rs)) automatically rewrites slot paths for writes. When an operator writes to a slot without specifying an explicit namespace, the system redirects the write to their personal namespace using `SlotPlacement::Personal`.

For example, writing to [`_slots/current-focus.md`](https://github.com/akitaonrails/ai-memory/blob/main/_slots/current-focus.md) as user "alice" automatically stores the content at `_slots/u-alice/current-focus.md". This prevents operators from accidentally overwriting shared slots or each other's data.

### Handling Unattributed Requests

Requests lacking identity credentials operate in a restricted mode. These unattributed requests can only read shared slots and cannot write to any personal namespace. This ensures system security when identity information is unavailable.

## Core Implementation Details

The slot isolation logic centers on the [`slots.rs`](https://github.com/akitaonrails/ai-memory/blob/main/slots.rs) module with supporting configuration infrastructure.

### Slot Logic in slots.rs

The [`crates/ai-memory-core/src/slots.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-core/src/slots.rs) file contains the fundamental algorithms:

- **`SlotVisibility::for_viewer(per_user_slots, identity)`**: Determines which namespaces are visible based on the feature flag and operator identity
- **`slot_placement(path, identity)`**: Returns `SlotPlacement::Personal(rewritten_path)` when rewriting is required, or `SlotPlacement::Shared` for explicit shared paths

### Configuration Propagation

The `per_user` setting flows through the architecture:

1. **Config parsing**: [`crates/ai-memory-cli/src/config.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/config.rs) defines the `SlotsConfig` struct with the `per_user` boolean
2. **Server initialization**: [`crates/ai-memory-mcp/src/server.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-mcp/src/server.rs) receives the flag and stores it in the server state
3. **Request handling**: Handlers check the flag to instantiate correct visibility rules for each operation

## Practical Implementation Examples

### Automatic Namespace Rewriting

```rust
use ai_memory_core::{IdentityKey, SlotPlacement};

let alice = IdentityKey::User("alice".into());
let path = "_slots/current-focus.md";

// Writing without namespace automatically uses Alice's private space
match ai_memory_core::slot_placement(path, Some(&alice)) {
    SlotPlacement::Personal(p) => println!("Stored at {p}"),
    _ => println!("No rewrite needed"),
}
// Output: Stored at _slots/u-alice/current-focus.md

```

### Visibility Checking in Request Handlers

```rust
async fn get_slot(
    state: &State,               // contains per_user_slots flag
    viewer: Option<&IdentityKey>,
    slot_path: &str,
) -> Result<String, anyhow::Error> {
    let visibility = ai_memory_core::SlotVisibility::for_viewer(
        state.per_user_slots, 
        viewer
    );
    
    if !visibility.allows(slot_path) {
        return Err(anyhow::anyhow!("Forbidden"));
    }
    
    // Fetch content from store...
    Ok(content)
}

```

### Visibility Rules Verification

```rust
use ai_memory_core::SlotVisibility;

let alice = IdentityKey::User("alice".into());
let vis = SlotVisibility::for_viewer(true, Some(&alice));

assert!(vis.allows("_slots/current-focus.md"));          // shared slot
assert!(vis.allows("_slots/u-alice/current-focus.md"));  // own slot
assert!(!vis.allows("_slots/u-bob/current-focus.md"));   // other user's slot

```

## Summary

- **Enable isolation** by setting `per_user = true` in the `[slots]` section of [`ai-memory.toml`](https://github.com/akitaonrails/ai-memory/blob/main/ai-memory.toml)
- **Private namespaces** follow the pattern `_slots/u-{username}/` and are created automatically
- **Visibility rules** in `SlotVisibility::for_viewer` restrict operators to shared slots and their own namespace
- **Write redirection** via `slot_placement` prevents accidental overwrites of shared data by routing unattributed writes to personal namespaces
- **Unattributed requests** operate in read-only mode for shared slots only, ensuring security boundaries

## Frequently Asked Questions

### How do I migrate from shared slots to per-operator slots without losing data?

Existing shared slots remain accessible at their original paths after enabling `per_user = true`. Only new writes without explicit namespaces get redirected to personal spaces. To preserve collaborative data, keep shared slots in the root `_slots/` directory and train operators to use explicit paths for shared resources.

### Can operators still share slots when per-user mode is enabled?

Yes. Explicit paths to shared slots (those not prefixed with `u-{username}/`) remain visible to all operators. The system only restricts visibility of personal namespaces (`_slots/u-*/`). Operators can collaborate by writing to specific shared paths or reading from common slots in the root namespace.

### What happens if two operators write to the same slot name simultaneously?

When `per_user = true` is active, writes to [`_slots/example.md`](https://github.com/akitaonrails/ai-memory/blob/main/_slots/example.md) from different operators create separate files: [`_slots/u-alice/example.md`](https://github.com/akitaonrails/ai-memory/blob/main/_slots/u-alice/example.md) and [`_slots/u-bob/example.md`](https://github.com/akitaonrails/ai-memory/blob/main/_slots/u-bob/example.md). No collision occurs because the `slot_placement` function automatically prepends the operator's namespace. To create truly shared content, operators must explicitly reference the shared path.

### How does the system handle authentication for slot operations?

The `IdentityKey` struct identifies operators, typically extracted from request headers or session tokens. If no identity is present (unattributed requests), `SlotVisibility::for_viewer` returns restricted visibility showing only shared slots, and write operations are blocked from creating personal namespaces. The server implementation in [`crates/ai-memory-mcp/src/server.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-mcp/src/server.rs) handles the identity extraction and passes it to the visibility checking logic.