Calendar
Today's agenda from Google Calendar — next-meeting countdown, one-click join, and on Pro, an AI-written brief that ties the next meeting to your recent PRs and Linear issues.
Open a new tab, see what's next. The Calendar widget shows your day's events from Google Calendar with a live countdown to the next meeting, one-click join buttons for Meet / Zoom / Teams parsed from the event description, and on Pro a one-sentence AI brief tying the meeting to the PRs and issues it likely concerns.
Sarah is reviewing the billing refactor — waiting on your sign-off before the migration.
- 11:00 am Standup
- 2:00 pm PR review with Sarah
- 3:30 pm Design sync
- 4:30 pm 1:1 with Maria
Connect Google Calendar
Drop the widget in and you'll see a Connect Google Calendar
button. Click it once — butter walks you through Google's OAuth flow with
the calendar.readonly scope, and you're done. You don't
register your own Google Cloud project; a small butter-operated worker
holds the client secret so you don't have to.
Where the token lives: the worker brokers the handshake, then hands the
access token (and refresh token) to your browser and forgets it — no
persistent storage on our side. From there the token sits in
chrome.storage.local on your device, and every API call goes
directly from your browser to googleapis.com. We don't see
what's on your calendar.
To disconnect, revoke the connection from your Google account permissions — the widget will catch the next 401 and show a Reconnect pill at the top of the card.
Note that "Connect Google Calendar" is a separate consent from "Sign in to butter with Google." Sign-in only asks for your email and profile — never your calendar. Granting calendar access is an explicit second step on the widget itself.
Add it to your dashboard
Press E to enter edit mode, A to add, pick Calendar. It drops in at four-wide, five-tall — enough height for the next-up card plus four or five agenda rows. Drag wider if you have a busy day; shorter if you only care about the next meeting.
How the data flows
- One API call, today only. The widget fetches
/calendars/primary/eventswith a time window covering today in your local timezone, expanded into individual instances (singleEvents=true) so recurring meetings appear once each. Cancelled events, working-location events, and birthdays are filtered out client-side. - Join links are parsed from the event. The widget looks
at
conferenceDatafirst (Google's structured field), thenhangoutLink(legacy Meet), then sweeps the description and location for Zoom / Teams / Webex / Whereby URLs. First match wins. - 2-minute cache. The fetched events are cached locally
for two minutes, keyed in
chrome.storage.local. The countdown ticks live every five seconds when the next event is within two minutes, every thirty seconds otherwise — without re-hitting Google. - Today's window is local. The widget uses your machine's timezone for the today range, so a 9 PM event still counts as today even when UTC has rolled over. No timezone setting needed.
The AI brief (Pro)
On Pro the next-up card grows a one-sentence brief under the event metadata. The brief is generated by passing the event (title, description, attendees, time) plus your recent GitHub PRs and Linear issues to a Supabase Edge Function that calls an LLM. The result reads like "Sarah is reviewing the billing refactor — waiting on your sign-off before the migration." with up to three chips below linking the PRs and issues the brief references.
Things to know about the brief:
- Only the next event auto-generates. The brief runs once per upcoming event and is cached on-device for two hours, so reopening a new tab doesn't re-bill the model. Click the refresh icon on the brief to force a regeneration.
- References are sourced from your widgets. If you have the GitHub and/or Linear widgets configured, their cached data feeds the brief. If neither is connected, the brief is generated from the event alone — usually still useful for context.
- The payload is minimal. Event title, description, attendee names and emails, time window — plus the titles and identifiers of your recent PRs and issues. Never full PR diffs, never full issue bodies, never your tokens. No retention on OpenAI's side under their API terms, no training. See the privacy doc for the exact payload.
Settings
| Setting | Type | Default |
|---|---|---|
| 24-hour clock Off renders event times in 12-hour format (2:00 pm – 2:30 pm). On switches to 24-hour (14:00 – 14:30). Affects the next-event card and the agenda list. | toggle | off |
| Show declined events Off hides events you've declined — usually the right default since declined meetings are noise. On surfaces them with an italic title so they're visible but visually deprioritised. | toggle | off |
Small things you might miss
- Past events fade. Earlier events stay in the list at reduced opacity so you can see what's already happened today without them dominating the visual field.
- "Starting" beats "now". When the next event is within the last ten seconds before kickoff the countdown reads starting — a clearer cue than "now" for the drop-everything moment.
- Brief copy avoids identifier names. The brief itself says things like "the billing refactor" rather than "PR #427" — the chips below carry the identifiers, so the prose stays readable.
- One Google account at a time. The widget shows the connected account's email in the toolbar so you can confirm which Google account is feeding it. Disconnect and reconnect to switch.
Heads up
- Primary calendar only for now. The widget reads your primary Google calendar; secondary calendars (shared team calendars, a separate personal account) aren't pulled in yet.
- Google only. Outlook / Microsoft 365 support is on the list but not shipped. Apple Calendar via CalDAV isn't planned because it doesn't have a workable hosted OAuth story for an extension.
- The brief lags the data by up to two minutes. The event cache TTL is two minutes, so a meeting created just-now might not appear in the brief until the next fetch. Hit the toolbar refresh to force a re-pull.
- Token revocation is detected, not predicted. If you revoke calendar access from Google's permissions page mid-session, the widget will keep showing cached events until the next fetch attempt — at which point it'll catch the 401 and switch to Reconnect.