Family Assistant
Sovereign family operations hub โ email โ calendar + RAG, with LLM-powered parsing, conflict resolution, and conversational retrieval. Zero cloud dependencies.
Family Assistant watches a dedicated email inbox, extracts structured event data using a local LLM (no regex, no brittle date parsers), syncs to a self-hosted Radicale CalDAV calendar, and answers questions about past emails using semantic search. When events conflict, it suggests intelligent resolutions. When someone asks "what do the kids need for the field trip?", it pulls the answer from the emails it's already processed.
Why This Exists
Family calendar management is a solved problem โ if you use Cozi, Google Family Calendar, or any of the dozen apps out there. But they all share the same weakness: they parse appointment emails with regex. One formatting change from your vet's office and the parser breaks.
Family Assistant uses Prompt-as-Code: a local LLM reads the email and extracts structured JSON. The prompt is easier to update than a regex library, handles edge cases naturally, and doesn't break when a sender changes their subject line format.
More importantly, Family Assistant is sovereign โ it runs on your hardware, stores data on your disk, and uses your domain. No Google account required. No OAuth tokens that expire. No API quotas that get suspended. Your calendar, your email, your data.
Architecture
Email โ Cloudflare Email Worker โ hook.hoffdesk.com โ FastAPI Webhook
โ
โผ
LLM Triage โโฌโโ Appointment Parse โโโ Radicale CalDAV + Brain
โ
โโโ Newsletter Parse โโโ Radicale CalDAV + Brain
โ
โผ
Conflict Detection
โ
โผ
LLM Resolution (split / reassign / reschedule)
โ
โผ
Hermes Telegram Alert with Inline Buttons
Group Chat โโโ Intent Router โโฌโโ Calendar Mutation (move/cancel/add/rename/remind)
โโโ Question โ Hybrid Query (Calendar + Brain RAG)
โโโ Chatter โ Silence
Location Resolution: Cache โ Fuzzy Match โ goplaces โ Nominatim โ Haversine
Key design decisions:
- Sovereign โ no Google dependency. Radicale CalDAV on your hardware, Cloudflare for TLS termination and email routing, local Ollama for LLM inference.
- Push architecture โ Cloudflare Email Worker webhook replaces IMAP polling. Instant delivery, no bot-like behavior.
- Prompt-as-Code โ prompts live in text files, not Python. Update extraction logic without touching code.
- Hybrid retrieval โ Radicale calendar is the source of truth for time/date/location; ChromaDB provides detail context (dress codes, what to bring, signup links).
- Intent guardrail โ three-way classification prevents hallucinated RAG queries on chatter ("okay", "thanks").
- Cache-first location resolution โ every location string passes through a 5-tier resolver (exact cache โ fuzzy match โ goplaces โ Nominatim โ haversine estimate) to prevent LLM hallucinations.
- Day-of-week mismatch detection โ LLM extracts the claimed day, pipeline validates against the parsed date, warns if they disagree.
- Self-hosted calendar โ Radicale CalDAV with bcrypt auth, Cloudflare Tunnel for iOS, flat-file storage. Zero API limits, zero ban risk.
Features
Email Pipeline
- Webhook delivery โ Cloudflare Email Worker posts raw RFC 5322 email to FastAPI webhook. No polling, no IMAP, instant delivery.
- Appointment extraction โ LLM parses any email format into structured events
- Newsletter extraction โ multi-type (events, reminders, actions, info) with dedup
- Recurring events โ weekly, biweekly, monthly (e.g. "2nd Wednesday"), with count or end date
- Shadow filter โ rejected items downgraded, not deleted; restore from digest
- Auto-ingestion โ all parsed emails/newsletters stored in ChromaDB for RAG retrieval
- HTML-to-text โ stdlib-only HTML conversion, no external dependencies
- Day-of-week mismatch โ warns when email says "Monday" but the parsed date is Tuesday
Calendar Management
- Radicale CalDAV sync โ create, update, cancel, dedup against existing events via caldav+icalendar
- iCalendar RRULE support โ full recurring event generation
- Conflict detection โ finds overlapping events with 5-min grace period
- LLM conflict resolution โ split, reassign, or reschedule with priority rules
- Interactive Telegram buttons โ resolve conflicts with a tap
- Shared family calendar โ both phones sync via single CalDAV account
Hermes Notification System
- Direct Telegram Bot API โ reliable delivery, no CLI timeout issues
- Per-event notifications โ single message per calendar event with location + travel time
- Day-of-week warnings โ โ ๏ธ when email day claim doesn't match parsed date
- Inline action buttons โ conflict resolution, slot selection, task completion
Conversational Retrieval (Family Brain)
- Hybrid query โ synthesizes Calendar (temporal truth) + ChromaDB (detail context)
- Semantic search โ
nomic-embed-textembeddings via local Ollama - Retrieval-only โ answers questions, never offers actions it can't execute
- 30-day backfill โ seed the brain from existing processed emails
Location Intelligence
- 5-tier resolution stack โ exact cache โ fuzzy prefix match โ goplaces/Google Places โ Nominatim/OSM โ haversine estimate
- Home-biased coordinates โ locations resolve with travel time from home
- Fuzzy matching โ "Golrusk" โ "Golrusk Pet Care Center" (min 4 chars)
- Nominatim fallback โ free OpenStreetMap geocoder, no API key needed
- Travel time estimation โ straight-line distance ร 1.4 road factor รท 35 mph
Chat-Driven Intent Engine
- Wake words โ "Socrates", "calendar", "schedule" (configurable)
- Reply-to context โ replying to a bot message carries event context
- Calendar mutations โ move, cancel, add, rename, reject, remind
- Rejection engine โ "we don't need that mass, ignore it forever" โ persistent rule
- Maintenance sentinel โ recurring household task tracking with Done buttons
- Slot handler โ follow signup links, extract available time slots, tap to add reminder
Reliability
- Global error handler โ pipeline crashes push stack traces to admin DM, no silent deaths
- Idempotent ingestion โ ChromaDB uses upsert, Calendar uses dedup
- TTL cleanup โ 12-month auto-purge for school year context expiration
- Sovereign backup โ daily tar of Radicale + ChromaDB + config โ local + remote (Gaming PC via Tailscale SSH)
- Dedup โ in-memory 24h TTL on webhook, message-id dedup on email pipeline
Quick Start
Prerequisites
- Python 3.10+
- Ollama running locally (or on another machine on your network)
- Radicale CalDAV server (or any CalDAV server)
- Cloudflare account (for Email Worker + Tunnel)
- Telegram bot token (for notifications and interactive features)
Installation
git clone https://github.com/NightKnight64/family-assistant.git
cd family-assistant
pip install -e .
Setup
# Interactive setup wizard
python -m family_assistant setup
# Or non-interactive (creates template files)
python -m family_assistant setup --non-interactive
This creates:
- .env โ API credentials template
- family.yaml โ your family members, roles, nicknames
Configure Your Family
Edit family.yaml:
family:
members:
- name: Alex
role: dad
pronouns: he/him
- name: Jordan
role: mom
pronouns: she/her
- name: Riley
role: son
pronouns: he/him
nicknames: [Rye] # LLM normalizes these
needs_adult: true # Requires adult to transport
- name: Morgan
role: daughter
pronouns: she/her
needs_adult: true
- name: Buddy
role: dog
needs_adult: true
location:
home:
address: "123 Main St, Anytown, ST 12345"
lat: 44.5054
lng: -87.9557
Set Up Radicale CalDAV
pip install radicale
See WEBHOOK_DEPLOY.md for full Radicale + Cloudflare + systemd setup instructions.
Key config:
- Bind to 0.0.0.0:5232 (or 127.0.0.1 if behind Cloudflare Tunnel)
- Use bcrypt htpasswd ($2b$ prefix)
- Permissive rights for private home network
Set Up Email Pipeline
- Cloudflare Email Worker โ deployed as
hoffdesk-email, code atscripts/email_worker.js(v3) - Email Routing โ configure
assistant@yourdomain.comโ Worker - Webhook server โ install
hoffdesk-webhook.servicesystemd unit - Cloudflare Tunnel โ map
hook.yourdomain.comโlocalhost:5000
See WEBHOOK_DEPLOY.md for step-by-step instructions.
Set Up LLM
By default, Family Assistant uses a local Ollama instance:
# Install models
ollama pull qwen2.5-coder:7b # Extraction + synthesis
ollama pull nomic-embed-text # Embeddings
ollama pull qwen3-vl:8b # Vision/OCR (optional, for Document Sorter)
Point to a remote Ollama instance in .env:
LLM_URL=http://your-server:11434/v1/chat/completions
LLM_MODEL=qwen2.5-coder:7b
OLLAMA_EMBED_URL=http://your-server:11434/api/embeddings
VISION_LLM_URL=http://your-server:11434/api/chat # Optional, for Document Sorter
Set Up Telegram Bot
- Create a bot via @BotFather
- Get the bot token and your chat IDs
- Add to
.env:TELEGRAM_BOT_TOKEN,TELEGRAM_CHAT_ID,TELEGRAM_DEV_ID
Usage
Email Pipeline
# Process emails from webhook (called by FastAPI webhook server)
python -m family_assistant process # process unread emails โ parse โ calendar + brain
# Legacy: IMAP-based processing (if not using webhook)
python -m family_assistant process --dry-run # preview without creating events
python -m family_assistant process --no-notify # skip Telegram notifications
# Show upcoming calendar events
python -m family_assistant upcoming --hours 168
# Detect scheduling conflicts
python -m family_assistant conflicts --hours 168
# Generate resolution options for conflicts
python -m family_assistant resolve --hours 168
Conflict Resolution
- Detect โ finds events with overlapping time windows (5-min grace period)
- Resolve โ LLM generates 2-3 options based on family priorities:
- Split โ both events happen, parents divide responsibilities
- Reassign โ same event, different adult takes over
- Reschedule โ removes lower-priority event + creates a rebook reminder - Handle โ you pick an option, it executes the calendar changes
Priority rules (built into the resolution prompt):
- Children's medical/dental > pet appointments > adult personal
- Kids need adults to transport; dogs need adults to transport
- Suggest splitting before rescheduling when possible
Interactive Conflict Alerts
# Scan for conflicts + send Telegram alert with inline buttons
python -m family_assistant conflict-notify
Intent Engine (Chat-Driven Calendar)
# Direct intent parse + execute
python -m family_assistant intent --message "move OT to 4pm tomorrow"
# Routed from Telegram group reply
python -m family_assistant chat-intent --message "cancel the vet" --reply --quoted "Maggie grooming on Friday"
# Inbound hook (OpenClaw message bridge)
python -m family_assistant inbound-hook --message "Socrates, add soccer practice Tuesdays at 4"
# Reject an event type
python -m family_assistant reject "First Communion Mass" "we don't need this"
python -m family_assistant rejections # list active rejection rules
Family Brain (RAG Queries)
# Ask a question about past emails/newsletters
python -m family_assistant brain-query --question "what do the kids need for the field trip?"
# Check Brain stats
python -m family_assistant brain-stats
# Backfill Brain from the last 30 days of email
python -m family_assistant brain-backfill --days 30
# Purge documents older than 12 months
python -m family_assistant brain-purge
Location Cache
# Resolve a location (cache โ goplaces โ Nominatim)
python -m family_assistant location --query "Golrusk Pet Care Center"
# Show cached locations
python -m family_assistant location-stats
Maintenance Sentinel
# Check recurring task status + brief
python -m family_assistant maintenance
# Mark a task complete
python -m family_assistant maint-done --event-summary "Change water filter"
Slot Handler (Signup Links)
# Fetch signup slots from a URL
python -m family_assistant click --url "https://signupgenius.com/..." --context "field trip chaperone"
# Handle slot button tap
python -m family_assistant slot-callback --callback-data 'slot|abc123|2'
Backup
# Manual backup (runs daily at 7 AM via cron)
./backup_hoffdesk.sh
# Skip remote copy (Gaming PC offline)
SKIP_REMOTE=true ./backup_hoffdesk.sh
Project Structure
family_assistant/
โโโ config.py โ All config from env vars + family.yaml + .env auto-load
โโโ email_fetcher.py โ IMAP fetch, decode, mark-read (legacy, pre-webhook)
โโโ email_webhook.py โ FastAPI webhook server for Cloudflare Email Worker
โโโ appointment_parser.py โ LLM extraction + JSON normalization + recurrence
โโโ newsletter_parser.py โ Multi-type extraction + Phase 1+2 LLM dedup + recurrence
โโโ calendar_sync.py โ Radicale CalDAV CRUD, dedup, event matching, recurring events
โโโ rrule_builder.py โ RRULE construction from LLM recurrence dicts
โโโ conflict_engine.py โ Detection + resolution + response handler
โโโ conflict_notify.py โ Telegram inline buttons for conflict resolution + rejection
โโโ rejection_engine.py โ LLM-powered rejection intent parsing + rule persistence
โโโ family_brain.py โ ChromaDB RAG: embed, ingest, query, hybrid synthesis
โโโ location_cache.py โ 5-tier location resolution (cache โ fuzzy โ goplaces โ Nominatim โ haversine)
โโโ hermes.py โ Telegram push notifications (events, conflicts, digest, alerts)
โโโ pipeline.py โ process_emails() + process_webhook_email() orchestration + error handler
โโโ intent_engine.py โ Chat intent parsing + calendar execution + hybrid question handler
โโโ intent_router.py โ Inbound gateway: wake word/reply-to-bot โ intent classification
โโโ inbound_hook.py โ OpenClaw message bridge โ intent router
โโโ maintenance_sentinel.py โ Recurring household task tracker + alert dedup
โโโ clicker.py โ Follow URLs โ extract signup slots โ Telegram buttons
โโโ slot_handler.py โ Slot button tap โ cache lookup โ calendar reminder
โโโ document_sorter.py โ OCR (qwen3-vl) + LLM classify โ Google Drive upload (WIP)
โโโ url_fetcher.py โ Jina Reader for JS-rendered page content
โโโ cli.py โ All CLI commands
โโโ setup.py โ Setup wizard
โโโ prompts/ โ Externalized prompt text files
โ โโโ appointment_extract.txt
โ โโโ appointment_retry.txt
โ โโโ newsletter_extract.txt
โ โโโ newsletter_dedup.txt
โ โโโ chat_intent.txt
โ โโโ conflict_resolve.txt
โ โโโ email_classify.txt
โโโ family.yaml.example โ Template for family configuration
โโโ tests/
โโโ test_qa.py โ 14-case QA suite
scripts/
โโโ backup_hoffdesk.sh โ Daily backup: Radicale + ChromaDB + secrets โ local + remote
โโโ email_worker.js โ Cloudflare Email Worker (posts to webhook)
โโโ research_agent/ โ Research CLI for deep-dive topics
โโโ research_cli.py โ Research agent command-line interface
โโโ systemd/ โ Systemd service files
โโโ hoffdesk-webhook.service
โโโ radicale.service
โโโ family-assistant-webhook.service
Customizing Prompts
The prompts/ directory contains the LLM instructions. Edit them to:
- Add new appointment types (e.g., "school play rehearsal")
- Change output format (add fields, modify field names)
- Adjust conflict resolution priorities
- Add family-specific context (allergies, recurring schedules, etc.)
- Modify intent classification (add wake words, change chatter rules)
Family member names and nicknames are injected automatically from family.yaml.
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
CALDAV_URL |
Yes | http://127.0.0.1:5232 |
Radicale CalDAV server URL |
CALDAV_USER |
Yes | assistant |
CalDAV username |
CALDAV_PASSWORD |
Yes | โ | CalDAV password |
CALDAV_CALENDAR_NAME |
Yes | family |
Calendar name |
LLM_URL |
No | http://localhost:11434/v1/chat/completions |
Ollama endpoint for extraction |
LLM_MODEL |
No | qwen2.5-coder:7b |
Model for extraction and synthesis |
LLM_NEWSLETTER_MODEL |
No | qwen2.5-coder:7b |
Model for newsletter extraction |
LLM_NEWSLETTER_URL |
No | Falls back to LLM_URL |
Endpoint for newsletter model |
OLLAMA_EMBED_URL |
No | http://localhost:11434/api/embeddings |
Ollama endpoint for embeddings |
VISION_LLM_URL |
No | โ | Ollama endpoint for vision/OCR model |
TELEGRAM_BOT_TOKEN |
Yes | โ | Telegram bot token |
TELEGRAM_CHAT_ID |
No | โ | Family group chat ID |
TELEGRAM_DEV_ID |
No | โ | Admin DM chat ID (error alerts) |
WEBHOOK_SECRET |
Yes | โ | Shared secret for Cloudflare Email Worker auth |
GOOGLE_PLACES_API_KEY |
No | โ | Google Places API key (optional, Nominatim is free fallback) |
FAMILY_CONFIG_PATH |
No | Auto-detect | Path to family.yaml |
INTENT_WAKE_WORDS |
No | Socrates,calendar,schedule |
Wake words for intent routing |
REMOTE_HOST |
No | โ | SSH target for backup (e.g. user@host) |
Set these in a .env file in the working directory โ Family Assistant auto-loads it.
Deployment
See WEBHOOK_DEPLOY.md for full deployment instructions including:
- Radicale CalDAV server setup (systemd, htpasswd, rights)
- FastAPI webhook server (Cloudflare Tunnel, email routing)
- Cloudflare Email Worker deployment
- iPhone CalDAV account configuration
- Backup script setup (local + remote via Tailscale SSH)
Permanent Model Rules
- โ
qwen2.5-coder:7bโ single model for ALL pipeline tasks (extraction, synthesis, intent) - โ
qwen3-vl:8bโ vision/OCR only (Document Sorter),keep_alive: 0 - โ
nomic-embed-textโ embeddings only - โ No
home-assistmodel โ ever - โ No
deepseek-r1models โ burn thinking tokens, fail JSON - โ No
qwen3:8bโ thinking tokens can't be disabled, 3-13x slower
Roadmap
v1.0 โ (Complete)
- [x] Email โ Calendar pipeline with LLM extraction
- [x] Cloudflare Email Worker webhook (push architecture)
- [x] Radicale CalDAV migration (Google-free)
- [x] Conflict detection + resolution (split/reassign/reschedule)
- [x] Hermes Telegram notification agent (direct Bot API)
- [x] Day-of-week mismatch detection
- [x] Location intelligence (5-tier cache + Nominatim fallback + travel time)
- [x] Interactive conflict buttons in Telegram
- [x] Rejection engine (shadow filter + persistent rules)
- [x] Intent engine (chat-driven calendar mutations)
- [x] Recurring event support (weekly, biweekly, monthly patterns)
- [x] Family Brain RAG (ChromaDB + hybrid query)
- [x] Global error handler (admin DM alerts)
- [x] Maintenance sentinel (recurring task tracking)
- [x] Sovereign backup (local + remote via Tailscale SSH)
- [x] Document Sorter (OCR + classify, WIP)
Post-v1.0 (Deferred)
- [ ] Multi-calendar support (work vs. personal)
- [ ] Docker Compose deployment
- [ ] Refactor prompts to YAML for user configurability
- [ ] Provider abstraction (Gmail โ Outlook, iCloud)
- [ ] Web UI for conflict resolution
- [ ] Auth failure circuit breaker (3 consecutive โ pause + alert)
License
MIT โ see LICENSE.