Summary
Add integration with Granola for syncing meeting notes to local markdown files.
Prerequisites
Research Findings (Feb 2026)
API Status
Granola does not offer a public API. Integration uses local auth tokens + reverse-engineered endpoints.
Reference Implementation
The Granola-to-Obsidian plugin provides a complete working example.
Technical Details
Authentication:
- Read WorkOS tokens from
~/Library/Application Support/Granola/supabase.json (macOS)
- Tokens use OAuth 2.0 with single-use rotating refresh tokens
- Each token refresh invalidates the previous token
API Endpoints:
POST https://api.granola.ai/v2/get-documents # List documents (paginated)
POST https://api.granola.ai/v1/get-document-transcript # Get transcript
POST https://api.granola.ai/v1/get-documents-batch # Batch fetch by IDs
POST https://api.granola.ai/v2/get-document-lists # List folders
POST https://api.granola.ai/v1/get-workspaces # List workspaces
Content Format:
- Granola uses ProseMirror internally (same as PM Toolkit's Tiptap!)
- Can convert directly between formats or serialize to Markdown
Implementation Plan
Phase 1: Core Infrastructure
1.1 Granola Detection
1.2 Token Management
1.3 API Client
Phase 2: Content Sync
2.1 Document Conversion
2.2 File Management
2.3 Sync Operations
Phase 3: Auto-Sync & Watching
3.1 Scheduled Sync
3.2 File Watching (Optional)
Phase 4: Settings UI
Add "Granola" section to PM Toolkit Settings panel:
Connection
Sync Settings
Content Settings
File Organization
Filtering
Advanced
Settings Schema
{
"pmtoolkit.granola.enabled": false,
"pmtoolkit.granola.syncDirectory": "Granola",
"pmtoolkit.granola.autoSyncFrequency": 300000,
"pmtoolkit.granola.filenameTemplate": "{created_date}_{title}",
"pmtoolkit.granola.dateFormat": "YYYY-MM-DD",
"pmtoolkit.granola.includeTranscript": false,
"pmtoolkit.granola.includeMyNotes": true,
"pmtoolkit.granola.includeEnhancedNotes": true,
"pmtoolkit.granola.enableDateFolders": false,
"pmtoolkit.granola.enableGranolaFolders": false,
"pmtoolkit.granola.documentSyncLimit": 100,
"pmtoolkit.granola.syncAllHistorical": false,
"pmtoolkit.granola.selectedFolders": [],
"pmtoolkit.granola.existingFileAction": "skip"
}
File Structure
src/
├── granola/
│ ├── index.ts # Exports
│ ├── TokenManager.ts # Auth token handling
│ ├── GranolaClient.ts # API client
│ ├── ContentConverter.ts # ProseMirror → Markdown
│ ├── SyncManager.ts # File sync orchestration
│ └── types.ts # Granola data types
Commands
| Command |
Description |
pmtoolkit.syncGranola |
Manually trigger Granola sync |
pmtoolkit.openGranolaSettings |
Jump to Granola section in settings |
Status Bar
When Granola is enabled, show status in bottom bar:
$(sync~spin) Syncing Granola... - during sync
$(check) Granola: 5 synced - after successful sync (3s)
$(error) Granola: Error - on failure
$(cloud) Granola - idle (clickable to sync)
Error Handling
| Error |
User Message |
Action |
| Auth file not found |
"Granola not installed or not signed in" |
Show setup instructions |
| Token expired |
"Granola session expired" |
Prompt to open Granola app |
| API error |
"Granola sync failed: {error}" |
Retry with backoff |
| Network error |
"Unable to reach Granola servers" |
Queue for retry |
Testing
Risks & Mitigations
| Risk |
Mitigation |
| API changes break sync |
Version detection, graceful degradation |
| Token rotation fails |
Clear guidance to re-auth via Granola app |
| Large sync overwhelms system |
Pagination, progress indicator, cancellation |
| Conflicts with existing files |
Configurable behavior, never overwrite without consent |
Sources
Summary
Add integration with Granola for syncing meeting notes to local markdown files.
Prerequisites
Research Findings (Feb 2026)
API Status
Granola does not offer a public API. Integration uses local auth tokens + reverse-engineered endpoints.
Reference Implementation
The Granola-to-Obsidian plugin provides a complete working example.
Technical Details
Authentication:
~/Library/Application Support/Granola/supabase.json(macOS)API Endpoints:
Content Format:
Implementation Plan
Phase 1: Core Infrastructure
1.1 Granola Detection
supabase.json)1.2 Token Management
src/granola/TokenManager.ts1.3 API Client
src/granola/GranolaClient.tsgetDocuments()with paginationgetDocumentTranscript()getDocumentsBatch()getFolders()getWorkspaces()Phase 2: Content Sync
2.1 Document Conversion
src/granola/ContentConverter.tsgranola_id2.2 File Management
src/granola/SyncManager.tsgranola_idfrontmatter2.3 Sync Operations
pmtoolkit.syncGranolaPhase 3: Auto-Sync & Watching
3.1 Scheduled Sync
3.2 File Watching (Optional)
Phase 4: Settings UI
Add "Granola" section to PM Toolkit Settings panel:
Connection
Sync Settings
Content Settings
File Organization
{title},{created_date},{id}Filtering
Advanced
Settings Schema
{ "pmtoolkit.granola.enabled": false, "pmtoolkit.granola.syncDirectory": "Granola", "pmtoolkit.granola.autoSyncFrequency": 300000, "pmtoolkit.granola.filenameTemplate": "{created_date}_{title}", "pmtoolkit.granola.dateFormat": "YYYY-MM-DD", "pmtoolkit.granola.includeTranscript": false, "pmtoolkit.granola.includeMyNotes": true, "pmtoolkit.granola.includeEnhancedNotes": true, "pmtoolkit.granola.enableDateFolders": false, "pmtoolkit.granola.enableGranolaFolders": false, "pmtoolkit.granola.documentSyncLimit": 100, "pmtoolkit.granola.syncAllHistorical": false, "pmtoolkit.granola.selectedFolders": [], "pmtoolkit.granola.existingFileAction": "skip" }File Structure
Commands
pmtoolkit.syncGranolapmtoolkit.openGranolaSettingsStatus Bar
When Granola is enabled, show status in bottom bar:
$(sync~spin) Syncing Granola...- during sync$(check) Granola: 5 synced- after successful sync (3s)$(error) Granola: Error- on failure$(cloud) Granola- idle (clickable to sync)Error Handling
Testing
Risks & Mitigations
Sources