.claude/skills/meeting-backup/SKILL.md
Backup today's Granola meeting notes to local markdown files, organized by client folder. Uses Granola folder metadata to route meetings to appropriate client directories. Run this as part of an evening workflow to archive meeting notes, summaries, and action items. Triggers: "backup meetings", "save today's meetings", "archive meetings", "evening backup", "download meeting notes", "sync meetings", "meeting backup".
npx skillsauth add johncarpenter/knowledge-base meeting-backupInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Backup today's Granola meeting notes to local markdown files, organized by Granola folder (client). Run as part of an evening routine to ensure meeting notes are archived locally.
Meetings are saved to directories based on their Granola folder:
| Granola Folder | Local Directory |
|----------------|-----------------|
| Suncorp | clients/Suncorp/meetings/ |
| Circuit | clients/Circuit/meetings/ |
| Jot | clients/JOT/meetings/ |
| Zane | clients/Zane/meetings/ |
| Pacwest | clients/Pacwest/meetings/ |
| 2Lines | operations/meetings/ |
| (other/unfiled) | operations/meetings/ |
Filename convention: YYYY-MM-DD-meeting-title-slug.md
clients/
├── Circuit/
│ └── meetings/
│ └── 2026-02-09-circuit-standup.md
├── Suncorp/
│ └── meetings/
│ └── 2026-02-09-suncorp-standup.md
└── JOT/
└── meetings/
└── 2026-02-09-jot-review.md
operations/
└── meetings/
└── 2026-02-09-team-sync.md
| Tool | Purpose |
|------|---------|
| mcp__granola__list_meetings | List meetings in a time range |
| mcp__granola__get_meetings | Get meeting details by ID(s) |
| mcp__granola__get_meeting_transcript | Get full transcript (recent meetings only) |
The Granola cache contains folder metadata that maps meetings to clients. Read this before processing meetings.
Cache location: /Users/john/Library/Application Support/Granola/cache-v3.json
import json
# Read the cache
with open('/Users/john/Library/Application Support/Granola/cache-v3.json', 'r') as f:
data = json.load(f)
inner = json.loads(data.get('cache'))
state = inner.get('state', {})
# Get folder metadata and document lists
dlm = state.get('documentListsMetadata', {})
doc_lists = state.get('documentLists', {})
# Build document_id -> folder_title mapping
doc_to_folder = {}
for list_id, doc_ids in doc_lists.items():
if isinstance(doc_ids, list):
meta = dlm.get(list_id, {})
folder_title = meta.get('title', 'Unfiled') if isinstance(meta, dict) else 'Unfiled'
for doc_id in doc_ids:
doc_to_folder[doc_id] = folder_title
FOLDER_TO_PATH = {
'Suncorp': 'clients/Suncorp/meetings',
'Circuit': 'clients/Circuit/meetings',
'Jot': 'clients/JOT/meetings',
'Zane': 'clients/Zane/meetings',
'Pacwest': 'clients/Pacwest/meetings',
'Stratenym': 'clients/Stratenym/meetings',
'2Lines': 'operations/meetings',
# Default fallback
'_default': 'operations/meetings',
}
def get_output_path(meeting_id, doc_to_folder):
folder = doc_to_folder.get(meeting_id, 'Unfiled')
base_path = FOLDER_TO_PATH.get(folder, FOLDER_TO_PATH['_default'])
return base_path
# Search for today's date
mcp__granola__search_meetings(query="2026-02-09", limit=20)
# Or search broadly and filter by date
mcp__granola__search_meetings(query="", limit=50)
# Then filter results where created_at matches today
meeting_id = "<uuid from search results>"
# Get metadata
details = mcp__granola__get_meeting_details(meeting_id=meeting_id)
# Get notes and summaries
documents = mcp__granola__get_meeting_documents(meeting_id=meeting_id)
# Get transcript if available (recent meetings only)
transcript = mcp__granola__get_meeting_transcript(meeting_id=meeting_id)
Template:
# [Meeting Title]
**Date:** YYYY-MM-DD HH:MM
**Attendees:** Name1, Name2, Name3
**Source:** Granola (backed up YYYY-MM-DD)
---
## Summary
[AI-generated summary from documents]
## Key Decisions
- [Decision 1]
- [Decision 2]
## Action Items
- [ ] [Action item with owner]
- [ ] [Action item with owner]
## Notes
[Human-written notes or structured panel content]
---
## Transcript
<details>
<summary>Click to expand full transcript</summary>
[Full transcript with speaker labels]
</details>
# Get folder from mapping
folder = doc_to_folder.get(meeting_id, 'Unfiled')
base_path = FOLDER_TO_PATH.get(folder, FOLDER_TO_PATH['_default'])
# Generate slug from title
slug = meeting_title.lower().replace(" ", "-").replace(":", "")[:50]
filename = f"{date}-{slug}.md"
path = f"{base_path}/{filename}"
# Ensure directory exists
os.makedirs(base_path, exist_ok=True)
# Write file
Write(file_path=path, content=markdown_content)
After processing all meetings, report:
When triggered, execute this workflow:
1. Read Granola cache to build document_id -> folder mapping
2. Get current date (YYYY-MM-DD format)
3. List Granola meetings for today (mcp__granola__list_meetings)
4. For each meeting found:
a. Look up folder from doc_to_folder mapping
b. Determine output path from FOLDER_TO_PATH
c. Check if file already exists in target directory
d. If not, gather details via mcp__granola__get_meetings
e. Format as markdown
f. Ensure target directory exists
g. Save to {base_path}/YYYY-MM-DD-slug.md
5. Report results grouped by client/folder
2026-02-09-standup-2.md if needed| Scenario | Action | |----------|--------| | No transcript available | Include note: "Transcript not available in local cache" | | No summary | Use first 200 chars of notes as summary | | No attendees | List as "Unknown" | | Empty meeting | Skip with note in report |
For evening backup (default: today):
from datetime import date
today = date.today().isoformat() # "2026-02-09"
For specific date backup:
target_date = "2026-02-08" # User-specified
After running /meeting-backup:
Meeting Backup Complete
Date: 2026-02-09
Meetings found: 5
Files created: 5
By Client:
Suncorp (2):
- clients/Suncorp/meetings/2026-02-09-suncorp-standup.md
- clients/Suncorp/meetings/2026-02-09-infrastructure-sync.md
Circuit (1):
- clients/Circuit/meetings/2026-02-09-circuit-review.md
Zane (1):
- clients/Zane/meetings/2026-02-09-zane-weekly-sync.md
Internal (1):
- operations/meetings/2026-02-09-team-planning.md
Skipped:
- (none)
FOLDER_TO_PATH and ensure the directory exists under clients/.mcp.jsontools
Generate FinOps cost comparison report using cloud-doctor MCP for Suncorp Azure subscriptions
tools
Query, retrieve, and save Granola meeting notes and summaries locally using the proofgeist Granola MCP server (local cache-based). Use this skill whenever the user wants to: search or find past meetings, get meeting summaries or transcripts, copy meeting notes to local markdown files, review what was discussed in a meeting, look up action items or decisions from meetings, export meeting data, or analyze meeting patterns. Triggers: "meeting notes", "meeting summary", "what was discussed", "find the meeting", "copy meeting notes", "export meeting", "meeting transcript", "action items from meeting", "last meeting", "recent meetings", "meeting with [person]", "granola".
tools
Search, retrieve, and index local markdown knowledgebase files using the QMD CLI. Use this skill whenever the user wants to: search a local knowledgebase of markdown files, retrieve specific documents or passages from indexed collections, index or re-index a directory of .md files, check the status of the knowledge index, or perform any knowledge retrieval task against local documentation. Triggers: "search the knowledgebase", "find in docs", "index my files", "look up", "search notes", "retrieve document", "knowledge search", "what does the docs say about", "find information about", "re-index", "update the index".
tools
Export a markdown file to PDF using Jinja templates and WeasyPrint. Renders markdown through the template system and converts to PDF. Supports metadata like title, author, client, date via YAML frontmatter or arguments. Triggers: "export to pdf", "render pdf", "convert to pdf", "make pdf", "export document as pdf", "pdf export", "generate pdf".