Skip to content

Repository files navigation

Glance in the macOS menu bar, showing today's agenda

Glance

Your day, in the menu bar.

A small native macOS app that shows your Google Calendar agenda without opening a browser tab, a calendar app, or anything else.

macOS 14+ Swift 6 SwiftUI No dependencies MIT


A day passing in Glance: the now-line descends, finished events dim, the countdown shrinks

A day passing. The line marks now, finished events dim behind it, and the menu bar counts down to whatever is next.

What it does

  • Today's agenda in one click — times, titles, calendar colours, and a line marking where you are in the day. Finished events stay on screen, dimmed, because "nothing left today" is accurate and useless at 23:45.
  • Your next commitment, always visible — the menu bar counts down to it, so most of the time you never open the panel at all.
  • This week in a small window — seven days, multi-day events repeated on every day they span, empty days kept so it reads as a calendar rather than a list.
  • Join the call from the menu bar — Meet, Teams, Zoom, Webex, Whereby and Jitsi links are pulled out of the invite, so the meeting is one click from the countdown.
  • Only the calendars you want — hide the ones you do not, per calendar, across every account macOS has.

Deliberately not a calendar client. No editing, no month grid, no inbox.

Screens

Light Dark
Today
This week
Settings

Every image above is rendered from a synthetic fixture, never from a real account — Glance's UI is someone's appointments, so publishing a screenshot of it would publish their day. See DemoData.swift.

Install

Important

Glance is signed with a self-signed certificate, not notarized. macOS blocks a downloaded build outright on first launch, usually claiming the app is damaged. It is not — that is what an un-notarized app looks like to Gatekeeper.

Download Glance-<version>.zip from Releases, unzip, move to /Applications, then run this before first launch:

xattr -dr com.apple.quarantine /Applications/Glance.app
open /Applications/Glance.app

Right-click → Open also works on some macOS versions, but recent ones have stopped offering it for unsigned apps, so the command above is the reliable route.

Building from source avoids all of this — a locally built bundle never gets a quarantine attribute, so Gatekeeper never engages. It is the recommended path until there is a Developer ID to notarize with.

Setup

Three one-time steps. Full detail in docs/SETUP.md.

1. Connect Google to macOS. System Settings → Internet Accounts → Google → enable Calendars. macOS runs the sync; Glance reads the result.

2. Tick your calendars at syncselect, then restart the sync agent.

killall CalendarAgent    # relaunches on demand; safe

Google's CalDAV bridge only sends calendars selected on that page, and it defaults to your primary one. The second half matters as much as the first: macOS picks up new events within minutes but does not promptly re-read the list of calendars, so without the restart the fix looks like it did nothing. This cost a full day to work out.

3. Create a self-signed code-signing certificate — otherwise the calendar permission prompt returns after every rebuild, because macOS keys the grant to the signature.

Check what actually arrived:

open -n Glance.app --args --scan-dump && sleep 6 && head -20 "$TMPDIR/glance-scan.log"

Build

No Xcode required — Command Line Tools are enough. The build never calls xcodebuild.

./build.sh              # release build → Glance.app
./build.sh --dist       # + dist/Glance-<version>.zip
./run.sh --verify       # launch and confirm it started
./Tools/make-icon.sh    # regenerate AppIcon.icns from IconView.swift

Glance is menu-bar-only (LSUIElement), so there is no Dock icon and no window. Look in the menu bar; pgrep -x Glance is the only programmatic proof it is running.

Verifying without a GUI

An app with no window is hard to test by looking at it, so it explains itself instead:

./Glance.app/Contents/MacOS/Glance --selftest              # 83 checks, no permissions
open -n Glance.app --args --scan-dump                      # real calendar read
open -n Glance.app --args --scan-dump --probe-links        # where conference links live
.build/release/Glance --render-ui out/                     # UI in all four appearances

--selftest covers countdown formatting, day grouping, midnight and timezone rollover, calendar filtering — and the contrast budget: every foreground/background pairing the UI renders is checked against WCAG AA in light, dark, and both Increase Contrast variants. A colour change that fails contrast fails the build.

--scan-dump must go through open. macOS attributes a permission request to the responsible process, so a binary run from a terminal is judged against Terminal's grant: access reads notDetermined and the request returns instantly without prompting or erroring.

How it works

Glance reads calendars through EventKit, so macOS runs the Google sync and Glance renders the result. No OAuth, no tokens, no polling loop, no Google Cloud project — and events update live through EKEventStoreChanged.

CalendarService ──► GlanceStore ──► views
   (actor)         (@MainActor)

CalendarService is the only file that imports EventKit, and it is an actor because EKEventStore is not Sendable. Everything crossing out of it is a Sendable value type, so no EventKit object ever reaches a view. Source is flat in Sources/Glance/.

The trade is that EventKit cannot see some Google-specific extras: no per-event colours, and RSVP is permanently read-only. Conference links turned out not to be among them — a probe found them sitting in notes on 52 of 148 events, which retired a planned week of OAuth work and made the Join button a NSDataDetector pass instead. Glance extracts the link at the service edge and discards the notes there; meeting agendas and dial-in PINs never travel further into the app. That story is in docs/PLAN.md.

Privacy

Glance sends nothing anywhere. There is no network code in it at all — no analytics, no crash reporting, no update check. It reads the calendar database macOS already maintains, and that is the whole of its I/O.

The one thing it writes is ~/Library/Preferences/space.godev.Glance.plist: which calendars you have hidden, and whether past events stay on screen.

Status

All eight phases shipped. It reads every calendar, survives midnight and timezone changes, adapts to light and dark, is accessible and localizable, and events are actionable — join the call, open it in Calendar.app, copy the link.

Current state in docs/STATUS.md, what is next in docs/TODO.md, and why any of it is the way it is in docs/PLAN.md — including the decisions not to build notifications, quick-add, or a Google API integration.

Contributing

See CONTRIBUTING.md. The short version: no dependencies without discussion, keep EventKit inside CalendarService, colours only from Palette, and --selftest has to pass.

License

MIT © 2026 Alessio Occhipinti (@LasaleFamine)

About

Your day, in the menu bar. A native macOS app that shows your Google Calendar agenda — no browser tab, no calendar app, no dependencies.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages