glebis/meeting-prep
Prepare for upcoming meetings — pulls Cal.com bookings, researches participants, audits previous sessions from Obsidian vault, and creates prep notes. Also links prep notes to post-meeting session notes.
npx skills add https://github.com/glebis/claude-skills --skill meeting-prep
Prepares comprehensive meeting prep notes for upcoming Cal.com bookings by researching participants and auditing session history from the Obsidian vault.
All paths and settings are in config.yaml next to this file. Read it before executing any steps.
# config.yaml — key fields:
vault.root # Obsidian vault root
vault.meetings # Where meeting notes live
vault.people_search_depth # How deep to search for person notes
prep_notes.prefix # Filename prefix (default: "prep")
prep_notes.type_tag # Frontmatter type value (default: "meeting-prep")
calcom.lookahead_days # Default booking lookahead
calcom.timezone # Display timezone
calcom.time_format # 12h or 24h
On first run: Read config.yaml from the same directory as this SKILL.md file. Resolve ~ to the user's home directory. Use these values for all path references below — never hardcode paths.
/meeting-prepcalcom.lookahead_days days2026-06-03) → prep bookings on that specific dateGreg) → prep only bookings with that participanttomorrow / today / this week → natural date rangeslink → scan for unlinked prep↔session note pairs and connect themsync → reconcile prep notes with Cal.com booking state (cancelled, rescheduled, deleted)status → show Dataview-style overview of all prep notes and their link statusRead config.yaml from the skill directory. Resolve all paths (expand ~). Store as variables for use in subsequent steps:
VAULT_ROOT = config.vault.root
MEETINGS_DIR = config.vault.meetings
PEOPLE_DEPTH = config.vault.people_search_depth
PREP_PREFIX = config.prep_notes.prefix
TYPE_TAG = config.prep_notes.type_tag
LOOKAHEAD = config.calcom.lookahead_days
TIMEZONE = config.calcom.timezone
Load Cal.com MCP tools via ToolSearch (query: "calcom", max_results: 20). Then:
get_bookings to retrieve upcoming bookings (status: accepted) within the target date rangeget_booking_attendees to get the full attendee list — Cal.com bookings can have multiple attendees (e.g., lab sessions, masterminds, group calls)For each unique participant, search MEETINGS_DIR for previous session notes:
grep -rl "PARTICIPANT_NAME" $MEETINGS_DIR 2>/dev/null
Read matching files (up to 5 most recent) to extract:
Also search for a person note in the vault:
find $VAULT_ROOT -maxdepth $PEOPLE_DEPTH -name "*PARTICIPANT_NAME*" -not -path "*/Meetings/*" 2>/dev/null
Use the Workflow tool to parallelize participant research. Pass MEETINGS_DIR and VAULT_ROOT via workflow args so subagents know where to search.
For each unique participant, spawn an agent that:
There are two modes depending on the number of attendees:
YYYYMMDD-$PREP_PREFIX-PARTICIPANT_SLUG.mdYYYYMMDD-$PREP_PREFIX-EVENT_SLUG.md (where EVENT_SLUG is the Cal.com event type slug in lowercase kebab-case). The note lists all attendees with brief profiles, and the research section covers all participants.If a prep note already exists for that date+session, update it instead of creating a duplicate.
Use this template:
---
type: $TYPE_TAG
date: YYYY-MM-DD
participant: "Full Name"
email: [email protected]
event_type: "Cal.com event type name"
duration: X min
time: "HH:MM $TIMEZONE"
zoom_link: "https://..."
status: prep
session_note: ""
tags:
- $TYPE_TAG
- SESSION_TYPE
---
# Prep: Full Name — YYYY-MM-DD
## Session Info
- **Time**: HH:MM–HH:MM $TIMEZONE (Day of week)
- **Type**: Event type name (X min)
- **Location**: Zoom link
- **Participant timezone**: Timezone
## About FIRST_NAME
RESEARCH_SUMMARY
## Previous Sessions (N total)
### Most Recent: YYYY-MM-DD — Event Type
KEY_TOPICS_AND_OUTCOMES
### Earlier Sessions
BRIEF_LIST_WITH_DATES_AND_TOPICS
## Continuity & Follow-ups
- Outstanding action items from previous sessions
- Recurring themes or patterns
- Progress on previously discussed goals
## Prep Ideas
- Conversation starters from research
- Topics to revisit based on session history
- Questions to explore
## Notes
_Space for pre-meeting thoughts and during-meeting notes_
When multiple bookings exist for the same participant within the lookahead window (e.g., Jun 3 and Jun 9), sort them by date and handle as follows:
prior_prep: "[[YYYYMMDD-prep-participant]]" to frontmatter, pointing to the earlier prep note ## Prior Session
A session with FIRST_NAME is scheduled for PRIOR_DATE — it will have happened by the time this session occurs.
Update this note after the PRIOR_DATE session with fresh context.
For first-time participants (no vault history), replace the "Previous Sessions" and "Continuity" sections with:
## First Meeting
No previous sessions found in vault.
## Context & Talking Points
- Research-based conversation starters
- Questions to understand their goals and needs
- How they likely found you / booking context
For bookings with 2+ attendees, use this template instead:
---
type: $TYPE_TAG
date: YYYY-MM-DD
participants:
- name: "Full Name 1"
email: [email protected]
- name: "Full Name 2"
email: [email protected]
event_type: "Cal.com event type name"
duration: X min
time: "HH:MM $TIMEZONE"
zoom_link: "https://..."
status: prep
session_note: ""
tags:
- $TYPE_TAG
- SESSION_TYPE
---
# Prep: Event Type Name — YYYY-MM-DD
## Session Info
- **Time**: HH:MM–HH:MM $TIMEZONE (Day of week)
- **Type**: Event type name (X min)
- **Location**: Zoom link
- **Attendees**: N participants
## Attendees
### FIRST_NAME_1 LAST_NAME_1
BRIEF_PROFILE_AND_RESEARCH_SUMMARY
### FIRST_NAME_2 LAST_NAME_2
BRIEF_PROFILE_AND_RESEARCH_SUMMARY
## Previous Sessions per Attendee
SUMMARY_OF_VAULT_HISTORY_PER_ATTENDEE (grouped by person, skip if no history)
## Prep Ideas
- Group dynamics to consider
- Topics to cover with the full group
- Individual follow-ups to weave in
## Notes
_Space for pre-meeting thoughts and during-meeting notes_
After creating all prep notes, output a concise summary:
[[YYYYMMDD-PREP_PREFIX-participant-slug]]TIMEZONE for displaymeeting-prep linkWhen invoked with link, scan for prep notes that don't yet have a linked session note, and connect them.
grep -rl "type: $TYPE_TAG" $MEETINGS_DIR 2>/dev/null
session_note: "" (unlinked):date and participant from frontmatter find $MEETINGS_DIR -name "YYYYMMDD-*" -not -name "*$PREP_PREFIX*" | xargs grep -l "PARTICIPANT_NAME" 2>/dev/null
participants: in YAML frontmatter; Granola notes have participants: tooIn the prep note:
session_note: "[[YYYYMMDD-matching-note-filename]]"status: prep → status: doneIn the session note:
## Prep Note section at the end (before any existing ## See also section if present): ## Prep Note
- [[YYYYMMDD-PREP_PREFIX-participant-slug]]
## See also section, add the link there instead of creating a new section-$PREP_PREFIX- in filename)meeting-prep syncWhen invoked with sync, reconcile all active prep notes with the current state of their Cal.com bookings. This catches cancellations, reschedules, and deleted bookings that would otherwise leave stale prep notes in the vault.
grep -rl "type: $TYPE_TAG" $MEETINGS_DIR 2>/dev/null
Filter to only notes where status: prep (skip done, cancelled, orphaned).
date (YYYY-MM-DD)participant (full name)email (attendee email)event_type (Cal.com event type name)get_bookings to retrieve bookings covering the date range of all active prep notes. For each prep note, match against Cal.com bookings by date + attendee email.Cancelled — the booking exists on Cal.com with a cancelled status:
status: prep → status: cancelled ## Cancelled
Booking was cancelled on YYYY-MM-DD (detected during sync).
Rescheduled — the booking exists but with a different date/time:
date field in frontmatter to the new datetime field to the new timeYYYYMMDD-$PREP_PREFIX-participant-slug.md to NEW_YYYYMMDD-$PREP_PREFIX-participant-slug.md ## Rescheduled
Moved from ORIGINAL_DATE to NEW_DATE (detected during sync on YYYY-MM-DD).
Still active — booking exists, same date/time, accepted status:
status: prep → status: orphaned. Append: ## Orphaned
No matching booking found on Cal.com (detected during sync on YYYY-MM-DD). The booking may have been deleted.
event_type in addition to date + attendee email to disambiguate. If ambiguity remains, skip the note and flag it in the report for manual review.status: done: Skip entirely — these are already linked to session notes and should not be modified by sync.meeting-prep statusWhen invoked with status, scan all prep notes and report their current state. Also output useful Dataview queries the user can paste into their vault.
Scan $MEETINGS_DIR for files matching *-$PREP_PREFIX-*.md. For each, read frontmatter and report:
| Date | Participant | Status | Session Note |
|------|------------|--------|-------------|
| from date | from participant | prep or done | linked note or — |
After the table, output a Top 5 most-met participants summary by scanning all prep notes in the vault, counting occurrences per participant, and listing the top 5 with their session count and date of last meeting.
Include these ready-to-paste queries in the status output:
Upcoming preps (unlinked):
TABLE participant AS "Who", time AS "Time", event_type AS "Type", duration + " min" AS "Duration"
FROM "Meetings"
WHERE type = "$TYPE_TAG" AND status = "prep"
SORT date ASC
Completed preps (linked to session notes):
TABLE participant AS "Who", date AS "Date", session_note AS "Session Note"
FROM "Meetings"
WHERE type = "$TYPE_TAG" AND status = "done"
SORT date DESC
Prep coverage — sessions without a prep note:
TABLE title AS "Session", date AS "Date", participants AS "Participants"
FROM "Meetings"
WHERE !contains(file.name, "$PREP_PREFIX") AND !contains(file.inlinks.file.name, "$PREP_PREFIX")
SORT date DESC
LIMIT 20
All preps by participant:
TABLE date AS "Date", status AS "Status", event_type AS "Type", session_note AS "Linked"
FROM "Meetings"
WHERE type = "$TYPE_TAG"
SORT participant ASC, date DESC
Meeting frequency by participant:
TABLE length(rows) AS "Sessions", min(rows.date) AS "First", max(rows.date) AS "Last"
FROM "Meetings"
WHERE type = "$TYPE_TAG"
GROUP BY participant
SORT length(rows) DESC
Participant timeline (embed in a participant's person note — uses this.participant for context):
TABLE date AS "Date", event_type AS "Type", status AS "Status", session_note AS "Linked"
FROM "Meetings"
WHERE type = "$TYPE_TAG" AND participant = this.participant
SORT date DESC
Recent meeting activity (last 30 days, all sessions, cross-referenced with prep coverage):
TABLE title AS "Session", participants AS "With",
choice(contains(file.inlinks.file.name, "prep"), "✓", "—") AS "Prepped"
FROM "Meetings"
WHERE date >= date(today) - dur(30 days) AND !contains(file.name, "prep")
SORT date DESC
First-timers list (people met only once — potential follow-up candidates):
TABLE participant AS "Who", date AS "Met On", event_type AS "Type"
FROM "Meetings"
WHERE type = "$TYPE_TAG"
GROUP BY participant
FLATTEN length(rows) AS count
WHERE count = 1
FLATTEN rows.date AS date
FLATTEN rows.event_type AS event_type
SORT date DESC
Take glebis/meeting-prep from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.