$npx -y skills add ArtemXTech/claude-code-obsidian-starter --skill granolaQuery and sync Granola meetings to Obsidian vault. Use when user mentions Granola, meeting transcripts, or wants to sync meeting notes. Reads from local cache - no API needed.
| 1 | # Granola Skill |
| 2 | |
| 3 | Query and sync Granola AI meeting notes to Obsidian vault. |
| 4 | |
| 5 | ## How It Works |
| 6 | |
| 7 | Granola stores everything locally at `~/Library/Application Support/Granola/cache-v3.json`: |
| 8 | - Documents (meetings with title, notes, people) |
| 9 | - Transcripts (real-time, with timestamps and source) |
| 10 | - Updates in real-time as you record |
| 11 | |
| 12 | No API calls needed - reads directly from local cache. |
| 13 | |
| 14 | ## Quick Start |
| 15 | |
| 16 | ```bash |
| 17 | # List all meetings |
| 18 | python3 .claude/skills/granola/scripts/granola.py list |
| 19 | |
| 20 | # Get specific meeting with transcript |
| 21 | python3 .claude/skills/granola/scripts/granola.py get <id> |
| 22 | |
| 23 | # Sync new meetings to vault |
| 24 | python3 .claude/skills/granola/scripts/granola.py sync |
| 25 | |
| 26 | # Sync specific meeting |
| 27 | python3 .claude/skills/granola/scripts/granola.py sync --id <id> |
| 28 | ``` |
| 29 | |
| 30 | ## Commands |
| 31 | |
| 32 | ### list |
| 33 | |
| 34 | List all Granola meetings with sync status. |
| 35 | |
| 36 | ```bash |
| 37 | python3 .claude/skills/granola/scripts/granola.py list |
| 38 | python3 .claude/skills/granola/scripts/granola.py list --limit 5 |
| 39 | ``` |
| 40 | |
| 41 | Output: |
| 42 | ``` |
| 43 | [✓] 2026-01-09 Team Sync - Weekly |
| 44 | ID: abc123... |
| 45 | Transcript: 450 segments, ~86 min |
| 46 | |
| 47 | [ ] 2026-01-10 Team Standup |
| 48 | ID: def456... |
| 49 | Transcript: 120 segments, ~15 min |
| 50 | ``` |
| 51 | |
| 52 | - `[✓]` = already synced to vault |
| 53 | - `[ ]` = not synced yet |
| 54 | |
| 55 | ### get |
| 56 | |
| 57 | View full meeting details and transcript. |
| 58 | |
| 59 | ```bash |
| 60 | python3 .claude/skills/granola/scripts/granola.py get <id> |
| 61 | python3 .claude/skills/granola/scripts/granola.py get <id> --no-transcript |
| 62 | ``` |
| 63 | |
| 64 | ### sync |
| 65 | |
| 66 | Sync meetings to `Meetings/` as structured Markdown. |
| 67 | |
| 68 | ```bash |
| 69 | # Sync new meetings only |
| 70 | python3 .claude/skills/granola/scripts/granola.py sync |
| 71 | |
| 72 | # Sync specific meeting |
| 73 | python3 .claude/skills/granola/scripts/granola.py sync --id <id> |
| 74 | |
| 75 | # Re-sync all (overwrites existing) |
| 76 | python3 .claude/skills/granola/scripts/granola.py sync --all |
| 77 | ``` |
| 78 | |
| 79 | ## Output Format |
| 80 | |
| 81 | Synced meetings are saved to `Meetings/` with this structure: |
| 82 | |
| 83 | ```markdown |
| 84 | --- |
| 85 | type: granola-meeting |
| 86 | date: 2026-01-09 |
| 87 | time: "19:30" |
| 88 | duration_min: 86 |
| 89 | granola_id: abc123... |
| 90 | people: |
| 91 | - "[[Sarah Chen]]" |
| 92 | topics: [] |
| 93 | status: raw |
| 94 | --- |
| 95 | |
| 96 | # Meeting Title |
| 97 | |
| 98 | ## Notes |
| 99 | |
| 100 | (Your notes from Granola) |
| 101 | |
| 102 | ## Transcript |
| 103 | |
| 104 | [19:30:45] 🎤 Hey, how's it going? |
| 105 | [19:30:48] 🎤 Great to meet you... |
| 106 | ``` |
| 107 | |
| 108 | **Transcript icons:** |
| 109 | - 🎤 = microphone (you) |
| 110 | - 🔊 = system audio (others on call) |
| 111 | |
| 112 | ## Workflow |
| 113 | |
| 114 | 1. **Record meeting** in Granola (real-time transcription) |
| 115 | 2. **Sync to vault**: `python3 .claude/skills/granola/scripts/granola.py sync` |
| 116 | 3. **Process meeting**: Extract action items, update people notes |
| 117 | 4. **Mark as processed**: Change `status: raw` to `status: processed` |
| 118 | |
| 119 | ## Querying with Bases |
| 120 | |
| 121 | Use `Granola.base` to query synced meetings: |
| 122 | |
| 123 | | View | Filter | |
| 124 | |------|--------| |
| 125 | | Recent | Last 7 days | |
| 126 | | Needs Processing | status = raw | |
| 127 | | By Person | Grouped by people field | |
| 128 | |
| 129 | ## Data Structure |
| 130 | |
| 131 | **Local cache:** `~/Library/Application Support/Granola/cache-v3.json` |
| 132 | |
| 133 | ``` |
| 134 | cache (JSON string) → state → |
| 135 | ├── documents: {id: {title, notes_plain, notes_markdown, people, created_at}} |
| 136 | └── transcripts: {id: [{text, source, start_timestamp, end_timestamp}]} |
| 137 | ``` |
| 138 | |
| 139 | **Transcript segment:** |
| 140 | ```json |
| 141 | { |
| 142 | "text": "Hey, how's it going?", |
| 143 | "source": "microphone", |
| 144 | "start_timestamp": "2026-01-09T19:30:45.123Z", |
| 145 | "end_timestamp": "2026-01-09T19:30:48.456Z" |
| 146 | } |
| 147 | ``` |
| 148 | |
| 149 | ## Tips |
| 150 | |
| 151 | - **Real-time access**: Cache updates as you record - can query mid-meeting |
| 152 | - **Free tier hack**: Sync hourly to bypass 7-day history limit |
| 153 | - **No auth needed**: Uses local files, not API |