pub struct Vein { /* private fields */ }Expand description
“The Vein” — local RAG memory engine backed by SQLite FTS5 + semantic embeddings.
Two retrieval modes, used together:
BM25 (always available) Full-text search via SQLite FTS5 with Porter-stemming. Fast, zero extra GPU cost, works as the fallback when the embedding model isn’t loaded.
Semantic (when LM Studio has an embedding model loaded)
Calls /v1/embeddings (nomic-embed-text-v1.5 or similar) to produce 768-dim float
vectors for each chunk. At search time the query is embedded and cosine similarity
selects the most conceptually relevant chunks — even when no keywords match.
Hybrid search runs BM25 and semantic in parallel, deduplicates by path, and returns the top-k results ranked by combined score. Semantic results score higher when the embedding model is available; BM25 fills the gap when it isn’t.
Indexing is incremental: files are re-indexed only when their mtime changes. Embedding
vectors are stored in a separate chunks_vec SQLite table so they survive re-runs
without hitting the embedding API again.
Implementations§
Source§impl Vein
impl Vein
pub fn new<P: AsRef<Path>>( db_path: P, base_url: String, ) -> Result<Self, Box<dyn Error>>
Sourcepub fn index_document(
&mut self,
path: &str,
last_modified: i64,
full_text: &str,
) -> Result<Vec<String>, Box<dyn Error>>
pub fn index_document( &mut self, path: &str, last_modified: i64, full_text: &str, ) -> Result<Vec<String>, Box<dyn Error>>
Index a single file for BM25 search. Skip if mtime hasn’t changed. Returns the chunks that were written (empty if file was unchanged).
Sourcepub fn embed_and_store_chunks(&self, path: &str, chunks: &[String])
pub fn embed_and_store_chunks(&self, path: &str, chunks: &[String])
Embed a set of chunks for one file and store the vectors.
Called after index_document returns new chunks.
Silently skips if the embedding model is unavailable.
Sourcepub fn search_bm25(
&self,
query: &str,
limit: usize,
) -> Result<Vec<SearchResult>, Box<dyn Error>>
pub fn search_bm25( &self, query: &str, limit: usize, ) -> Result<Vec<SearchResult>, Box<dyn Error>>
BM25-ranked full-text search via FTS5 MATCH.
Sourcepub fn search_semantic(&self, query: &str, limit: usize) -> Vec<SearchResult>
pub fn search_semantic(&self, query: &str, limit: usize) -> Vec<SearchResult>
Semantic search: embed the query, cosine-similarity against all stored vectors. Returns empty if the embedding model isn’t loaded.
Sourcepub fn search_context(
&self,
query: &str,
limit: usize,
) -> Result<Vec<SearchResult>, Box<dyn Error>>
pub fn search_context( &self, query: &str, limit: usize, ) -> Result<Vec<SearchResult>, Box<dyn Error>>
Hybrid search: BM25 + semantic, deduplicated and re-ranked.
Semantic results are preferred (they score higher) when the embedding model is available. BM25 fills in or takes over when it isn’t. Results from the active room (hottest subsystem by edit count) get a small boost so the model gravitates toward what’s currently being worked on.
Sourcepub fn index_project(&mut self) -> usize
pub fn index_project(&mut self) -> usize
Walk the entire project and index all source files (BM25 + embeddings).
Skips: target/, .git/, node_modules/, .hematite/, files > 512 KB.
Also indexes .hematite/docs/ — the designated reference document drop folder.
Returns the number of files processed (unchanged files are fast-pathed).
Sourcepub fn index_workspace_artifacts(&mut self, workspace_root: &Path) -> usize
pub fn index_workspace_artifacts(&mut self, workspace_root: &Path) -> usize
Index workspace-local supporting context that should be available even
outside a real project workspace: .hematite/docs/, recent session
reports stored in .hematite/reports/, and imported chat exports in
.hematite/imports/.
Sourcepub fn index_recent_session_reports(&mut self, workspace_root: &Path) -> usize
pub fn index_recent_session_reports(&mut self, workspace_root: &Path) -> usize
Index the most recent local session reports by exchange pair so prior decisions remain searchable across launches without flooding the vein.
Sourcepub fn index_imported_session_exports(&mut self, workspace_root: &Path) -> usize
pub fn index_imported_session_exports(&mut self, workspace_root: &Path) -> usize
Index imported chat exports from .hematite/imports/.
Supported inputs include already-normalized > transcripts, Claude Code
JSONL, Codex CLI JSONL, simple role/content JSON exports, ChatGPT
mapping exports, and Hematite session-report JSON.
Sourcepub fn file_count(&self) -> usize
pub fn file_count(&self) -> usize
Total number of unique files currently indexed. Session exchange chunks are excluded so status counts stay source/doc centric.
Sourcepub fn embedded_chunk_count(&self) -> usize
pub fn embedded_chunk_count(&self) -> usize
Number of source/doc chunks that have semantic embedding vectors stored. Session exchange chunks are excluded so status counts stay source/doc centric.
Sourcepub fn has_any_embeddings(&self) -> bool
pub fn has_any_embeddings(&self) -> bool
True when any chunk type currently has embeddings available.
Sourcepub fn reset(&self)
pub fn reset(&self)
Wipe all indexed data. The DB file stays on disk; next index_project() call rebuilds from scratch (re-reads all files, re-embeds all chunks).
Sourcepub fn inspect_snapshot(&self, hot_limit: usize) -> VeinInspectionSnapshot
pub fn inspect_snapshot(&self, hot_limit: usize) -> VeinInspectionSnapshot
Return a compact operator-facing snapshot of what The Vein currently knows.
Intended for trust/debug surfaces like /vein-inspect.
Sourcepub fn bump_heat(&self, path: &str)
pub fn bump_heat(&self, path: &str)
Record an edit to a file. Increments its heat score in file_heat. Called from the tool dispatch after a successful edit_file / write_file / patch_hunk / multi_search_replace so the L1 context stays current.
Sourcepub fn hot_file_paths(&self, n: usize) -> Vec<String>
pub fn hot_file_paths(&self, n: usize) -> Vec<String>
Return the paths of the top hot files (most edited). Used by RepoMapGenerator to bias PageRank toward active files.
Sourcepub fn hot_files_weighted(&self, n: usize) -> Vec<(String, f64)>
pub fn hot_files_weighted(&self, n: usize) -> Vec<(String, f64)>
Return hot files with normalized heat weights in [0.0, 1.0]. The hottest file gets weight 1.0; others are scaled proportionally. Used by RepoMapGenerator to apply heat-weighted PageRank personalization.
Sourcepub fn l1_context(&self) -> Option<String>
pub fn l1_context(&self) -> Option<String>
Build the L1 context block — a compact “hot files” summary injected into the system prompt at session start. Capped at ~150 tokens. Files are grouped by room so the model sees subsystem structure at a glance. Returns None when there are no heat records yet (fresh project).
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Vein
impl RefUnwindSafe for Vein
impl Unpin for Vein
impl UnsafeUnpin for Vein
impl UnwindSafe for Vein
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<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
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