Calendar — butter docs Skip to content
Widgets / The day

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.

Free (agenda) Pro (AI brief) Requires Google Calendar OAuth 2-minute cache
Calendar
Next
PR review with Sarah
in 14 min · 2:00 – 2:30 pm
Join Meet

Sarah is reviewing the billing refactor — waiting on your sign-off before the migration.

PR #427 — refactor billing ALG-892 — Subscription v3
  • 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/events with 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 conferenceData first (Google's structured field), then hangoutLink (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.