A macOS menubar app that syncs your Granola meeting notes to a local folder as Markdown files.
- Auto-sync when meetings end (watches Granola cache for changes)
- One-click sync from the menubar
- Recent Notes submenu for quick access to last 5 synced notes
- Clickable notifications - click to open the synced note
- Action items extraction - automatically finds TODOs, ACTION items, FOLLOW UPs
- Sync stats - shows meeting count and last sync time in menu
- Obsidian integration - AI-powered organization into your vault (optional)
- Exports notes, transcripts, and metadata (attendees, timestamps, meeting links)
- Markdown files with YAML frontmatter for easy searching/indexing
- Auto-start at login via launchd
git clone https://github.com/kllymx/Breakfast.git
cd Breakfast
chmod +x install.sh
./install.shThis will:
- Create a Python virtual environment
- Install dependencies (rumps, pyobjc)
- Configure auto-start at login
- Launch the menubar app
Look for the icon in your menubar:
| Menu Item | Action |
|---|---|
| Sync Now | Sync all new meetings |
| Sync Last 7 Days | Re-sync recent meetings (overwrites) |
| Recent Notes | Quick access to last 5 synced notes |
| Open Notes Folder | Opens the output directory |
| X meetings synced | Total meeting count |
| Last sync: Xm ago | Time since last sync |
| View Log | Opens sync log in Console |
node index.js # Sync all meetings
node index.js --days 7 # Sync last 7 days
node index.js --force # Force overwrite existing files
node index.js --verbose # Verbose outputSet GRANOLA_OUTPUT_DIR environment variable to change where notes are saved:
export GRANOLA_OUTPUT_DIR="$HOME/Notes/Meetings"Default: ~/Documents/Granola Notes
The install script configures launchd to auto-start the app at login. Launchd manages the process—don't manually start the app when launchd is active, or you'll get duplicate icons.
# Stop the app
launchctl unload ~/Library/LaunchAgents/com.arcane.granola-sync.plist
# Start the app
launchctl load ~/Library/LaunchAgents/com.arcane.granola-sync.plist
# Restart (after config changes)
launchctl unload ~/Library/LaunchAgents/com.arcane.granola-sync.plist
launchctl load ~/Library/LaunchAgents/com.arcane.granola-sync.plistlaunchctl unload ~/Library/LaunchAgents/com.arcane.granola-sync.plist
rm ~/Library/LaunchAgents/com.arcane.granola-sync.plistEach meeting exports as YYYY-MM-DD-meeting-title.md:
---
id: abc123
title: "Weekly Standup"
created_at: 2025-01-03T10:00:00Z
meeting_start: 2025-01-03T10:00:00-05:00
meeting_end: 2025-01-03T10:30:00-05:00
attendees: ["alice@example.com", "bob@example.com"]
---
# Weekly Standup
**Start:** Friday, January 3, 2025 at 10:00 AM
**Duration:** 30 minutes
---
## Attendees
- Alice <alice@example.com> (organizer)
- Bob <bob@example.com>
---
## Notes
Discussion points from the meeting...
---
## Transcript
**Me** [10:01:05 AM]: Let's get started...
**Speaker** [10:01:10 AM]: Sounds good...- macOS
- Node.js (for sync script)
- Python 3 (for menubar app)
- Granola desktop app
Use Claude Code to automatically organize notes into your Obsidian vault with proper links, tags, and folder structure.
- Claude Code CLI installed and authenticated
- An Obsidian vault
-
Copy the example config:
cp config.example.json config.json
-
Edit
config.json:{ "obsidian": { "enabled": true, "vault_path": "~/Documents/YourVault", "meetings_folder": "Meetings", "auto_import": false, "claude_instructions": "Your instructions here..." } } -
Customize
claude_instructionsfor your vault structure. The example config includes a full template with:- Client identification from email domains
- Client file creation/linking
- Meeting note template with frontmatter, wiki links, action items
- Full transcript preservation
See
config.example.jsonfor the complete template you can customize.
| Menu Item | Description |
|---|---|
| Import to Obsidian | Import new notes in background (uses manifest to skip already-imported) |
| Force Re-import All (Live) | Opens Terminal with Claude Code UI to process all notes interactively |
| Open Obsidian Vault | Opens your vault folder |
- Import to Obsidian: Runs headlessly in background, processes one note at a time, tracks imported notes in
.breakfast-imported.jsonmanifest - Force Re-import All (Live): Opens a single Claude Code session that scans all notes and processes them—you can watch Claude work in real-time
node obsidian-import.js # Import new notes (headless)
node obsidian-import.js --force # Re-import all notes
node obsidian-import.js --dry-run # Preview what would import
node obsidian-import.js --live # Interactive mode (shows Claude UI)Granola stores meeting data locally at ~/Library/Application Support/Granola/cache-v3.json. This tool reads that cache and exports meetings as Markdown files.
Transcripts: Since Granola stores transcripts on their servers (not locally), we fetch them via Granola's API using your existing auth token from ~/Library/Application Support/Granola/supabase.json. This is created automatically when you log into Granola — no additional setup required.
MIT