What Is the Purpose of the ai-memory-core Crate in the ai-memory Project?
The ai-memory-core crate serves as the domain-model layer of the ai-memory project, providing a stable, I/O-free foundation of core types, identifiers, and utilities that all other crates depend on.
This crate defines the fundamental vocabulary of the system—from workspace and page identifiers to observation kinds and sanitization rules—while enforcing strict architectural boundaries that keep business logic pure and testable. If you're working with the akitaonrails/ai-memory codebase, understanding this crate is essential to navigating its modular architecture.
Core Responsibilities of ai-memory-core
The crate centralizes eight key responsibilities that together form the project's shared language:
| Responsibility | Description |
|---|---|
| Core vocabulary | Defines identifiers (WorkspaceId, ProjectId, PageId), enums (AgentKind, PageKind, ObservationKind), and structs representing system entities |
| Error handling | Provides the unified MemoryError type and MemoryResult alias via src/error.rs |
| Pure-compute constraint | Contains no I/O logic—no file access, network calls, or OS-specific code |
| Sanitization & privacy | Implements Sanitizer and Sanitized<T> types for stripping private data before persistence |
| Page & observation modeling | Supplies Page, NewPage, Observation, NewObservation, and related validation helpers |
| Slot handling | Defines slot utilities (SlotPlacement, is_slot_path) for wiki slot syntax |
| Routing snippets | Provides MARKER_START, MARKER_END, and find_marker_line for embedded code snippets |
| Workstream primitives | Holds data structures for workstream events processed by downstream crates |
This design creates a single source of truth for identifiers and enforces the invariant that core types remain I/O-free, making them trivially unit-testable and safe to use from any context.
Why ai-memory-core Contains No I/O
The module comment in src/lib.rs explicitly documents this architectural decision. By prohibiting file access, network calls, and OS-specific code, the crate achieves:
- Deterministic testing—all functions are pure Rust computations
- Cross-crate safety—downstream crates can depend on core types without pulling in I/O side effects
- Clean architecture boundaries—storage and networking concerns are pushed to dedicated crates like
ai-memory-store
This mirrors patterns found in domain-driven design, where the domain layer remains isolated from infrastructure concerns.
Key Types and Where to Find Them
Identifiers (src/ids.rs)
All system identifiers are centralized in crates/ai-memory-core/src/ids.rs. The PageId type uses UUID v7 for time-sortable identifiers:
use ai_memory_core::ids::PageId;
let page_id = PageId::new(); // Generates UUID v7
Other identifiers include WorkspaceId, ProjectId, AgentId, ThreadId, and EmbeddingId.
Observations (src/observation.rs)
The Observation and NewObservation structs, plus the ObservationKind enum, model user messages, agent responses, and system events:
use ai_memory_core::{ObservationKind, NewObservation};
let obs = NewObservation {
body: "User query here".into(),
kind: ObservationKind::UserMessage,
metadata: None,
};
Sanitization (src/sanitize.rs)
Before observations reach persistent storage, the Sanitizer strips sensitive data:
use ai_memory_core::{Sanitizer, SanitizeConfig, NewObservation};
let config = SanitizeConfig::default();
let sanitizer = Sanitizer::new(config);
let sanitized = sanitizer.sanitize_new_observation(
NewObservation {
body: "password: secret123".into(),
kind: ObservationKind::UserMessage,
..Default::default()
}
).expect("sanitization succeeds");
Routing Snippets (src/routing_snippet.rs)
The routing-skill system embeds code snippets in wiki pages using marker constants:
use ai_memory_core::routing_snippet::{MARKER_START, MARKER_END, find_marker_line};
let content = format!(
"{}\nfn helper() {{}}\n{}",
MARKER_START, MARKER_END
);
The find_marker_line helper locates these markers within page content for extraction.
Error Handling Strategy
Rather than allowing each crate to define its own error types, ai-memory-core provides a unified error system in src/error.rs:
MemoryError—the workspace-wide error enumMemoryResult<T>—type alias forResult<T, MemoryError>
This ensures that errors propagate consistently across crate boundaries without forcing downstream code to handle multiple error representations.
How Other Crates Use ai-memory-core
The crate acts as a dependency root for the workspace. For example:
ai-memory-store—imports core types to implement persistence logicai-memory-wiki—usesPage,SlotPlacement, and routing snippet utilitiesai-memory-workstream—processesWorkstreamEventprimitives defined in coreai-memory-mcp—depends on user models and credentials fromsrc/user.rs
This dependency graph ensures that changes to core types propagate predictably, while the no-I/O guarantee prevents accidental coupling between domain logic and infrastructure.
File Structure Reference
| File Path | Purpose |
|---|---|
crates/ai-memory-core/Cargo.toml |
Crate metadata and public description |
crates/ai-memory-core/src/lib.rs |
Public façade and design documentation |
crates/ai-memory-core/src/ids.rs |
All identifier types (PageId, WorkspaceId, etc.) |
crates/ai-memory-core/src/observation.rs |
Observation payloads and kinds |
crates/ai-memory-core/src/page.rs |
Page model structs and validation |
crates/ai-memory-core/src/sanitize.rs |
Privacy-preserving sanitizer implementation |
crates/ai-memory-core/src/routing_snippet.rs |
Routing marker constants and helpers |
crates/ai-memory-core/src/user.rs |
User accounts and API credentials |
crates/ai-memory-core/src/error.rs |
Unified MemoryError and MemoryResult |
Summary
ai-memory-coreis the domain-model layer of the ai-memory project, providing a stable foundation for all other crates- It enforces zero I/O—all functions are pure computations, making testing trivial and dependencies safe
- It centralizes identifiers, errors, observations, pages, sanitization, routing snippets, and user models
- Downstream crates (
ai-memory-store,ai-memory-wiki, etc.) build on this contract without duplicating type definitions or importing side effects - The design follows domain-driven architecture principles, isolating core vocabulary from infrastructure concerns
Frequently Asked Questions
What makes ai-memory-core different from other crates in the project?
Unlike ai-memory-store (persistence) or ai-memory-wiki (wiki operations), ai-memory-core contains only pure data types and computation. It has no file system access, no database connections, and no network code. This makes it the safest dependency in the workspace—any crate can use it without worrying about side effects or test mocking complexity.
How do I add a new identifier type to the system?
Define it in crates/ai-memory-core/src/ids.rs following the existing pattern. Most identifiers are newtype wrappers around UUIDs with #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] and a new() constructor. Once added, the type becomes available workspace-wide without modifying any other crate.
Why is there a single MemoryError type instead of per-crate errors?
A unified MemoryError in src/error.rs eliminates error conversion boilerplate when crossing crate boundaries. When ai-memory-store returns an error that ai-memory-wiki needs to handle, both speak the same error language. This reduces From implementations and improves debuggability through consistent error formatting.
Can I use ai-memory-core in my own Rust project?
Yes—the crate is pure Rust with no I/O dependencies, making it suitable for any project needing similar domain types. However, it's designed specifically for the ai-memory ecosystem. For external use, you'd likely want to fork and adapt the identifier and observation models to your own domain requirements.
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 →