pub struct KnowledgeBase { /* private fields */ }Expand description
Markdown knowledge base application layer.
Wraps VirtualFs for sandboxed file I/O, BacklinkIndex for
link tracking, and provides all app-layer features (chat, journal,
habits, checklist, etc.).
No kernel dependencies. Can be used standalone by any channel.
Implementations§
Source§impl KnowledgeBase
impl KnowledgeBase
Sourcepub fn new(root: PathBuf) -> Result<Self>
pub fn new(root: PathBuf) -> Result<Self>
Create a new KnowledgeBase for the given root directory.
Sourcepub fn for_space(space_dir: &Path) -> Result<Self>
pub fn for_space(space_dir: &Path) -> Result<Self>
Create a new KnowledgeBase scoped to a Space’s subdirectory.
Sourcepub fn on_file_change<F>(&self, f: F)
pub fn on_file_change<F>(&self, f: F)
Register a callback to be invoked on every file change.
The callback receives (path, FileChange).
Multiple callbacks can be registered.
Sourcepub fn note_read_bytes(&self, path: &str) -> Result<Option<Vec<u8>>>
pub fn note_read_bytes(&self, path: &str) -> Result<Option<Vec<u8>>>
Read a note’s raw bytes — for binary assets (images, etc.) that aren’t
valid UTF-8. Text notes should use [note_read].
Sourcepub fn note_write(&self, path: &str, content: &str) -> Result<()>
pub fn note_write(&self, path: &str, content: &str) -> Result<()>
Write a note — creates or overwrites.
Routes through crate::frontformat::write_note so memo paths
carry a canonical oxios: frontmatter block (id/created/updated)
while system paths (Chat.md, journal/, etc.) stay raw.
No-op precedence (§5.3.2): when frontformat::write_note
returns WriteOutcome::NoOp — meaning the merged memo is
semantically identical to the on-disk file, OR the system-path
bytes already match — we return Ok(()) before reindexing
backlinks or firing on_file_change callbacks. The invariant:
no pointless churn.
Sourcepub fn note_write_with_meta(
&self,
path: &str,
content: &str,
meta: &NoteMeta,
) -> Result<bool>
pub fn note_write_with_meta( &self, path: &str, content: &str, meta: &NoteMeta, ) -> Result<bool>
Write a note with provenance metadata (RFC-022).
Merges the provided NoteMeta into the file’s oxios:
table (synthesizing id/created/updated on a fresh memo;
preserving id/created across a re-write) via
crate::frontformat::with_oxios_table, then delegates to
Self::note_write.
User-authored refusal: if the file already exists and its
frontmatter block contains no oxios: table — i.e., the
frontmatter is user-authored (Obsidian tags, custom keys) —
we return Ok(false) and leave the file untouched. The brief
§5.3.2 specifies that user-authored frontmatter is sacred; an
agent metadata write must never overwrite it.
Sourcepub fn notes_needing_review(&self) -> Result<Vec<(String, NoteMeta)>>
pub fn notes_needing_review(&self) -> Result<Vec<(String, NoteMeta)>>
List notes that need Dream review (RFC-022).
Scans the vault for .md files with needs_review: true in
their oxios: frontmatter. Routes through
crate::frontformat::read_note_meta so the frontmatter
grammar is the v4 / oxi-frontmatter v0.1 contract, not the
bespoke parser that lived in this module before T12.
Sourcepub fn note_delete(&self, path: &str) -> Result<()>
pub fn note_delete(&self, path: &str) -> Result<()>
Delete the note at path, removing it from the filesystem and
dropping any recorded backlinks for that file.
Sourcepub fn note_restore(&self, path: &str, content: &str) -> Result<()>
pub fn note_restore(&self, path: &str, content: &str) -> Result<()>
Restore a note’s content without triggering file-change callbacks.
Used when reverting to a previous git version — writes the file
through crate::frontformat::write_note (so pre-migration
blobs gain synthesized id/created/updated while keeping their
oxios: row and editor-supplied keys), updates the backlink
index, but does not fire on_file_change callbacks. This
prevents an infinite loop where restore → write → callback →
git commit → … repeats.
Sourcepub fn note_move(&self, old_path: &str, new_path: &str) -> Result<()>
pub fn note_move(&self, old_path: &str, new_path: &str) -> Result<()>
Move/rename a note.
In addition to the filesystem rename and backlink reindex, this
rewrites every [text](old_path)] reference in other notes
(and any self-reference in the moved note) to point at new_path,
AND every [[target]] wikilink that resolves to old_path (with
ambiguity guard for bare stems). Without this, renaming a note
that other notes link to would silently orphan those links — a
latent bug that affected both the F2 sidebar rename and the
H1-driven rename.
Sourcepub fn list_all_md_files(&self) -> Result<Vec<(String, i64)>>
pub fn list_all_md_files(&self) -> Result<Vec<(String, i64)>>
List all markdown files in the knowledge base (path, size). Used by startup git reconciliation to detect post-crash drift.
Sourcepub fn search(&self, query: &str, limit: usize) -> Result<Vec<NoteHit>>
pub fn search(&self, query: &str, limit: usize) -> Result<Vec<NoteHit>>
Search notes by file name fuzzy matching.
Note: Semantic search is handled by KnowledgeLens,
not by this method.
Sourcepub fn backlinks_for(&self, path: &str) -> Vec<Backlink>
pub fn backlinks_for(&self, path: &str) -> Vec<Backlink>
Get backlinks for a note.
Sourcepub fn link_graph(&self) -> LinkGraph
pub fn link_graph(&self) -> LinkGraph
Get the full link graph for visualization.
Sourcepub fn index_all(&self) -> Result<usize>
pub fn index_all(&self) -> Result<usize>
Index all markdown files in the knowledge base.
Walks the entire directory tree (at any depth) and builds the backlink index, including wikilink targets resolved against a stem index built from the same walk. Returns the number of files indexed.
Sourcepub fn reindex_one(&self, path: &str) -> Result<()>
pub fn reindex_one(&self, path: &str) -> Result<()>
Reindex a single note after an external change (vault watcher).
Extracted from KnowledgeBase::index_all internals: rebuilds
the stem index (so wikilinks resolve against the current file
set), then runs the single-file backlink indexing pass
(remove_file + index_file_with, which replaces the file’s
previous links instead of accumulating them). The file is only
read, never written. Fails if the file cannot be read.
Sourcepub fn forget_file(&self, path: &str)
pub fn forget_file(&self, path: &str)
Drop a note from the index after an external deletion (vault watcher). Does not touch the filesystem.
Sourcepub fn chat_append(&self, message: &str) -> Result<()>
pub fn chat_append(&self, message: &str) -> Result<()>
Append a timestamped message to Chat.md.
Sourcepub fn chat_messages(&self) -> Result<Vec<String>>
pub fn chat_messages(&self) -> Result<Vec<String>>
Parse Chat.md into structured message blocks.
Sourcepub fn chat_delete(&self, msg_hash: &str) -> Result<bool>
pub fn chat_delete(&self, msg_hash: &str) -> Result<bool>
Delete a specific chat message by its content hash.
Sourcepub fn chat_rename(&self, msg_hash: &str, new_body: &str) -> Result<bool>
pub fn chat_rename(&self, msg_hash: &str, new_body: &str) -> Result<bool>
Rename a specific chat message by its content hash.
Sourcepub fn chat_move_to(&self, msg_hash: &str, target_path: &str) -> Result<bool>
pub fn chat_move_to(&self, msg_hash: &str, target_path: &str) -> Result<bool>
Move a chat message to a target file as a checklist item.
Sourcepub fn journal_add_record(&self, record: &str) -> Result<()>
pub fn journal_add_record(&self, record: &str) -> Result<()>
Add a timestamped record to today’s journal entry.
Sourcepub fn journal_add_emoji(&self, emoji: &str) -> Result<()>
pub fn journal_add_emoji(&self, emoji: &str) -> Result<()>
Add an emoji to today’s journal header.
Sourcepub fn journal_today_path(&self) -> String
pub fn journal_today_path(&self) -> String
Get today’s journal file path (e.g., “journal/2026.05 May.md”).
Sourcepub fn habits_last_week(&self) -> Result<Habits>
pub fn habits_last_week(&self) -> Result<Habits>
Get last week’s habit data.
Sourcepub fn habits_write(&self, year: i32, habits: &Habits) -> Result<()>
pub fn habits_write(&self, year: i32, habits: &Habits) -> Result<()>
Write habit data for a year.
Sourcepub fn config(&self) -> Result<KnowledgeConfig>
pub fn config(&self) -> Result<KnowledgeConfig>
Read the knowledge base config (config.json).
Sourcepub fn set_config(&self, config: &KnowledgeConfig) -> Result<()>
pub fn set_config(&self, config: &KnowledgeConfig) -> Result<()>
Write the knowledge base config.
Sourcepub fn checklist_items(
&self,
path: &str,
) -> Result<(Vec<String>, HashMap<String, bool>)>
pub fn checklist_items( &self, path: &str, ) -> Result<(Vec<String>, HashMap<String, bool>)>
Parse checklist items from a file.
Sourcepub fn checklist_incomplete(&self, path: &str) -> Result<Vec<String>>
pub fn checklist_incomplete(&self, path: &str) -> Result<Vec<String>>
Get incomplete checklist items from a file.
Sourcepub fn checklist_add(&self, path: &str, item: &str, checked: bool) -> Result<()>
pub fn checklist_add(&self, path: &str, item: &str, checked: bool) -> Result<()>
Add a checklist item to a file.
Sourcepub fn checklist_complete(&self, path: &str, item_hash: &str) -> Result<bool>
pub fn checklist_complete(&self, path: &str, item_hash: &str) -> Result<bool>
Complete a checklist item by hash.
Sourcepub fn checklist_remove(&self, path: &str, item_or_hash: &str) -> Result<bool>
pub fn checklist_remove(&self, path: &str, item_or_hash: &str) -> Result<bool>
Remove a checklist item by text or hash.
Sourcepub fn checklist_remove_completed(&self, path: &str) -> Result<(String, String)>
pub fn checklist_remove_completed(&self, path: &str) -> Result<(String, String)>
Remove all completed checklist items.
Sourcepub fn run_nightly_cleanup(&self) -> Result<NightlyReport>
pub fn run_nightly_cleanup(&self) -> Result<NightlyReport>
Run nightly cleanup.
Sourcepub fn run_scheduled_tasks(&self) -> Result<Vec<String>>
pub fn run_scheduled_tasks(&self) -> Result<Vec<String>>
Move due scheduled tasks to Chat.
Sourcepub fn today_report(&self) -> Result<TodayReport>
pub fn today_report(&self) -> Result<TodayReport>
Get today’s completion report.
Sourcepub fn done_today(&self) -> Result<Vec<FileEntry>>
pub fn done_today(&self) -> Result<Vec<FileEntry>>
Get list of files completed today.
Sourcepub fn markdown_to_html(&self, md: &str) -> String
pub fn markdown_to_html(&self, md: &str) -> String
Convert markdown to HTML.
Sourcepub fn auto_emoji(&self, text: &str) -> String
pub fn auto_emoji(&self, text: &str) -> String
Find an emoji for a keyword.
Sourcepub fn world_clock(&self, timezone_names: &[&str]) -> Vec<TimezoneEntry>
pub fn world_clock(&self, timezone_names: &[&str]) -> Vec<TimezoneEntry>
Generate world clock report for given timezone names.
Sourcepub fn mark_agent_write(&self, path: &str)
pub fn mark_agent_write(&self, path: &str)
Mark a file as having been written by an agent.
Sourcepub fn is_agent_write(&self, path: &str) -> bool
pub fn is_agent_write(&self, path: &str) -> bool
Check if a file was written by an agent.
Sourcepub fn clear_agent_write(&self, path: &str)
pub fn clear_agent_write(&self, path: &str)
Clear the agent-write marker for a file.
Sourcepub fn extract_text_imgs_links(&self, text: &str) -> ExtractResult
pub fn extract_text_imgs_links(&self, text: &str) -> ExtractResult
Extract text, images, and links from markdown content.
Sourcepub fn extract_headings(&self, content: &str) -> Vec<String>
pub fn extract_headings(&self, content: &str) -> Vec<String>
Extract headings from content for tag generation.
Source§impl KnowledgeBase
impl KnowledgeBase
Sourcepub fn watch(self: &Arc<Self>, settle: Duration) -> Result<WatchGuard>
pub fn watch(self: &Arc<Self>, settle: Duration) -> Result<WatchGuard>
Watch the vault root for external changes and reindex settled notes.
settle is the debounce window, parameterizable per caller: a
path is processed only after no further events have been
observed for it within the window (editors emit bursts of
create/write/rename events per save). A settled path that exists
is re-read into the backlink index and reported as
FileChange::Updated; a settled path that is gone is dropped
from the index and reported as FileChange::Deleted.
Self-writes by oxios itself also surface here and re-fire callbacks; that double-fire is tolerated at debug level and absorbed by downstream dedup (I-3).
The returned WatchGuard keeps the watcher alive. This takes
&Arc<Self> because the debounce thread owns a clone for the
lifetime of the watch.