Calendar Agent¶
easybar-calendar-agent owns EventKit.
It is responsible for:
- requesting calendar access
- observing changes
- building normalized snapshots
- grouping popup sections
- handling event mutations
- pushing updates to subscribers
Requests¶
{
"requestID": "month-42",
"command": "ping | version | fetch | subscribe | logs | create_event | update_event | delete_event",
"query": {
"startDate": "2026-03-29T00:00:00Z",
"endDate": "2026-04-01T00:00:00Z"
}
}
Notes:
requestIDis optional and is echoed by every direct response for request correlationqueryis required forfetchandsubscribe- date range is inclusive/exclusive, must be forward and finite, and may span at most 366 days
- section counts, filter arrays, text, identifiers, alerts, and mutation durations are bounded before EventKit work begins
- filters are applied server-side to regular and birthday calendars
Responses¶
{
"kind": "snapshot",
"requestID": "month-42",
"snapshot": { ... }
}
Other kinds:
pongversionsubscribedlog_subscribedlog_recordcreatedupdateddeletederror
Errors include a stable errorCode and a human-readable message:
{
"kind": "error",
"errorCode": "invalid_request",
"message": "The calendar date range exceeds the supported maximum."
}
invalid_request means the request itself is unsupported and retrying the same payload cannot
succeed. Other error codes describe permission, event lookup, writable-calendar, or mutation
failures.
Snapshot¶
{
"accessGranted": true,
"permissionState": "authorized",
"generatedAt": "2026-03-29T12:34:56Z",
"events": [],
"sections": []
}
Event fields¶
idtitlestartDateendDateisAllDaycalendarNamecalendarColorHexlocationurl(direct EventKit URL, or the first URL EasyBar can extract from location or notes)isHolidayhasAlerttravelTimeSeconds
Behavior notes¶
- the month client derives its preload radius from the shared 366-day request limit instead of using a hard-coded radius
- EasyBar assigns request identifiers to subscriptions and ignores delayed direct responses that belong to an older request; unsolicited broadcast snapshots intentionally omit an identifier
- no access returns an empty snapshot
- birthdays are separated and use the same calendar filters as regular events
- occurrence ids are deterministic even when EventKit omits an event identifier
- relative and absolute alarms are normalized into visible lead times
- sections are optional, day-bucketed once, and clamp multi-day display times to each section day
- EasyBar treats
invalid_requestas permanent for the exact rejected subscription: it logs the rejection once, suspends reconnects, and retains the last valid snapshot - when the subscription request or socket configuration changes, EasyBar clears the permanent block and reconnects immediately
Event travel-time bridge¶
EventKit does not expose a public, typed API for reading or writing an event's native travel-time
value. EasyBar therefore accesses the runtime travelTime property through
EventKitTravelTimeAdapter, with the dynamic Objective-C work isolated in
CEasyBarEventKitCompat.
The Objective-C boundary is intentional:
- KVC access can raise an Objective-C exception, which Swift
do/catchcannot catch. - the bridge checks that the runtime getter or setter exists before using it
- Objective-C catches any KVC exception and reports failure to Swift instead of crashing the agent
- the Swift adapter rejects non-finite, negative, zero-on-read, or excessively large values
A pure Swift KVC implementation might work on the current EventKit implementation, but it would lose the exception boundary. Calling the Objective-C method implementation directly from Swift would instead introduce unsafe runtime calling conventions and would still not catch Objective-C exceptions.
The bridge is a separate Swift Package Manager target because a target cannot mix Swift and Objective-C sources. It can be removed if travel-time support is removed, or if EventKit gains a public typed API that covers both reading and writing the native value.
Boundary¶
The calendar agent collects calendar data and performs calendar mutations.
EasyBar decides how calendar data is rendered.