Design Decisions
Event Tags via Shared Extended Properties
Google Calendar API offers extendedProperties on events for storing custom key-value metadata. There are two scopes:
private— scoped to the OAuth client ID that created them. Only the same client ID can read them back.shared— visible to anyone with access to the event (all attendees, all apps, including public calendar readers via the API).
Why shared?
We chose shared extended properties for the following reasons:
-
Data durability —
privateproperties are tied to the OAuth client ID incredentials.json. If you ever recreate your OAuth credentials in Google Cloud Console (new project, deleted and re-created client ID, etc.), allprivateextended properties become permanently inaccessible. The data isn’t deleted, but there is no way to recover it with a different client ID. Withshared, the data belongs to the event itself and survives credential changes. -
Acceptable visibility tradeoff —
sharedproperties are visible via the API to anyone who can read the event. On public calendars, this means anyone querying the API could see the tags. However, extended properties are not displayed in the Google Calendar web or mobile UI — they are only accessible programmatically. For a personal CLI tool, this is an acceptable tradeoff. -
Interoperability —
sharedproperties can be read and written by any tool or script with access to the calendar, not just rscalendar. This makes it possible to build other tools that interact with the same tags.
Implementation Plan
Tags will be stored as a comma-separated string under a single key in shared extended properties:
{
"extendedProperties": {
"shared": {
"tags": "work,urgent,followup"
}
}
}
The Google Calendar API supports filtering events by extended properties using the sharedExtendedProperty query parameter, enabling efficient tag-based queries without client-side filtering.
Deleting Extended Properties
Google Calendar API does not remove an extended property when you simply omit it from a PATCH request. To delete a property, you must explicitly set its value to null:
{
"extendedProperties": {
"shared": {
"key_to_delete": null
}
}
}
This is handled automatically by rscalendar properties delete.