This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a Rust library and CLI tool that combines faith-related statistics from multiple data sources into a unified view. It aggregates data from:
- ankistats: Bible verse memorization progress from Anki
- readingstats: Bible reading time from KOReader
- prayerstats: Prayer time tracking (future enhancement)
The crate provides both a library API for programmatic access and a CLI tool for viewing combined statistics.
faithstats serves as an aggregation layer that sits above the individual stats crates. It:
- Queries multiple databases (Anki, KOReader, etc.)
- Merges data by date, using zero values when data is missing for a particular day
- Returns errors if any required database is unavailable
- Provides unified data structures combining all sources
This design keeps the backend crate thin (just HTTP wrapper) while making the aggregation logic reusable across CLI, API, and future applications.
src/lib.rs: Public library API exposing functions likeget_faith_daily_stats()src/main.rs: CLI binary that loads config from .env and displays formatted tablessrc/models.rs: Data structures withSerialize(for API),ToSchema(for OpenAPI), andTabled(for CLI)
- ankistats, readingstats, prayerstats: Source data crates (path dependencies)
- statsutils: Shared date/time utilities
- anyhow: Error handling
- serde: JSON serialization
- utoipa: OpenAPI schema generation
- tabled: CLI table formatting
- clap: CLI argument parsing
- dotenvy: .env file loading
# Build the faithstats crate
cargo build -p faithstats
# Build release version
cargo build -p faithstats --release
# Run tests
cargo test -p faithstats
# Check code
cargo check -p faithstatsThe CLI loads database paths from environment variables rather than command-line arguments. Create a .env file in the project root or export the variables:
# Create .env file with database paths
cat > .env <<EOF
ANKI_DATABASE_PATH=/path/to/collection.anki2
KOREADER_DATABASE_PATH=/path/to/statistics.sqlite3
EOF
# Run the daily command
cargo run -p faithstats -- dailyOr export environment variables directly:
export ANKI_DATABASE_PATH="/path/to/collection.anki2"
export KOREADER_DATABASE_PATH="/path/to/statistics.sqlite3"
cargo run -p faithstats -- dailyCurrently, the CLI provides one subcommand:
faithstats daily: Show faith statistics for the last 30 days with combined view
Future commands may include weekly, monthly, or custom date ranges.
Retrieves unified faith statistics for the last 30 days.
Parameters:
anki_db_path: Path to Anki collection.anki2 databasekoreader_db_path: Path to KOReader statistics.sqlite3 database
Returns:
FaithDailyStatscontaining:days: Vec ofFaithDayStatswith per-day breakdownsummary:FaithDailySummarywith aggregate statistics
Error Handling:
- Returns error if either database is unavailable or cannot be queried
- Uses zero values for days where one source has no data, but still requires both databases to be accessible
Example:
use faithstats::get_faith_daily_stats;
let stats = get_faith_daily_stats(
"/path/to/collection.anki2",
"/path/to/statistics.sqlite3"
)?;
println!("Total faith time: {:.2} hours", stats.summary.total_hours);
println!("Anki study: {:.2} min/day", stats.summary.anki_average_minutes_per_day);
println!("Reading: {:.2} min/day", stats.summary.reading_average_minutes_per_day);Combined statistics for a single day:
pub struct FaithDayStats {
pub date: String, // YYYY-MM-DD format
// Anki Bible memorization stats
pub anki_minutes: f64,
pub anki_matured_passages: i64,
pub anki_lost_passages: i64,
pub anki_cumulative_passages: i64,
// KOReader Bible reading stats
pub reading_minutes: f64,
// Prayer stats (future)
pub prayer_minutes: f64,
}Aggregate statistics across all sources:
- Per-source totals: minutes, hours, average per day, days active
- Anki-specific: matured/lost passages, net progress
- Combined: total time, average, days with any activity
Container with daily breakdown and summary:
pub struct FaithDailyStats {
pub days: Vec<FaithDayStats>,
pub summary: FaithDailySummary,
}The get_faith_daily_stats() function merges data from multiple sources:
- Query both databases: Calls
ankistats::get_last_30_days_stats()andreadingstats::get_last_30_days_stats() - Create lookup maps: Builds HashMap by date for efficient lookup
- Collect unique dates: Gets all dates from both sources
- Merge by date: For each date:
- Look up stats from both sources
- Use zero values if a source has no data for that date
- Combine into unified
FaithDayStats
- Compute summary: Aggregate statistics across all days
This approach ensures:
- All dates from both sources are included
- No data is lost
- Missing data is represented as zeros (not omitted)
- Errors bubble up if databases are unavailable
ANKI_DATABASE_PATH: Path to Anki collection database fileKOREADER_DATABASE_PATH: Path to KOReader statistics database file
The CLI will attempt to load a .env file from the current directory using the dotenvy crate. If the file doesn't exist, it falls back to checking environment variables directly.
The backend crate imports faithstats as a dependency and wraps its functions in HTTP endpoints:
/api/faith/daily: ReturnsFaithDailyStatsas JSON- Future:
/api/faith/weekly, etc.
The backend loads database paths from the same environment variables and passes them to the library functions.
- Prayer statistics integration: When
prayerstatsis implemented, automatically include prayer data - Weekly aggregation:
get_faith_weekly_stats()for 12-week view - Custom date ranges: Allow querying specific time periods
- Additional metrics: Total verses read, prayer topics, etc.
- Unified CLI commands: More subcommands (weekly, monthly, summary)
- The crate is designed to gracefully handle new data sources
- Adding a new source requires:
- Update
FaithDayStatsmodel with new fields - Update
FaithDailySummarywith new aggregates - Update merging logic in
get_faith_daily_stats() - Update CLI display and summary output
- Update
- Prayer stats are already scaffolded in the models with
prayer_minutesfield
When adding tests, consider:
- Testing merge logic with different date ranges
- Testing zero-value handling when sources have gaps
- Testing error propagation when databases are unavailable
- Testing summary calculations with various data patterns