Calendar
Your agenda from Google Calendar — today, the next three days, or the week, depending on how big you make it. Next-meeting countdown, one-click join, and on Pro, an AI-written brief.
Open a new tab, see what's next. The Calendar widget shows your 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. How far ahead it looks depends on how big you make it.
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.
The horizon follows the size
Rather than a setting you'd never revisit, the widget reads its own width and picks the sensible window:
- Small (roughly square) — today's agenda, nothing else. The classic at-a-glance card.
- Medium — today plus the next two days, grouped under day headers, so Friday afternoon shows you Monday morning.
- Wide — the full week ahead. Empty days are skipped rather than rendered as blank headers.
Resize the widget and the horizon updates immediately — no reload, no setting to find.
How the data flows
- One API call per window. The widget fetches
/calendars/primary/eventswith a time window matching its current horizon 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 / Around 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. - The window is local. The widget uses your machine's timezone for the date 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 includes them in the list. (The italic titles you may notice are tentative RSVPs, regardless of this setting.) | 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.