turbovault-core
Core data models, error types, and configuration for the Obsidian vault management system.
This crate provides the foundational types and utilities that all other TurboVault crates depend on. It defines the canonical data structures, error handling, configuration management, and cross-cutting concerns like metrics and validation.
Purpose
turbovault-core is the foundation layer that:
- Defines all core data models (vault files, links, headings, tags, etc.)
- Provides a unified error type system for composable error handling
- Manages server and vault configuration with validation
- Implements multi-vault coordination and lifecycle management
- Offers lightweight metrics collection with zero locking overhead
- Provides content validation framework with extensible validators
- Defines configuration profiles for different deployment scenarios
- Implements resilience patterns (retry logic, circuit breakers)
Key Components
Data Models (models.rs)
Rich, serializable types representing Obsidian vault elements:
use *;
// Core vault file with parsed content
let file = new;
// Structured link types
let link = new;
// Parse results include headings, tags, callouts, tasks, etc.
assert_eq!;
assert!;
Types:
VaultFile- Complete parsed markdown file with all elementsLink- Links with type classification (see LinkType below)Heading- Hierarchical headings with anchorsTag- Inline and frontmatter tagsTaskItem- Checkboxes with completion statusCallout- Obsidian callout blocks (note, warning, tip, etc.)Block- Generic content blocks with IDsFrontmatter- YAML metadataFileMetadata- File system metadata (size, timestamps, checksum)ContentBlock- Block-level AST (Heading, Paragraph, Code, List, Table, etc.)InlineElement- Inline formatting (Strong, Emphasis, Code, Link, Image)
LinkType variants:
WikiLink- Basic wikilink:[[Note]]Embed- Embedded content:![[Note]]BlockRef- Block reference:[[Note#^blockid]]or#^blockidHeadingRef- Cross-file heading:[[Note#Heading]]orfile.md#sectionAnchor- Same-document anchor:[[#Heading]]or#sectionMarkdownLink- Markdown link to file:[text](./file.md)ExternalLink- External URL:[text](https://...)
Error Handling (error.rs)
Unified error type for the entire system:
use ;
Error Categories:
Io- File system errors (auto-converted fromstd::io::Error)FileNotFound- Missing files with path contextInvalidPath- Path validation failuresPathTraversalAttempt- Security violationsFileTooLarge- Size limit violationsParseError- Content parsing failuresConfigError- Configuration validation issuesValidationError- Content validation failuresConcurrencyError- Race condition detectionNotFound- Missing graph entries
Configuration (config.rs)
Builder-based configuration with validation:
use *;
// Single vault configuration
let vault = builder
.as_default
.watch_for_changes
.build?;
// Server-wide configuration
let mut server_config = new;
server_config.vaults.push;
server_config.max_file_size = 20 * 1024 * 1024; // 20MB
server_config.validate?;
Features:
VaultConfig- Per-vault settings with optional overridesServerConfig- Global server settings with defaults- Builder pattern for ergonomic construction
- Automatic validation on build
- Persistence to/from YAML
Multi-Vault Management (multi_vault.rs)
Coordinate multiple Obsidian vaults simultaneously:
use MultiVaultManager;
let manager = new?;
// Add new vault
manager.add_vault.await?;
// Switch active vault
manager.set_active_vault.await?;
// List all vaults
let vaults = manager.list_vaults.await?;
for vault_info in vaults
Features:
- Vault isolation and independent lifecycle
- Default vault concept with automatic fallback
- Setting inheritance with per-vault overrides
- Async-safe with RwLock coordination
- Clone-safe for sharing across threads
Metrics (metrics.rs)
Lock-free metrics infrastructure for high-performance observability:
use *;
// Lock-free counter (atomic operations)
let counter = new;
counter.increment;
counter.add;
assert_eq!;
// Histogram for distributions
let histogram = new;
histogram.record;
// RAII timer for automatic duration recording
// Duration automatically recorded on drop
Features:
Counter- Monotonically increasing atomic valuesHistogram- Distribution tracking with statisticsHistogramTimer- RAII timer for automatic recordingMetricsContext- Global registry (rarely used)- Zero locking overhead
- Saturating arithmetic (no overflow panics)
Validation (validation.rs)
Extensible content validation framework:
use *;
// Create validators
let validator = new
.add_validator
.add_validator
.add_validator;
// Validate a file
let report = validator.validate;
if !report.passed
Validators:
FrontmatterValidator- Required fields, tag format validationLinkValidator- Empty targets, suspicious URLs, fragment-only linksContentValidator- Length checks, required headingsCompositeValidator- Run multiple validators
Severity Levels:
Info- Informational messagesWarning- Should be addressed but not criticalError- Should be fixed (fails validation)Critical- Must be fixed (fails validation)
Configuration Profiles (profiles.rs)
Pre-configured deployments for common use cases:
use ConfigProfile;
// Create profile-based configuration
let config = Production.create_config;
// Or get recommendation based on vault size
let profile = recommend;
let config = profile.create_config;
Available Profiles:
Development- Verbose logging, all features enabled, metrics onProduction- Optimized for reliability and securityReadOnly- Search/analysis only, no write operationsHighPerformance- Tuned for large vaults (5000+ files)Minimal- Bare essentials onlyMultiVault- Multiple vault support with isolationCollaboration- Team features, webhooks, exports
Resilience (resilience.rs)
Patterns for graceful error handling:
use *;
// Retry with exponential backoff
let config = conservative;
let result = retry_with_backoff.await?;
// Circuit breaker for preventing cascading failures
let circuit_breaker = new;
if circuit_breaker.is_request_allowed else
Features:
- Exponential backoff retry with configurable limits
- Circuit breaker with Closed/Open/HalfOpen states
- Fallback strategies for graceful degradation
Usage Examples
Basic Setup
use *;
// Configure a vault
let vault_config = builder
.as_default
.build?;
// Create server configuration
let mut server_config = new;
server_config.vaults.push;
server_config.validate?;
// Create multi-vault manager
let manager = new?;
Working with Files
use *;
// Create a vault file
let metadata = FileMetadata ;
let mut file = new;
// Add parsed elements
file.headings.push;
file.links.push;
// Query parsed content
let outgoing = file.outgoing_links;
let has_rust_tag = file.has_tag;
let blocks = file.blocks_with_ids;
Dependent Crates
All other TurboVault crates depend on turbovault-core:
- turbovault-parser - Uses models for parse results
- turbovault-vault - Uses config and models for vault operations
- turbovault-graph - Uses models for link graph construction
- turbovault-batch - Uses models and config for batch operations
- turbovault-export - Uses models for export operations
- turbovault-tools - Uses all types for MCP tool implementations
- turbovault-server - Uses config and multi-vault management
Development
Building
Testing
# Run all tests
# Run with output
# Run specific test
Documentation
# Generate and open docs
Design Decisions
Why Separate Core Crate?
- Dependency Inversion: Higher-level crates depend on abstractions, not implementations
- Compilation Performance: Core changes don't rebuild entire project
- API Stability: Core types are stable; implementations can evolve
- Testing: Easy to test models and config without heavyweight dependencies
Why Builder Pattern?
Configuration objects have many optional fields. Builders provide:
- Clear, fluent API
- Compile-time enforcement of required fields
- Validation on build
- Future-proof (add fields without breaking API)
Why Lock-Free Metrics?
Traditional metrics use Mutex/RwLock which:
- Adds contention in high-throughput scenarios
- Can cause unpredictable latency spikes
- Doesn't scale well across many cores
Lock-free atomics provide:
- Predictable O(1) performance
- No contention or waiting
- Perfect for hot paths
Why Custom Error Type?
Using anyhow::Error loses type information. Custom Error enum provides:
- Pattern matching on error categories
- Rich context (path, size, line numbers)
- Composable error handling across crates
- Clear API contracts
License
Licensed under the same terms as the TurboVault project.