A native macOS menu bar app that fetches events from all your Google Calendars and posts a formatted weekly schedule to Notion and/or Obsidian β automatically every Sunday night, or on demand.
|
Hover to open |
Preview & edit events |
Posted to Notion |
- ποΈ Hover over the menu bar icon β events load instantly from cache
- π Fetches 1 week by default; modify to 1β4 weeks inline
- βοΈ Preview and edit events before posting
- π Posts a beautifully formatted day-by-day table to Notion
- π Obsidian support β sync to your Obsidian vault via Local REST API plugin
- π Sync target selector β choose Notion, Obsidian, or Both in Settings
- π Auto-runs every Sunday at 9 PM via launchd
- βοΈ Email notification on every post (manual and autorun)
- πΎ Persists posted state across relaunches β shows "Open in Notion" or "Open in Obsidian" when already posted
- β¨ Autorun banner shows when the Sunday sync has fired
β οΈ Warns if a page for that date range already exists
brew tap dkeg/cal-bridge
brew install --cask cal-bridgeThen run the setup script:
./scripts/install.sh- Download the latest
CalBridge.dmgfrom Releases - Open the DMG, drag
CalBridge.appto/Applications - Clone this repo and run the setup script:
git clone https://github.com/dkeg/cal-bridge.git
cd cal-bridge
chmod +x scripts/install.sh
./scripts/install.sh- macOS 13+
- Node.js 18+ (
brew install node) - A Google account
- A Notion account and/or Obsidian with the Local REST API plugin
- A Resend account (free tier, for email notifications)
CalBridge includes a built-in setup flow β no terminal or config file editing required.
- Launch
CalBridge.appfrom/Applications - The setup window appears automatically on first launch
- Click Connect with Google β your browser opens for OAuth authorization
- Authorize access to Google Calendar
- Return to the app β it captures the token automatically
- Enter your Notion integration token (get it at notion.so/my-integrations)
- Click Finish Setup
Your credentials are stored securely in macOS Keychain β no .env editing needed.
- Go to notion.so/my-integrations
- Create a new integration β copy the Integration Token
- Open the Notion page you want to post under
- Click
Β·Β·Β·β Connections β connect your integration
- Install the Local REST API plugin in Obsidian
- Copy the API key from the plugin settings
- Enter it in Settings β Configuration β Obsidian API Key
- Set your vault path and target folder
- Sign up at resend.com
- Copy your API Key from the dashboard
- Enter it in Settings β Configuration β Resend API Key
- Launch
CalBridge.appfrom/Applications - Hover over the calendar icon β events load instantly
- Optionally click Modify to change the number of weeks (1β4)
- Toggle calendars on/off, edit or remove individual events
- Click Post to Notion β, Post to Obsidian β, or Post to Both β depending on your sync target
- Button changes to Open in Notion or Open in Obsidian once posted β persists across relaunches
- Change sync target anytime in Settings β General
The app runs automatically every Sunday at 9 PM via a launchd agent. After firing it:
- Writes a flag file to
~/Library/Application Support/CalBridge/last-run.json - Sends an email notification to your configured address
- Shows an "Auto-synced" banner the next time you open the popover
To set up or recreate the launchd agent:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.drewcraig.cal-bridge-autorun.plistTo test manually:
node ~/Projects/cal-bridge/backend/dist/autorun.js# Clone
git clone https://github.com/dkeg/cal-bridge.git
cd cal-bridge
# Backend
cd backend
cp .env.example .env
# fill in credentials
npm install
npx ts-node auth.ts # get Google refresh token
npm start # runs on localhost:8420
# Compile autorun
npx tsc agent.ts autorun.ts --outDir dist --esModuleInterop --resolveJsonModule --module commonjs --target es2020
# Swift app
open CalNotionBar/CalNotionBar.xcodeproj
# Build and run in Xcode (βR)git tag v1.2.0
git push origin v1.2.0GitHub Actions will automatically build the .dmg and create a release.
CalBridge.app (Swift/SwiftUI)
βββ spawns β backend (Express + TypeScript) on localhost:8420
βββ /calendars β Google Calendar API
βββ /events β Google Calendar API
βββ /today β Google Calendar API (badge count)
βββ /notion β Notion API + Resend email
βββ /obsidian β Obsidian Local REST API
launchd agent (Sunday 9 PM)
βββ dist/autorun.js
βββ reads sync target from app plist
βββ fetches 1 week of events
βββ posts to Notion and/or Obsidian
βββ sends email via Resend
βββ writes ~/Library/Application Support/CalBridge/last-run.json
| Variable | Description |
|---|---|
GOOGLE_CLIENT_ID |
Google OAuth client ID (Desktop app type) |
GOOGLE_CLIENT_SECRET |
Google OAuth client secret |
GOOGLE_REFRESH_TOKEN |
Long-lived refresh token (from auth.ts or in-app setup) |
NOTION_API_KEY |
Notion integration token |
NOTION_PARENT_PAGE_ID |
ID of the parent Notion page |
RESEND_API_KEY |
Resend API key for email notifications |
RESEND_FROM |
Sender address once your domain is verified (default: onboarding@resend.dev) |
PORT |
Backend port (default: 8420) |
MIT