birthday-reminder-gcal
Calendar-driven birthday reminder. Reads today's events from your Google Calendar, filters by a configurable title prefix (default Birthday:), and sends a single summary message to the owner once a day. Generalizes to any annual milestone — change the prefix to Anniversary: for wedding anniversaries, Work: for hire-date check-ins, Holiday: for personal observances, anything.
Why Calendar-driven, not Contacts-driven
The cleaner design would be to read birthdays straight from Google Contacts via the People API. That doesn't work today: gog (v0.19.0) does NOT surface the birthdays field on any of contacts list, contacts get, or people get (verified — --select "birthdays,..." returns {} even with the People API enabled in the GCP project). The auto-populated "Birthdays" sub-calendar Google can build from Contacts is also not reachable via gog (addressbook#[email protected] returns unrecognized calendar name).
Calendar events you create yourself ARE first-class. So this workflow uses that pattern. The bonus: the same workflow handles every other kind of annual reminder without modification — just change the prefix.
Use case
You forget birthdays. You feel terrible when you do. Setting a daily morning ping that reads "Today is Mom's birthday" buys you back the relationships dental-appointment automation already buys you back.
This is the personal-use cousin of appointment-reminder-gcal — same Calendar-reading pattern, different goal (reminding yourself vs reminding customers).
Setup
- Credentials (Credentials view):
-
google-workspace— Google Workspace service-account JSON - Runtime environment (Runtime Environments view):
-
python— auto-created on every OS install - Calendar events — for each birthday/anniversary you want remembered, add an annual recurring all-day event to any calendar you own, with the title prefixed by your chosen tag:
Birthday: Mom Birthday: Dad Birthday: Sarah K. Birthday: Mike (work) Anniversary: Jane & JohnSet each to repeat yearly. The workflow ignores the year and reads month/day. - Edit
workflow.yaml— replace the three placeholders: -<<CALENDAR_ID>>—primaryfor your main calendar, or any calendar ID you own -<<BIRTHDAY_PREFIX>>—Birthday:(default), orAnniversary:,Holiday:,🎂, etc. Match the prefix you use in event titles. Case-insensitive. -<<OWNER_PUBLISHER>>— user name linked to your contact (email, SMS, Slack, etc.) - Schedule the workflow once daily at 8:00 AM (or whenever you read your morning notifications).
Pipeline
- find-today —
runtimeenv(python). Queries Calendar for today's events viagog calendar events --today, filters events whose title starts with the configured prefix (case-insensitive), extracts the name from each (Birthday: Sarah K.→Sarah K.), and prints a formatted summary. Empty days print "No 'Birthday:' events today" and exit cleanly. - notify —
message. Pipes the summary to the owner contact.
Sample output
Today is Friday, May 14, 2026.
2 people to remember:
- Mom
- Sarah K.
Reach out — a 30-second message lands harder than you'd think.
Customization
- Multiple categories in one workflow — change the filter from a single prefix to a list. The script's
prefix_lcheck can become anany(title.lower().startswith(p) for p in PREFIXES). One daily reminder covers birthdays + anniversaries + work milestones. - N days ahead — change
--todayto--days 7to look a week out (gives you lead time to send a card). Update the summary text to reflect. - Auto-send greeting to the person — if the calendar event has an attendee with an email, the script captures it (see the
attendeesfield in the matches). Add agog gmail send --to <addr> --subject "..." --body "..."call inside the match loop. Caveat: many people put their own attendees on these events; that's themselves, not the celebrant. Test before broadcasting. - Different calendar per category — duplicate the workflow, point each copy at a different calendar ID and prefix. Keeps work birthdays separate from family ones.
- Tone — edit the closing line in the script. Examples: drop it entirely; add
"Cake suggestion: ..."with an AI step; pull a memory from a notes Sheet about the person. - Year-by-year deduplication — the current workflow has no state; running it twice in a day produces two notifications. Add a Sheet-based last-seen tracker (
event_id | year_notified) if that matters. Most users just schedule it once daily and accept the trade-off.
Companion patterns
appointment-reminder-gcal— same Calendar-reading pattern for customer appointments- Make a copy of this workflow called
anniversary-reminder-gcal(prefixAnniversary:) - Make a copy called
work-milestone-gcal(prefixWork milestone:) for hire-date anniversaries
Verified
gog calendar events --today --cal <id> shape verified against the real Workspace account (2026-05-10): events return id, summary, start, attendees. The "no birthdays via People API in gog" gap was confirmed by direct testing — contacts list, contacts get, people get, and --select "birthdays" all return field sets without birthday data. That gap is the reason this workflow is Calendar-driven rather than Contacts-driven.
Source
See workflow.yaml.