pub struct MemoryStore { /* private fields */ }Expand description
The main memory store — manages agent-level markdown files with a hybrid search index.
Blueprint-managed files (SOUL.md, lifecycle files) live in config_dir
(.starpod/config/). Runtime data files (daily logs, agent-written files)
live in agent_home (.starpod/).
The FTS5/vector database lives in db_dir (.starpod/db/).
User-specific files (USER.md, MEMORY.md, daily logs) are handled by
UserMemoryView, not this struct.
§Search Pipeline
search— FTS5 + temporal decay (always available)vector_search— cosine similarity (requires embedder)hybrid_search— FTS5 + vector → RRF fusion → decay → MMR
§Security
All file read/write operations validate paths via scoring::validate_path
to prevent directory traversal. Writes are capped at 1 MB.
Implementations§
Source§impl MemoryStore
impl MemoryStore
Sourcepub async fn new(
agent_home: &Path,
config_dir: &Path,
db_dir: &Path,
) -> Result<Self>
pub async fn new( agent_home: &Path, config_dir: &Path, db_dir: &Path, ) -> Result<Self>
Create a new MemoryStore.
agent_home: the.starpod/directory (runtime data, general read/write)config_dir: the.starpod/config/directory (SOUL.md, lifecycle files)db_dir: the.starpod/db/directory (contains memory.db)
Sourcepub async fn new_user(user_dir: &Path) -> Result<Self>
pub async fn new_user(user_dir: &Path) -> Result<Self>
Create a lightweight per-user memory store.
Uses user_dir for both file storage and the SQLite database
(user_dir/memory.db). Skips seeding default lifecycle files
(SOUL.md, HEARTBEAT.md, etc.) since those belong to the agent-level store.
The store has max_connections(1) to keep resource usage low when
many users each get their own store.
Any existing .md files in user_dir are indexed on creation.
Sourcepub fn agent_home(&self) -> &Path
pub fn agent_home(&self) -> &Path
Get the agent home directory path (.starpod/).
Sourcepub fn config_dir(&self) -> &Path
pub fn config_dir(&self) -> &Path
Get the config directory path (.starpod/config/).
Sourcepub fn has_bootstrap(&self) -> bool
pub fn has_bootstrap(&self) -> bool
Returns true if BOOTSTRAP.md exists and has non-empty content.
Sourcepub fn clear_bootstrap(&self) -> Result<()>
pub fn clear_bootstrap(&self) -> Result<()>
Delete BOOTSTRAP.md (called after successful bootstrap execution).
Sourcepub fn bootstrap_context(&self) -> Result<String>
pub fn bootstrap_context(&self) -> Result<String>
Build agent-level bootstrap context from SOUL.md only.
User-specific context (USER.md, MEMORY.md, daily logs) is handled by
UserMemoryView::bootstrap_context().
Sourcepub fn set_half_life_days(&mut self, days: f64)
pub fn set_half_life_days(&mut self, days: f64)
Set the half-life for temporal decay on search results.
Sourcepub fn set_mmr_lambda(&mut self, lambda: f64)
pub fn set_mmr_lambda(&mut self, lambda: f64)
Set the MMR lambda for diversity vs relevance balance.
Sourcepub fn set_chunk_size(&mut self, size: usize)
pub fn set_chunk_size(&mut self, size: usize)
Set the target chunk size in characters for indexing.
Sourcepub fn set_chunk_overlap(&mut self, overlap: usize)
pub fn set_chunk_overlap(&mut self, overlap: usize)
Set the overlap in characters between chunks.
Sourcepub fn set_bootstrap_file_cap(&mut self, cap: usize)
pub fn set_bootstrap_file_cap(&mut self, cap: usize)
Set the maximum characters to include from a single file in bootstrap context.
Sourcepub async fn search(
&self,
query: &str,
limit: usize,
) -> Result<Vec<SearchResult>>
pub async fn search( &self, query: &str, limit: usize, ) -> Result<Vec<SearchResult>>
Full-text search across all indexed content.
Results are re-ranked with temporal decay: recent daily logs score higher than older ones, while evergreen files (SOUL.md, HEARTBEAT.md) are unaffected.
Sourcepub fn set_embedder(&mut self, embedder: Arc<dyn Embedder>)
pub fn set_embedder(&mut self, embedder: Arc<dyn Embedder>)
Set the embedder for vector search.
Sourcepub async fn vector_search(
&self,
query: &str,
limit: usize,
) -> Result<Vec<SearchResult>>
pub async fn vector_search( &self, query: &str, limit: usize, ) -> Result<Vec<SearchResult>>
Vector search: embed the query, compare against stored vectors, return top-K.
Returns empty vec if no embedder is configured.
Sourcepub async fn hybrid_search(
&self,
query: &str,
limit: usize,
) -> Result<Vec<SearchResult>>
pub async fn hybrid_search( &self, query: &str, limit: usize, ) -> Result<Vec<SearchResult>>
Hybrid search: run FTS5 + vector search, fuse with RRF, apply MMR.
Falls back to FTS5-only when no embedder is configured. Pipeline: FTS5 + vector → RRF fusion → temporal decay → MMR diversity.
Sourcepub fn read_file(&self, name: &str) -> Result<String>
pub fn read_file(&self, name: &str) -> Result<String>
Read a file from the appropriate directory (config_dir for config files, agent_home otherwise).
Sourcepub async fn write_file(&self, name: &str, content: &str) -> Result<()>
pub async fn write_file(&self, name: &str, content: &str) -> Result<()>
Write a file and reindex it.
Config files (SOUL.md, lifecycle files) are written to config_dir, everything else to agent_home.
Sourcepub async fn append_daily(&self, text: &str) -> Result<()>
pub async fn append_daily(&self, text: &str) -> Result<()>
Append a timestamped entry to today’s daily log.
Auto Trait Implementations§
impl Freeze for MemoryStore
impl !RefUnwindSafe for MemoryStore
impl Send for MemoryStore
impl Sync for MemoryStore
impl Unpin for MemoryStore
impl UnsafeUnpin for MemoryStore
impl !UnwindSafe for MemoryStore
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more