This repository contains an Obsidian plugin and two Claude Code skills that work together to bridge Granola meeting data with your personal knowledge management system.
Granola updated its local cache format from cache-v3.json to cache-v4.json with significant structural changes. This broke both the plugin and the extractor script. The following fixes have been applied:
| Component | What broke | Fix applied |
|---|---|---|
| Obsidian plugin | getGranolaCachePath() hardcoded to cache-v3.json |
Now auto-detects cache-v4.json → cache-v3.json |
| Obsidian plugin | loadGranolaCache() only handled v3's string-encoded cache |
Added v4 branch: data.cache is now a plain object with a state key |
| Obsidian plugin | extractAISummary() read from documentPanels (removed in v4) |
Falls back to notes_markdown → notes_plain → notes → placeholder |
| Obsidian plugin | Meetings with no AI summary were silently skipped | Removed the skip gate — all meetings sync, with a placeholder if no notes exist |
| Extractor script | CACHE_PATH hardcoded to cache-v3.json |
Auto-detects the latest cache-v*.json file |
| Extractor script | Only handled v3 structure | Added v4 dict structure handling |
Important cache behaviour: Granola writes cache-v4.json only on app startup — the file is not updated while the app is running. Live meeting data is stored in an encrypted OPFS database. To refresh the cache after a meeting, fully quit Granola (Cmd+Q on macOS, not just closing the window) and reopen it.
AI summary fetch: In v4, Granola stores AI-generated summaries in the cloud rather than the local cache. The plugin now calls https://api.granola.ai/v1/get-document-panels to fetch the real AI summary whenever the local cache contains no notes. It reads the WorkOS auth token automatically from ~/Library/Application Support/Granola/supabase.json — no configuration needed. If the token is expired or the API is unreachable, the placeholder text is shown as a fallback.
The Obsidian plugin syncs Granola's AI summaries into your vault as markdown files with rich YAML frontmatter (granola_id, folders, participants, etc.). These synced files become the foundation for both skills:
- Granola Search queries the synced markdown files by folder tags, title, and content.
- Granola Transcript extracts the full verbatim transcript from Granola's local cache — content the plugin doesn't sync — and prints it in the conversation.
- Obsidian Granola Sync Plugin — syncs AI summaries from Granola into your Obsidian vault.
- Granola Search Skill (
/granola-search) — searches the synced meeting files by folder tags, title, and body content. RequiresVAULT_GRANOLA_PATHto be configured. - Granola Transcript Skill (
/granola-transcript) — extracts the full transcript from Granola's cache (which the plugin doesn't sync) and prints it in the conversation. RequiresVAULT_GRANOLA_PATHto be configured.
This plugin runs within Obsidian to pull your latest meeting summaries.
- Auto-sync on startup: Automatically checks for new meetings when you open Obsidian.
- AI Summary Extraction: Pulls the clean AI summary (not just the raw text).
- Rich Metadata: Populates YAML frontmatter with
granola_id, deep links (granola_url), and participant lists. - Incremental Sync: Only adds new meetings; avoids duplicates.
- Node.js installed
- Obsidian installed
- Granola installed and run at least once (so the local cache exists)
- Clone this repository:
git clone https://github.com/sonomirco/obsedian-plugin-and-skills-for-granola.git cd obsedian-plugin-and-skills-for-granola - Install dependencies and build:
npm install && npm run build - Create a folder named
granola-syncinside your Obsidian vault's.obsidian/plugins/directory. - Copy
main.jsandmanifest.jsoninto that folder. - Open Obsidian, go to Settings > Community Plugins, and enable Granola Sync.
In Obsidian Settings > Granola Sync:
- Output folder: Destination for meeting notes (Default:
Granola). - Days to sync: How far back to look for meetings (Default:
365).
Platform note: the plugin auto-detects the Granola cache at ~/Library/Application Support/Granola/cache-v4.json (falling back to cache-v3.json for older installs). On Windows, update getGranolaCachePath() in main.ts to match your Granola install location, then rebuild.
The two skills (/granola-search and /granola-transcript) are Claude Code custom skills. To install them:
- Copy the
skills/folder from this repo into your project or working directory. - Open each skill's
SKILL.mdand setVAULT_GRANOLA_PATHto the absolute path where the Obsidian plugin writes meeting files (e.g.,/Users/you/your-vault/Granola). - The skills will be available as
/granola-searchand/granola-transcriptin Claude Code.
The Granola Transcript skill also requires Python 3.6+ for the extractor script.
Located in skills/granola-search. A Claude Code skill invocable with /granola-search.
Configuration: Set VAULT_GRANOLA_PATH in the skill's SKILL.md to the absolute path where the Obsidian plugin writes meeting files.
This skill searches through the markdown files created by the Obsidian plugin. It uses a 3-step progressive filtering approach against the synced files' YAML frontmatter and body content:
- Folder tags — filter by person names, projects, or categories (e.g., "Chat with Alex", "Project Alpha").
- Title — narrow by meeting title keywords.
- Body content — search for topics and keywords in the summary text.
Each step narrows the result set. Steps are skipped when no matching filter is given, and natural language queries like "meetings with Alex about automation" are parsed across all three dimensions.
Located in skills/granola-extractor. A Claude Code skill invocable with /granola-transcript.
Configuration: Set VAULT_GRANOLA_PATH in the skill's SKILL.md to the absolute path where the Obsidian plugin writes meeting files.
The Obsidian plugin only syncs AI summaries — it does not include the full verbatim transcript. This skill extracts that missing content directly from Granola's local cache (auto-detected, supports cache-v3.json and cache-v4.json) and displays it in the conversation.
- Search — finds a meeting by partial title match in the synced markdown files at
VAULT_GRANOLA_PATH. - Extract — reads the
granola_idfrom the matched file's frontmatter, then uses theGranolaExtractorPython script to pull the full transcript from Granola's cache. - Display — prints the complete transcript with speaker labels in the conversation.
The GranolaExtractor class can also be used directly:
from scripts.granola_extractor import GranolaExtractor
extractor = GranolaExtractor()
transcript = extractor.get_transcript('your-granola-id')