From e92c2ee5f9c6273a3359371fa77558e316d57db1 Mon Sep 17 00:00:00 2001 From: Gabriel Brown Date: Mon, 17 Aug 2026 11:04:05 -0400 Subject: [PATCH] Design the Panama calendar agenda --- .../2026-08-17-calendar-agenda-design.md | 261 ++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 docs/superpowers/specs/2026-08-17-calendar-agenda-design.md diff --git a/docs/superpowers/specs/2026-08-17-calendar-agenda-design.md b/docs/superpowers/specs/2026-08-17-calendar-agenda-design.md new file mode 100644 index 0000000..e904bb4 --- /dev/null +++ b/docs/superpowers/specs/2026-08-17-calendar-agenda-design.md @@ -0,0 +1,261 @@ +# Calendar Agenda design + +## Summary + +Panama will use Evolution Data Server (EDS), the same calendar backend already +used by GNOME Calendar, to turn the existing date menu into a live Daybook. The +shell will display synchronized Google, iCloud/CalDAV, Nextcloud, local, and ICS +subscription events without owning account credentials or implementing calendar +sync. + +The approved visual direction is **A · Daybook**: a 760-pixel Prism panel with a +month calendar on the left and the selected day's agenda on the right. GNOME +Calendar remains the account-management and event-editing application. + +## Goals + +- Show events from every enabled EDS calendar already visible to GNOME Calendar. +- Keep month context and the selected day's schedule visible together. +- Represent all-day, timed, recurring, and multi-day events correctly. +- Preserve the complete notification center, weather, and conditional media + controls in the date menu. +- Open events in GNOME Calendar and expose a Join action for recognized meeting + links. +- Surface upcoming events globally only when they are timely and actionable. +- Continue working from EDS's local cache while account providers are offline. + +## Non-goals + +- Panama will not store account passwords, OAuth tokens, or CalDAV credentials. +- Panama will not add, remove, or reconfigure calendar accounts. +- Panama will not create or edit events in the first release. Those actions open + GNOME Calendar. +- Panama will not implement reminders, alarms, tasks, or email invitations. +- Panama will not parse remote ICS URLs or synchronize calendar data itself. +- Wi-Fi QR sharing is no longer planned. + +## Existing system + +The workstation runs Evolution Data Server 3.60.2 and GNOME Calendar 50. EDS +currently reports ten enabled event sources backed by CalDAV, contacts, and a +local calendar. The GNOME Shell calendar service also works in the Hyprland +session and reports that calendars are available. + +Panama can therefore integrate below the GNOME Calendar user interface: + +```text +Google / iCloud / Nextcloud / ICS subscriptions + │ + ▼ + Evolution Data Server + ┌──────┴──────┐ + ▼ ▼ + GNOME Calendar Panama Daybook + manage + edit glance + launch +``` + +## Architecture + +### Calendar bridge + +Add `config/dot/quickshell/scripts/calendar-agenda`, a small Python/GObject +bridge using the installed `EDataServer` and `ECal` introspection libraries. A +native EDS client is preferred over scraping GNOME Calendar or reading source +files because it preserves recurrence, time-zone, source, and cached-sync +semantics. + +The bridge exposes three commands: + +- `probe` reports whether EDS, the source registry, and at least one enabled + event source are available. It never emits account names or event contents. +- `query START END` returns one normalized JSON snapshot and exits. It is used by + tests and as a recovery path. +- `watch START END` emits newline-delimited JSON snapshots. It refreshes when a + source changes and periodically as a defensive fallback. Restarting `watch` + with a new range is how the shell follows month navigation. + +`watch` queries enabled `E_SOURCE_EXTENSION_CALENDAR` sources, connects an +`ECal.Client` for each one, and expands recurrence instances for the requested +time range. One unavailable source does not suppress healthy sources. Refreshes +are debounced so a provider sync produces one shell update rather than a burst. + +Each snapshot has one stable contract: + +```json +{ + "ok": true, + "generatedAt": 1786978200, + "sources": [ + { + "id": "source-id", + "name": "Calendar name", + "color": "#82aaff" + } + ], + "events": [ + { + "id": "source-id:event-id:instance", + "sourceId": "source-id", + "uid": "event-id", + "summary": "Event title", + "start": 1786978200, + "end": 1786980000, + "allDay": false, + "location": "", + "joinUrl": "" + } + ], + "errors": [] +} +``` + +Source and event identifiers remain local. Descriptions and attendee lists are +not sent to Quickshell. The bridge inspects the component URL, location, and +description only to extract an HTTPS Google Meet, Zoom, Microsoft Teams, Webex, +or Jitsi URL; it does not include the original description in its output. + +### Quickshell service + +Add `services/CalendarAgenda.qml` as the single shell-facing calendar state +owner. It will: + +- Start and supervise the bridge. +- Hold normalized source and event arrays. +- Track loading, ready, degraded, and unavailable states. +- Expose events and colored day markers for a requested date or month. +- Calculate the next timed event and its relative start text. +- Open GNOME Calendar by event UUID, or by date when no event UUID exists. +- Open recognized meeting links through `xdg-open`. +- Restart the bridge when the visible month leaves the current loaded range. + +The normal range begins seven days before the visible month and ends seven days +after it. This covers all 42 calendar cells and the near-future bar capsule with +one query. + +The service refreshes when the Daybook opens, after a bridge change event, at +midnight, and every ten minutes as a fallback. It never writes event data to +Panama configuration or logs. + +## Daybook interface + +### Panel structure + +The date menu grows from 480 to 760 logical pixels and keeps the current Prism +surface, top-center anchor, type system, and open motion. + +```text +┌ Monday, August 17 ─────────────── DND · Open Calendar ┐ +│ August 2026 │ Up next · in 24 minutes │ +│ S M T W T F S │ Command Center standup Join │ +│ month grid │─────────────────────────────│ +│ colored markers │ Today · Your schedule │ +│ │ 1:00 Release planning │ +│ weather / media │ 2:30 Focus time │ +│ │ 6:30 Dinner │ +│ │ 2 notifications View │ +└─────────────────────────┴─────────────────────────────┘ +``` + +The left column is 310 pixels wide. It contains the month grid followed by the +conditional media card and weather. The right column owns either the agenda or +the full notification list. Its content scrolls independently when necessary; +the panel itself does not grow beyond the usable monitor height. + +### Calendar interaction + +- Opening from the clock selects today and shows the agenda. +- Clicking a current-month day selects it and updates the right column. +- Clicking an adjacent-month day navigates to that month and selects the day. +- Month arrows retain the selected day where possible and request a new range. +- Today uses the solid blue accent. The selected non-today date uses a restrained + accent surface. +- A day shows up to three source-colored dots. Additional events do not add more + dots. +- Calendar source names appear beside events rather than in a permanent legend, + which remains usable when more than three calendars are enabled. + +### Agenda interaction + +- The first future timed event on the selected day becomes the Up Next card. +- Up Next shows a Join action only for a recognized meeting URL. +- All-day events appear before timed events and do not become Up Next. +- Timed events are sorted by start time. Past events remain visible but dimmed. +- Each event shows its source color, time, summary, source name, and concise + location when present. +- Clicking an event opens it in GNOME Calendar with `--uuid`. +- An empty day says `Nothing scheduled` and keeps an `Open Calendar` action. +- Event titles are single-line and elide; full details belong in GNOME Calendar. + +### Notifications, media, and weather + +The notification summary appears at the bottom of the agenda only when history +is non-empty. Clicking it replaces the right column with the existing grouped +notification list. Opening the panel from the notification indicator starts in +that notification view; opening it from the clock starts in Agenda. + +Notification view keeps DND and Clear All. A `Back to agenda` action restores +the selected day without resetting the month. Existing inline replies remain +keyboard-accessible. + +The media card stays conditional and moves beneath the calendar. Weather remains +the quiet final item in the left column. Neither competes with Up Next. + +## Quiet global event capsule + +The bar does not permanently display calendar content and Panama does not emit +calendar toasts or sounds. + +A compact event capsule appears only for the next timed event: + +- fifteen minutes before its start; +- through five minutes after its start; and +- only when the event is not marked all-day. + +The capsule shows a calendar glyph and relative time, such as `12m` or `Now`. +The title stays in a tooltip to avoid exposing work details across the bar. +Clicking opens the Daybook on today. If a meeting URL exists, a small secondary +Join affordance is available inside the Daybook, not on the bar. + +The capsule uses event-driven transitions only. It has no pulse, shimmer, or +continuous animation. + +## Failure and privacy behavior + +- If one account is offline, cached events from that source remain visible when + EDS provides them; healthy sources continue normally. +- If the bridge fails, the calendar grid, notifications, media, and weather + remain usable. The agenda says `Calendar data is unavailable` and offers + `Open Calendar`. +- Malformed event fields are omitted individually rather than crashing the + service. +- Event summaries, locations, URLs, and account names are never written to shell + logs, settings, fixture files, or repository content. +- The bridge does not access EDS authentication extensions or credential stores. +- URL actions require a user click and only allow `https://` links. + +## Testing + +Focused tests will cover: + +1. The bridge's probe and normalized JSON contract without printing live event + contents. +2. Time-range filtering, ordering, all-day handling, recurrence identifiers, + meeting-link allowlisting, and malformed component handling through synthetic + local fixtures. +3. CalendarAgenda state, selected-date filtering, month marker aggregation, and + next-event timing through a deterministic fixture mode. +4. Daybook panel structure, date activation, notification-view routing, and + GNOME Calendar launch commands through contract tests. +5. A live read-only EDS smoke test that asserts enabled source and event counts + while redacting names and summaries. +6. Fresh Quickshell compilation, Hyprland configuration verification, visual + fixture screenshots, and a live panel check against the current EDS cache. + +No test creates, modifies, or deletes a real calendar event. + +## Documentation updates + +- Mark Calendar Agenda live in `config/dot/hypr/DESKTOP-PARITY.md`. +- Remove Wi-Fi QR sharing from the remaining roadmap and package guidance. +- Document GNOME Calendar as the account/editing handoff and the quiet capsule + behavior in `config/dot/hypr/README.md`.