This document provides a detailed technical explanation of how the Obsidian Vault Query Tool works, its architecture, and the concepts behind it.
The tool is built using a modular architecture with clear separation of concerns:
-
🔵 Core Components (
src/veruca/core/)- Base classes and interfaces
- Common utilities
- Embedding functionality
-
🟢 Data Sources (
src/veruca/sources/)- Obsidian integration
- Extensible for other sources
-
🟡 Document Processing (
src/veruca/sources/obsidian/parser.py) -
🟣 Query Handling (
src/veruca/sources/obsidian/query.py) -
🔴 Vector Storage and Search (
src/veruca/core/embeddings.py)
Here's how these components work together:
graph TD
A[Markdown Files] --> B[Document Processing]
B --> C[Text Chunking]
C --> D[Embedding Generation]
D --> E[Vector Storage]
F[User Query] --> G[Query Processing]
G --> H[Vector Search]
H --> I[Response Generation]
E --> H
style A fill:#2196f3,stroke:#333,stroke-width:2px,color:#fff
style B fill:#ffeb3b,stroke:#333,stroke-width:2px,color:#000
style C fill:#ffeb3b,stroke:#333,stroke-width:2px,color:#000
style D fill:#f44336,stroke:#333,stroke-width:2px,color:#fff
style E fill:#f44336,stroke:#333,stroke-width:2px,color:#fff
style F fill:#9c27b0,stroke:#333,stroke-width:2px,color:#fff
style G fill:#9c27b0,stroke:#333,stroke-width:2px,color:#fff
style H fill:#f44336,stroke:#333,stroke-width:2px,color:#fff
style I fill:#9c27b0,stroke:#333,stroke-width:2px,color:#fff
class DataSource(ABC):
"""Abstract base class for data sources."""- Defines interface for data sources
- Ensures consistent behavior
- Enables easy extension
class EmbeddingGenerator:
"""Handles embedding generation and vector operations."""- Manages embedding models
- Handles vector operations
- Provides common functionality
def load_markdown_files(vault_path: str) -> List[Tuple[str, Dict[str, Any], str]]:
"""Load all Markdown files from the given vault path with Obsidian-specific processing."""- Recursively scans the Obsidian vault for
.mdfiles - Handles file encoding and error cases
- Preserves file structure and relationships
The tool processes several Obsidian-specific features in separate functions:
def parse_frontmatter(content: str) -> Tuple[Dict[str, Any], str]:
"""Parse Obsidian's YAML frontmatter if present."""- Uses regex to identify YAML frontmatter
- Parses using PyYAML library
- Stores as metadata for each document
def extract_tags(content: str) -> List[str]:
"""Extract Obsidian tags from content."""- Uses regex
#(\w+)to find tags - Stores as metadata for filtering and organization
def process_obsidian_links(content: str, vault_path: str) -> str:
"""Process Obsidian's internal links and convert them to readable text."""- Converts to readable text
- Preserves display text when available
- Maintains document relationships
def process_callouts(content: str) -> str:
"""Process Obsidian's callouts (admonitions) to make them more readable."""- Converts to readable format
- Preserves callout type and content
The tool uses LangChain's RecursiveCharacterTextSplitter in index_vault():
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # Number of characters per chunk
chunk_overlap=50 # Number of characters to overlap between chunks
)Benefits:
- Maintains context across chunk boundaries
- Optimizes for embedding model input size
- Preserves document structure
Uses Ollama's nomic-embed-text model in both indexing and querying:
embedding_model = OllamaEmbeddings(model="nomic-embed-text")Key features:
- Local processing (no API calls)
- High-quality embeddings
- Fast processing
Uses ChromaDB for vector storage and retrieval in index_vault():
vector_store = Chroma.from_documents(
documents,
embedding=embedding_model,
persist_directory=CHROMA_DB_PATH
)Features:
- Persistent storage
- Efficient similarity search
- Metadata filtering
def query_vault(question: str, filter_tags: List[str] = None) -> None:
"""Query the indexed data with a question and optional tag filtering."""- User submits query
- Query is embedded using same model
- Similarity search performed
- Relevant documents retrieved
- Response generated
if filter_tags:
search_kwargs["filter"] = {"tags": {"$in": filter_tags}}- Filters results by specified tags
- Uses ChromaDB's metadata filtering
- Supports multiple tags
retriever = vector_store.as_retriever(
search_type="similarity_score_threshold",
search_kwargs={
"k": 4, # Number of results
"score_threshold": 0.5 # Minimum similarity score
}
)- Returns top 4 most relevant chunks
- Filters by similarity threshold
- Balances relevance and coverage
Uses Ollama's Mistral model with a custom prompt defined in sources/obsidian/query.py:
CUSTOM_PROMPT = """You are a helpful assistant that answers questions based on the provided context from an Obsidian vault.
The context comes from various notes, and each piece of information includes metadata about its source.
Context information:
{context}
Question: {question}
Please provide a detailed answer based on the context. If the information comes from specific notes, mention them by name.
If you're not sure about something, say so. Don't make up information that isn't in the context.
Answer:"""Features:
- Context-aware responses
- Source attribution
- Confidence indication
- Chunk size (500 chars) balances:
- Context preservation
- Memory efficiency
- Processing speed
- ChromaDB provides efficient vector storage
- Embeddings are persisted for reuse
- Metadata enables fast filtering
The tool can handle:
- Large vaults (thousands of files)
- Deep directory structures
- Various file sizes
Limitations:
- Memory constraints for very large files
- Processing time for initial indexing
- Storage requirements for embeddings
Features:
- Local processing only
- No external API calls
- No data transmission
The architecture supports:
- Adding new data sources through the
DataSourceinterface - Different embedding models
- Alternative vector stores
- Custom response formats
-
Performance
- Batch processing for large vaults
- Incremental updates
- Caching mechanisms
-
Features
- More Obsidian features (tables, code blocks)
- Advanced filtering options
- Query history and favorites
-
User Experience
- Interactive query interface
- Result visualization
- Query suggestions
-
Integration
- Obsidian plugin
- API interface
- Web interface
This project is licensed under the MIT License - see the LICENSE file for details.