A CalDAV sync and API server that provides a JSON REST API for accessing calendar events and todos.
Note: The CalDAV sync infrastructure is complete and working. Calendar discovery and sync scheduling is functional. The next step is implementing full iCalendar (VEVENT/VTODO) parsing to populate event and todo data. Currently, the API returns empty data sets but all endpoints are operational and tested.
- 🔄 CalDAV Synchronization: Connects to CalDAV servers (iCloud, Nextcloud, etc.) and syncs calendar data
- 💾 XDG-Compliant Caching: Stores calendar data locally using XDG directory standards for fast access
- 🔄 Background Sync: Automatically syncs with CalDAV server on a configurable interval
- 🌐 REST API: Provides JSON endpoints for accessing calendar and todo data
- 🔒 Security-First: No secrets in code or config files - credentials loaded from files or environment variables
- ✅ Fully Tested: Comprehensive test coverage with unit and integration tests
- 🚀 Async/Performance: Built on Tokio for high-performance async I/O
cargo build --release# Using file-based credentials (recommended)
./target/release/fred-cal \
--caldav-server /run/secrets/email/icloud/caldav_server \
--username /run/secrets/email/icloud/address \
--password /run/secrets/email/icloud/password
# Using direct values
./target/release/fred-cal \
--caldav-server "https://caldav.example.com" \
--username "user@example.com" \
--password "your-password"
# Using environment variables
export CALDAV_SERVER="https://caldav.example.com"
export CALDAV_USERNAME="user@example.com"
export CALDAV_PASSWORD="your-password"
./target/release/fred-cal
# Custom port (default is 3000)
./target/release/fred-cal \
--caldav-server "https://caldav.example.com" \
--username "user@example.com" \
--password "your-password" \
--port 8080
# Diagnose calendar color support (check what the server returns)
./target/release/fred-cal \
--caldav-server "https://caldav.example.com" \
--username "user@example.com" \
--password "your-password" \
--diagnose-colorsThe server will:
- Perform an initial sync with your CalDAV server
- Cache the data locally in
~/.local/share/fred-cal/ - Start the API server on
http://0.0.0.0:3000 - Sync with CalDAV server every 15 minutes in the background
If your calendar colors are not showing up in the API, you can run the diagnostic mode to see what the server is returning:
./target/release/fred-cal \
--caldav-server "https://caldav.example.com" \
--username "user@example.com" \
--password "your-password" \
--diagnose-colorsThis will:
- Connect to your CalDAV server
- Discover all calendars
- Make custom PROPFIND requests checking both standard CalDAV and Apple-specific namespaces
- Display the raw XML responses and parsed color values
- Exit without starting the server
Note: Calendar colors are supported but depend on the CalDAV server providing them. The standard CalDAV namespace is urn:ietf:params:xml:ns:caldav with the calendar-color property. Apple servers may use a different namespace: http://apple.com/ns/ical/. Use the diagnostic mode to see which namespace your server uses.
All endpoints return JSON responses.
GET /api/healthReturns server health status and current timestamp.
GET /api/get_todayReturns all calendar events and todos for today.
Response:
{
"events": [...],
"todos": [...],
"last_sync": "2026-01-03T18:30:00Z"
}GET /api/get_today_calendarsReturns only calendar events for today (no todos).
GET /api/get_today_todosReturns only todos for today (no calendar events).
GET /api/get_date_range/:rangeReturns events and todos for a specified date range.
Range Formats:
today- Today's datetomorrow- Tomorrow's dateweek- Next 7 days from todaymonth- Next 30 days from today2026-01-05- Specific date (returns that day)2026-01-05:2026-01-10- Date range from start to end+3d- 3 days from now-2d- 2 days ago+1w- 1 week from now
Examples:
# Get this week's events
curl http://localhost:3000/api/get_date_range/week
# Get events for a specific date
curl http://localhost:3000/api/get_date_range/2026-01-15
# Get events for next 3 days
curl http://localhost:3000/api/get_date_range/+3d{
"uid": "unique-event-id",
"summary": "Event Title",
"description": "Event description",
"location": "Event location",
"start": "2026-01-05T10:00:00Z",
"end": "2026-01-05T11:00:00Z",
"calendar_name": "Personal",
"calendar_url": "/calendars/user/personal/",
"calendar_color": "#FF5733",
"all_day": false,
"rrule": "FREQ=WEEKLY;BYDAY=MO",
"status": "CONFIRMED",
"etag": "..."
}{
"uid": "unique-todo-id",
"summary": "Todo Title",
"description": "Todo description",
"due": "2026-01-10T12:00:00Z",
"start": "2026-01-05T09:00:00Z",
"completed": null,
"priority": 1,
"percent_complete": 50,
"status": "IN-PROCESS",
"calendar_name": "Tasks",
"calendar_url": "/calendars/user/tasks/",
"etag": "..."
}--caldav-server <URL>- CalDAV server URL (or path to file containing URL)--username <USERNAME>- Username for authentication (or path to file)--password <PASSWORD>- Password for authentication (or path to file)--port <PORT>- API server port (default: 3000)--diagnose-colors- Run calendar color diagnostics and exit
CALDAV_SERVER- CalDAV server URLCALDAV_USERNAME- UsernameCALDAV_PASSWORD- Password
Calendar data is cached in the XDG data directory:
- Linux:
~/.local/share/fred-cal/ - macOS:
~/Library/Application Support/fred-cal/ - Windows:
%APPDATA%\fred-cal\
- Rust 1.70+ (edition 2024)
- Cargo
cargo build# Run all tests
cargo test
# Run with verbose output
cargo test -- --nocapture
# Run only unit tests
cargo test --bins
# Run only integration tests
cargo test --test integration_tests# Run clippy (linter)
cargo clippy --all-targets -- -D warnings
# Format code
cargo fmt
# Check formatting
cargo fmt -- --checkfred-cal/
├── src/
│ ├── main.rs # Application entry point
│ ├── cli.rs # Command line argument parsing
│ ├── models.rs # Data models (CalendarEvent, Todo, etc.)
│ ├── cache.rs # XDG-compliant cache management
│ ├── sync.rs # CalDAV sync manager
│ └── api.rs # REST API endpoints
├── tests/
│ └── integration_tests.rs # Integration tests with mock CalDAV server
└── Cargo.toml
- CLI Module: Handles argument parsing and credential loading (file or direct)
- Cache Manager: XDG-compliant local storage for calendar data
- Sync Manager: Manages CalDAV synchronization with background updates
- API Server: Axum-based REST API with JSON responses
- Models: Type-safe data structures for events and todos
-
Never hardcode credentials: Use file paths or environment variables
-
Restrict file permissions:
chmod 600 /run/secrets/email/icloud/* -
Use HTTPS: Always connect to CalDAV servers over HTTPS
-
Don't commit secrets: Never commit secret files to version control
The project includes comprehensive test coverage:
- 33 unit tests covering core functionality
- 5 integration tests with mock CalDAV server
- 0 warnings with strict clippy lints enabled
- No unwrap/expect in production code paths
See TESTING.md for detailed testing documentation.
MIT License - see LICENSE file for details.
Contributions are welcome! Please ensure:
- All tests pass:
cargo test - Code is formatted:
cargo fmt - No clippy warnings:
cargo clippy --all-targets -- -D warnings - New features include tests
- CalDAV connection and authentication
- Local caching with XDG directories
- Background sync
- REST API for calendar events and todos
- Comprehensive testing
- Full iCalendar parsing (VEVENT, VTODO)
- Recurring event expansion
- Calendar color support
- Full EXDATE/RDATE/RECURRENCE-ID support
- Write-back support (modify calendars/todos)
- WebSocket support for real-time updates
- Multi-calendar filtering
- Search functionality
Built with:
- axum - Web framework
- tokio - Async runtime
- fast-dav-rs - CalDAV client
- chrono - Date/time handling
- serde - Serialization framework
For issues and feature requests, please use the GitHub issue tracker.