How to Set Up Per-Operator Memory Slots on Shared Servers
Enable per-operator memory slots in ai-memory by setting per_user = true in the [slots] section of 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 file.
TOML Configuration
Add the following to your configuration file to activate private namespaces:
# 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 (lines 816-822), which passes the value to the server builder in crates/ai-memory-mcp/src/server.rs (lines 443-452) and the CLI serve command in 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 (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) 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 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 module with supporting configuration infrastructure.
Slot Logic in slots.rs
The 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 identityslot_placement(path, identity): ReturnsSlotPlacement::Personal(rewritten_path)when rewriting is required, orSlotPlacement::Sharedfor explicit shared paths
Configuration Propagation
The per_user setting flows through the architecture:
- Config parsing:
crates/ai-memory-cli/src/config.rsdefines theSlotsConfigstruct with theper_userboolean - Server initialization:
crates/ai-memory-mcp/src/server.rsreceives the flag and stores it in the server state - Request handling: Handlers check the flag to instantiate correct visibility rules for each operation
Practical Implementation Examples
Automatic Namespace Rewriting
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
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
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 = truein the[slots]section ofai-memory.toml - Private namespaces follow the pattern
_slots/u-{username}/and are created automatically - Visibility rules in
SlotVisibility::for_viewerrestrict operators to shared slots and their own namespace - Write redirection via
slot_placementprevents 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 from different operators create separate files: _slots/u-alice/example.md and _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 handles the identity extraction and passes it to the visibility checking logic.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →