No description
  • Go 47.1%
  • QML 31.2%
  • JavaScript 21.7%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Erik Straub c71c7ecf15 fix(plugin): sort and filter the hover tooltip to real upcoming events
The bar clock hover tooltip took calendarStore.upcomingEvents.slice(0, 3),
but that property is the raw events array from the state file — source order,
unfiltered, spanning the binary's whole [now-lookbehind, now+lookahead)
window. So the tooltip showed the first three rows as written (a past
birthday and two Heartgard reminders), never the actual soonest events.

Add Model.upcomingEvents(events, todayKey, limit): keep events on today or a
later day, sort by start instant, take the limit. Day-granularity filter (not
a now-instant cutoff) so today's all-day events survive. The agenda panel
already did this via agendaDayKeys; the tooltip was the one surface that
skipped it.
2026-08-19 12:56:01 -04:00
cmd/calagenda chore: bump version to 0.2.0 2026-08-19 01:02:44 -04:00
docs/superpowers/plans Updates package publishing token 2026-08-11 01:49:26 -04:00
internal feat(expand): per-source timezone override for feeds that mislabel times 2026-08-18 23:52:16 -04:00
packaging chore: add systemd units and PKGBUILD 2026-08-10 20:43:49 -04:00
test fix(plugin): sort and filter the hover tooltip to real upcoming events 2026-08-19 12:56:01 -04:00
testdata feat(expand): per-source timezone override for feeds that mislabel times 2026-08-18 23:52:16 -04:00
.gitignore chore: gitignore local sdd workspace 2026-08-10 19:17:57 -04:00
Agenda.qml feat(plugin): cap the agenda to a scrollable compact height 2026-08-19 00:55:25 -04:00
BarWidget.qml fix(plugin): sort and filter the hover tooltip to real upcoming events 2026-08-19 12:56:01 -04:00
CalendarStore.qml fix(plugin): read the state path via paths state, not a --state flag 2026-08-19 00:45:05 -04:00
EventRow.qml feat(plugin): match agenda time format to the bar's 12/24-hour clock 2026-08-19 00:45:15 -04:00
go.mod feat: CalDAV source, re-encoding go-ical objects to shared ICS bytes 2026-08-10 20:24:48 -04:00
go.sum feat: CalDAV source, re-encoding go-ical objects to shared ICS bytes 2026-08-10 20:24:48 -04:00
manifest.json feat: settings schema for day dots/join buttons; docs 2026-08-11 01:36:07 -04:00
Model.js fix(plugin): sort and filter the hover tooltip to real upcoming events 2026-08-19 12:56:01 -04:00
Panel.qml feat(plugin): cap the agenda to a scrollable compact height 2026-08-19 00:55:25 -04:00
README.md Merge calagenda-plugin into this repo; rename identity to erik.calagenda 2026-08-18 23:58:00 -04:00
WorldClocks.qml refactor: move UTC offset parsing out of WorldClocks into Model.js 2026-08-16 17:33:10 -04:00

calagenda

An Omarchy bar widget with a real calendar agenda — plus the small CLI that feeds it, in one repo. The calagenda binary fetches events from ICS/CalDAV/file sources, expands recurrences, and writes them as JSON; the Omarchy plugin (a fork of the stock omarchy.clock) renders the agenda, day dots, day selection, meeting-join buttons, and world clocks in the bar.

They talk over a stable seam: the plugin shells out to calagenda (calagenda paths --state, calagenda sync) and watches the JSON state file. The plugin runs without the binary too — month grid, rails, and world clocks still work; only the agenda shows an install hint.

The binary

go install git.straub.dev/erik/calagenda/cmd/calagenda@latest

Under mise, register it as a tool so it survives Go upgrades:

mise use -g "go:git.straub.dev/erik/calagenda/cmd/calagenda@latest"

Configure

~/.config/calagenda/config.toml (create it mode 0600):

lookbehindDays = 1
lookaheadDays  = 30

[[sources]]
name  = "Proton"
type  = "ics"
url   = "https://calendar.proton.me/api/calendar/v1/url/<token>/calendar.ics"
color = "#8a5cf6"

[[sources]]
name     = "Work"
type     = "ics"
url      = "https://outlook.office365.com/owa/calendar/<token>/reachcalendar.ics"
color    = "#e5484d"
timezone = "America/New_York"   # optional; see below

Getting a feed URL:

  • Proton Calendar — Settings → Calendars → Share → "Share with anyone."
  • Outlook/M365 — Settings → Calendar → Shared calendars → "Publish a calendar," ICS format.
  • Google — Calendar settings → "Secret address in iCal format."
  • CalDAV (iCloud, Fastmail, Nextcloud) — use type = "caldav" with username/passwordCommand.

Per-source timezone (optional): omit it to respect what the feed declares (the default). Set it to an IANA zone (e.g. America/New_York) to force every timed event in that source into that zone, ignoring the TZID/Z the feed carries — the fix for feeds that stamp local wall-clock times as UTC. All-day events are unaffected.

Secrets never need to sit in the file: use passwordCommand = "secret-tool lookup service calagenda account work".

Run

calagenda doctor          # validate config, probe every source
calagenda sync            # fetch, expand, write ~/.local/state/calagenda/events.json
calagenda sync --stdout   # same, printed to stdout, no write
calagenda paths state     # print the state file path
calagenda paths           # print both the config and state paths
calagenda --help          # full command and flag reference

Every command accepts --config and --state to override the XDG-derived paths — useful for testing a feed without touching your real config. The plugin triggers calagenda sync on its own (throttled) while it's on the bar, so a background timer isn't required; run calagenda sync by hand or from your own systemd timer if you want refreshes without the widget loaded.

The Omarchy plugin

omarchy plugin add https://git.straub.dev/erik/calagenda.git
omarchy plugin enable erik.calagenda center

Then set up the binary above so the agenda has data.

Settings

Set via omarchy bar set erik.calagenda <key> <value> [--json], or by hand-editing this plugin's entry in ~/.config/omarchy/shell.json:

Key Default Meaning
format / formatAlt inherited from the clock bar label format; right-click cycles through built-ins plus {next}, {nextTime}, {nextIn}, {count}
agendaDays 7 how many upcoming days the agenda covers
maxAgendaEvents 12 cap on total agenda rows before the list truncates
showDayDots true small colored dots on grid days with events
showJoinButtons true one-click join for detected Meet/Zoom/Teams/Webex/Jitsi/Whereby links
worldClocks [] e.g. [{"label":"Work","tz":"America/New_York"}]

Local development

The shell's plugin watcher may not follow a symlinked plugin directory for hot-reload — if edits don't show up live, run omarchy-shell shell rescanPlugins after saving. rescanPlugins alone is not reliable for verifying changes to an already-open popup's QML content — for that, restart the shell with omarchy-restart-shell.

Run the plugin's JS unit tests with node --test test/model.test.js; the binary's tests with go test ./....