# 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.
- Live event summaries, locations, URLs, and account names are never written to
  shell logs, settings, fixture files, or repository content. Synthetic fixture
  copy is intentionally generic.
- 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`.
