A Python tool that consolidates multiple iCal feeds, filters them to today's events, and generates AI-powered summaries of what each person's day looks like.
- Fetch and parse multiple iCal feeds per person
- Recurring event support — expands RRULE, RDATE, and EXDATE automatically
- Support for shared calendars visible to all
- Per-calendar regex ignore patterns to filter out noisy events
- Filter events to current day (or any date via
--tomorrow/--date) with automatic timezone detection - AI-generated natural language summaries using Ollama
- YAML-based configuration
- Markdown output format
Before using this tool, ensure you have the following installed:
-
Python 3.10+
# Verify installation python3 --version -
uv (recommended) or pip
# With uv — no manual install needed, deps are resolved automatically: uv run cal_summary.py # Or install manually with pip: pip3 install icalendar pytz requests pyyaml markdown recurring-ical-events # On macOS with Homebrew Python, you may need: /opt/homebrew/bin/python3 -m pip install --break-system-packages icalendar pytz requests pyyaml markdown recurring-ical-events
-
Ollama - Local LLM for generating summaries
# Install Ollama # Visit: https://ollama.ai/ # Pull a model (e.g., llama3.1) ollama pull llama3.1:8b # Verify Ollama is running ollama list
-
Clone this repository:
git clone [email protected]:jbeker/today_overview.git cd today_overview
-
Install Python dependencies:
# Recommended: use uv (handles deps automatically via inline metadata) uv run cal_summary.py # Or install manually: pip3 install icalendar pytz requests pyyaml markdown recurring-ical-events # For macOS with Homebrew Python (if you get "externally-managed-environment" error) /opt/homebrew/bin/python3 -m pip install --break-system-packages icalendar pytz requests pyyaml markdown recurring-ical-events
-
Configure your calendars in
config.yaml(see Configuration section below)
Edit config.yaml to set up your people and calendar feeds:
people:
- name: Jeremy
calendars:
- https://calendar.google.com/calendar/ical/YOUR_CALENDAR_ID/basic.ics
- https://another-calendar-feed.ics
- name: Alice
calendars:
- https://alice-personal-calendar.ics
- https://alice-work-calendar.ics
shared_calendars:
- https://shared-team-calendar.ics
- https://company-holidays.ics
settings:
# Optional: Override default Ollama model (defaults to "llama3.1:8b")
ollama_model: "llama3.1:8b"
# Optional: Set timezone (defaults to system timezone)
# timezone: "America/New_York"You can filter out unwanted events on a per-calendar basis using ignore_patterns. Each pattern is a regular expression matched (case-insensitively) against the event summary. Any event that matches at least one pattern is excluded.
people:
- name: Alice
calendars:
- url: https://example.com/alice/work.ics
description: "Work calendar"
ignore_patterns:
- "^Focus Time$" # exact match
- "lunch block" # substring match
- "OOO|Out of Office" # multiple terms
shared_calendars:
- url: https://example.com/shared/family.ics
description: "Family calendar"
ignore_patterns:
- "^Placeholder$"Patterns use Python's re module syntax. Useful examples:
| Pattern | Effect |
|---|---|
^Focus Time$ |
Exact match only |
lunch |
Any event containing "lunch" |
standup|stand-up |
Events matching either variant |
^\[Blocked\] |
Events starting with "[Blocked]" |
- Open Google Calendar
- Click the three dots next to the calendar name
- Select "Settings and sharing"
- Scroll to "Integrate calendar"
- Copy the "Secret address in iCal format" URL
- Open iCloud Calendar on the web
- Click the share icon next to the calendar
- Enable "Public Calendar"
- Copy the webcal:// or https:// URL
Most calendar applications provide an iCal (.ics) feed URL in their sharing or export settings.
Run the script to generate today's calendar summary:
# Recommended: uv handles dependencies automatically
uv run cal_summary.py
# Or run directly if deps are installed:
python3 cal_summary.py
# Or if you've made it executable:
./cal_summary.pyBy default, events are fetched for today. Use --tomorrow or --date to query a different date:
# Fetch tomorrow's events
python3 cal_summary.py --tomorrow
# Fetch events for a specific date
python3 cal_summary.py --date 2026-02-20
# Combine with other flags
python3 cal_summary.py --tomorrow --json
python3 cal_summary.py --date 2026-03-01 --debugThe --tomorrow and --date flags are mutually exclusive.
Suppress INFO messages and only show the LLM summaries:
python3 cal_summary.py --quiet
# or
python3 cal_summary.py -qThis is useful when piping output to files or other commands, as it removes all the progress information and only shows the final summaries.
Output summaries as a JSON array instead of formatted text:
python3 cal_summary.py --jsonThe JSON output format includes an array of objects with the following fields:
name: Person's namedate: The date of the summary (ISO format)summary: The LLM-generated summary text
Example output:
[
{
"name": "Jeremy",
"date": "2026-01-14",
"summary": "Jeremy has a busy day starting with..."
},
{
"name": "Alice",
"date": "2026-01-14",
"summary": "Alice's schedule includes..."
}
]This is useful for:
- Integration with other tools and scripts
- Programmatic processing of summaries
- Storing summaries in databases
- Building web applications or APIs
Note: JSON mode automatically suppresses INFO messages (equivalent to --quiet).
Convert markdown summaries to HTML format:
# Output as HTML sections
python3 cal_summary.py --html
# Or combine with JSON for HTML in JSON format
python3 cal_summary.py --json --htmlHTML-only mode (--html) outputs HTML fragments with each person's summary wrapped in a <section> tag:
<section>
<h2>Jeremy's Day - 2026-01-14</h2>
<p>Jeremy has a busy day starting with...</p>
<!-- More HTML content -->
</section>
<section>
<h2>Alice's Day - 2026-01-14</h2>
<p>Alice's schedule includes...</p>
<!-- More HTML content -->
</section>Combined JSON+HTML mode (--json --html) outputs JSON with HTML in the summary field:
[
{
"name": "Jeremy",
"date": "2026-01-14",
"summary": "<p>Jeremy has a busy day starting with...</p>"
}
]This is useful for:
- Embedding summaries in web pages
- Email newsletters (HTML format)
- CMS integration
- Combining with other HTML content
Note: HTML mode automatically suppresses INFO messages and outputs HTML fragments only (no <html>, <head>, or <body> tags).
python3 cal_summary.py --quiet > daily_summary.md
# Save as JSON
python3 cal_summary.py --json > daily_summary.json
# Save as HTML
python3 cal_summary.py --html > daily_summary.html
# Save as JSON with HTML content
python3 cal_summary.py --json --html > daily_summary.jsonAdd to your crontab to run daily:
# Run at 7 AM every day
0 7 * * * cd /path/to/today_overview && python3 cal_summary.py --quiet > ~/daily_summary_$(date +\%Y\%m\%d).mdCombine with mail command:
python3 cal_summary.py --quiet | mail -s "Daily Calendar Summary - $(date +\%Y-\%m-\%d)" [email protected]The script generates Markdown-formatted output with:
- Shared calendar events (if any)
- Individual sections for each person
- Event details (time, location, description)
- AI-generated natural language summary
Example output:
## Shared Calendar Events
- Team Standup at 09:00
- Company All-Hands at 14:00
## Jeremy
- Morning Workout at 06:30
- Client Meeting at 10:00
- Lunch with Sarah at 12:30
Jeremy has a busy day starting with an early morning workout...Install all required Python dependencies:
pip3 install icalendar pytz requests pyyaml markdown recurring-ical-events- Check that the calendar URL is correct and accessible
- Verify you have an internet connection
- Some calendar feeds may require authentication
- Ensure the URL points to a valid .ics file
- Try downloading the .ics file manually to verify it's valid
Install required Python libraries:
pip3 install icalendar pytz requests pyyaml markdown recurring-ical-eventsEnsure Ollama is running and the model is available:
# Check if Ollama is running
ollama list
# If not running, start it (it usually runs as a background service)
# Visit https://ollama.ai/ for installation instructions
# Ensure you have the required model
ollama pull llama3.1:8b- Verify the script is filtering for today's date
- Check that events exist on your calendars for today
- Ensure timezone settings are correct
Edit config.yaml:
settings:
ollama_model: "llama2" # or any other model available in OllamaAvailable models can be found with ollama list or at https://ollama.ai/library
Edit config.yaml:
settings:
timezone: "America/Los_Angeles"Edit the prompt setting in config.yaml to change how the AI generates summaries.
today_overview/
├── cal_summary.py # Main Python script
├── parse_ical.py # Helper for iCal parsing (legacy)
├── config.yaml # Configuration file
├── .gitignore # Git ignore rules
└── README.md # This file
This tool is provided as-is for personal use.
Feel free to modify and extend this tool for your needs!