A lightweight Windows 11 tray application that displays your next upcoming meeting from a public calendar ICS (.ics) feed.
It shows a dynamic tooltip with the next meeting title and time, and notifies you when the meeting is about to start. Optionally, it shows a hover/preview window with more details.
- Tray icon with dynamic tooltip showing:
Next: <Title> (In X min|In Y h|Mon HH:mm) - Auto balloon notification when a meeting is within 15 minutes (once per meeting)
- Context menu: Open Meeting, Refresh, Set Calendar URL, Exit
- Stores configuration in
%APPDATA%/ComingUpNext/config.json - Lightweight ICS parsing (skips malformed events)
- Configurable refresh interval (default 5 minutes) via
RefreshMinutesinconfig.jsonor "Set Refresh Minutes" context menu option
Provide a publicly accessible .ics URL (can be from Outlook, Google Calendar, etc.). The app reads VEVENT blocks and uses:
SUMMARY→ Meeting titleDTSTART→ Start time (all-day events treated as midnight local)DTEND→ End time (if missing/invalid defaults to +1 hour)URL→ Meeting link (if present)DESCRIPTION→ Fallback scan for firsthttp/httpslink ifURLabsent (helpful for Teams links embedded in description)
Example snippet:
BEGIN:VEVENT
SUMMARY:Daily Standup
DTSTART:20251030T090000Z
DTEND:20251030T091500Z
URL:https://teams.microsoft.com/l/meetup-join/...
END:VEVENTTimezone & recurrence handling:
TZID=parameters onDTSTART/DTENDare respected (converted from that zone to local).- UTC times (
Zsuffix) converted to local. - Floating times (no TZ) treated as local.
- Date-only values (
YYYYMMDD) treated as all-day starting at local midnight. - Simple weekly
RRULEpatterns (e.g.FREQ=WEEKLY;BYDAY=MO,WE;INTERVAL=1;UNTIL=20261102T160000Z) are expanded for upcoming occurrences (up to 3 months lookahead or UNTIL limit) including exclusions via matchingEXDATE. EXDATEentries remove specific occurrences from recurrence expansion.
Limitations: Advanced recurrence (monthly rules, BYSETPOS, COUNT, exceptions with time shifts) is not yet supported.
Requires .NET 9 SDK.
# Build
dotnet build
# Run (from project directory)
cd src/ComingUpNextTray
dotnet runOn first run, use the tray icon context menu "Set Calendar URL" to paste the ICS URL. Optionally adjust the refresh interval with "Set Refresh Minutes" (1-1440). The default is 5 minutes. You can force an immediate reload at any time with the "Refresh" context menu item (it disables while fetching to avoid overlapping requests).
Produce a single-file self-contained executable:
dotnet publish src/ComingUpNextTray/ComingUpNextTray.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeAllContentForSelfExtract=true -o publishThe output folder publish will contain the EXE. Version metadata (AssemblyVersion/FileVersion/Product Version) is taken from the <Version> property inside ComingUpNextTray.csproj.
An example WiX v5 setup is provided under installer/.
Prerequisites:
- .NET 10 SDK
- WiX Toolset v5 (installed automatically by the build script if missing)
Build the MSI (auto-reads <Version> from the csproj):
cd installer
./build.ps1 -Configuration Release -Runtime win-x64Result: installer/ComingUpNextTray-X.Y.Z.msi where X.Y.Z is the version from the project file.
To override the version just for a build (without editing the csproj), pass -Version:
./build.ps1 -Configuration Release -Runtime win-x64 -Version 1.2.3This stamps the EXE (assembly/file/product) and the MSI Package version consistently.
Adjustments:
- Update GUID placeholders in
installer/Product.wxs(generate new GUIDs viaNew-Guid). - Change
Manufacturer,Version, or add more components (e.g., config file defaults). - To auto-start for current user you can add a shortcut component pointing to Startup folder or set Run key (advanced customization).
Silent install example:
msiexec /i ComingUpNextTray-1.0.0.msi /qnUninstall:
msiexec /x ComingUpNextTray-1.0.0.msi /qnIf you modify published output location or add resources, re-run the build script to regenerate harvested components.
This repository includes two small CLI tools under the tools/ folder useful for debugging and reproducing the app's behavior against .ics feeds.
-
CalendarInspector (
tools/CalendarInspector)- Purpose: Download or read an ICS payload and print diagnostic information including raw
VEVENTblocks, parsed entries and a recurrence expansion log. Useful to inspect what the parser actually sees and how recurrences expand. - Usage (download a URL or read a file):
# URL (will attempt to GET the feed) dotnet run --project "tools\CalendarInspector\CalendarInspector.csproj" "https://example.com/calendar.ics" # Local file dotnet run --project "tools\CalendarInspector\CalendarInspector.csproj" "C:\path\to\calendar.ics"
- Notes: The inspector prints raw VEVENT blocks and a summary of parsed entries; it does not apply the app's next-meeting selection rules (it's focused on parsing diagnostics).
- Purpose: Download or read an ICS payload and print diagnostic information including raw
-
NextMeetingInspector (
tools/NextMeetingInspector)- Purpose: Mimics the tray application's selection logic and prints the single next meeting chosen by the app. It reuses
CalendarServiceandNextMeetingSelectorso behavior should match the running tray app closely. - Usage (URL-only):
dotnet run --project "tools\NextMeetingInspector\NextMeetingInspector.csproj" "https://example.com/calendar.ics" [ignoreFreeOrFollowing:true|false]
- The
ignoreFreeOrFollowingflag is optional and defaults totrue(matches the app's default behavior).
- The
- Notes and troubleshooting:
- The tool expects an absolute
httporhttpsURL. It uses the same HTTP fetch logic as the tray app (conditional requests, ETag/Last-Modified handling) where applicable. - Some calendar providers (Exchange/Office365) may require a public/share link or authentication; if you get
HTTP 401/403orHTTP 400, verify the URL is a public ICS export link or supply an appropriate authenticated feed. - The tool injects a browser-like
User-Agentheader to improve compatibility with servers that reject non-browser clients.
- The tool expects an absolute
- Purpose: Mimics the tray application's selection logic and prints the single next meeting chosen by the app. It reuses
Create a shortcut to the published EXE in:
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup
- Add Windows Toast notifications using Windows App SDK for richer UX
- Optional filtering (e.g. ignore all-day events or past events spanning multiple days)
See LICENSE.


