| name | meeting-prep |
| description | 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. |
Meeting Prep
Prepares comprehensive meeting prep notes for upcoming Cal.com bookings by researching participants and auditing session history from the Obsidian vault.
Configuration
All paths and settings are in config.yaml next to this file. Read it before executing any steps.
vault.root
vault.meetings
vault.people_search_depth
prep_notes.prefix
prep_notes.type_tag
calcom.lookahead_days
calcom.timezone
calcom.time_format
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.
When to Use
- User invokes
/meeting-prep
- User asks to prepare for upcoming meetings/sessions/calls
- User says "who do I have coming up" or "prep for my next session"
Arguments
- No args → prep all bookings in the next
calcom.lookahead_days days
- Date (
2026-06-03) → prep bookings on that specific date
- Name (
Greg) → prep only bookings with that participant
tomorrow / today / this week → natural date ranges
link → scan for unlinked prep↔session note pairs and connect them
sync → reconcile prep notes with Cal.com booking state (cancelled, rescheduled, deleted)
status → show Dataview-style overview of all prep notes and their link status
Workflow
Step 0: Load Config
Read 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
Step 1: Fetch Bookings
Load Cal.com MCP tools via ToolSearch (query: "calcom", max_results: 20). Then:
- Call
get_bookings to retrieve upcoming bookings (status: accepted) within the target date range
- For each booking, call
get_booking_attendees to get the full attendee list — Cal.com bookings can have multiple attendees (e.g., lab sessions, masterminds, group calls)
- Filter by arguments if provided (date, name)
- If no bookings found, report and stop
Step 2: Search Vault for Session History
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:
- Date and duration of each past session
- Key topics discussed (from headings, summary sections, or transcript excerpts)
- Any action items or follow-ups mentioned
- Session source (Fathom, Granola, manual)
Also search for a person note in the vault:
find $VAULT_ROOT -maxdepth $PEOPLE_DEPTH -name "*PARTICIPANT_NAME*" -not -path "*/Meetings/*" 2>/dev/null
Step 3: Research Participants (Workflow)
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:
- Web-searches the participant's name + company/email domain
- Checks LinkedIn profile (via web search, not direct scrape)
- Summarizes: role, company, recent activity, mutual context
- For returning participants: cross-references with vault history to identify patterns and continuity points
Step 4: Create Prep Notes in Obsidian
There are two modes depending on the number of attendees:
- Solo session (1 attendee): one prep note per session, exactly as described below. Filename:
YYYYMMDD-$PREP_PREFIX-PARTICIPANT_SLUG.md
- Group session (2+ attendees): one prep note for the whole session. Filename:
YYYYMMDD-$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.
Solo Session Template
Use this template:
---
type: $TYPE_TAG
date: YYYY-MM-DD
participant: "Full Name"
email: email@example.com
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_
Sequential Bookings for the Same Participant
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:
- First booking: standard prep note, no changes.
- Second+ booking: the prep note should acknowledge the earlier session:
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
Group Session Template
For bookings with 2+ attendees, use this template instead:
---
type: $TYPE_TAG
date: YYYY-MM-DD
participants:
- name: "Full Name 1"
email: email1@example.com
- name: "Full Name 2"
email: email2@example.com
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_
Step 5: Report
After creating all prep notes, output a concise summary:
- List of prepped sessions (date, time, participant, event type)
- Key highlights (first-timers flagged, notable follow-ups from history)
- Links to the created prep notes as
[[YYYYMMDD-PREP_PREFIX-participant-slug]]
Notes
- Always convert times to the configured
TIMEZONE for display
- Participant research should be respectful — professional context only
- If a participant has many previous sessions (>5), focus on the 3 most recent + overall patterns
- The prep note should be actionable: things to discuss, not just a dossier
- Tag first-time participants so they're easy to filter in Obsidian
- For group sessions, use the event type slug for the filename instead of participant name
Linking: meeting-prep link
When invoked with link, scan for prep notes that don't yet have a linked session note, and connect them.
How It Works
- Find all prep notes:
grep -rl "type: $TYPE_TAG" $MEETINGS_DIR 2>/dev/null
-
For each prep note with session_note: "" (unlinked):
- Extract
date and participant from frontmatter
- Search for a matching post-meeting note by date + participant name:
find $MEETINGS_DIR -name "YYYYMMDD-*" -not -name "*$PREP_PREFIX*" | xargs grep -l "PARTICIPANT_NAME" 2>/dev/null
- Fathom notes have
participants: in YAML frontmatter; Granola notes have participants: too
- Match by date prefix AND participant name appearing in the file
-
When a match is found, update both files:
In the prep note:
- Update frontmatter:
session_note: "[[YYYYMMDD-matching-note-filename]]"
- Update
status: prep → status: done
In the session note:
- Append a
## Prep Note section at the end (before any existing ## See also section if present):
## Prep Note
- [[YYYYMMDD-PREP_PREFIX-participant-slug]]
- If the session note already has a
## See also section, add the link there instead of creating a new section
-
Report which notes were linked and which prep notes are still unlinked (meeting hasn't happened yet or transcript not imported)
Matching Rules
- Date must match exactly (same YYYYMMDD prefix)
- Participant name match is fuzzy: check both full name and first name, case-insensitive
- Skip files that are themselves prep notes (
-$PREP_PREFIX- in filename)
- If multiple session notes match the same date+participant, prefer the one with a transcript (longer file)
- Never create duplicate links — check if the link already exists before adding
Sync: meeting-prep sync
When 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.
How It Works
- Find all active prep notes:
grep -rl "type: $TYPE_TAG" $MEETINGS_DIR 2>/dev/null
Filter to only notes where status: prep (skip done, cancelled, orphaned).
-
Extract booking identifiers from each prep note's frontmatter:
date (YYYY-MM-DD)
participant (full name)
email (attendee email)
event_type (Cal.com event type name)
-
Check Cal.com state: Load Cal.com MCP tools via ToolSearch (query: "calcom", max_results: 20). Call 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.
-
Update based on booking status:
Cancelled — the booking exists on Cal.com with a cancelled status:
- Update frontmatter:
status: prep → status: cancelled
- Append a section to the note:
## Cancelled
Booking was cancelled on YYYY-MM-DD (detected during sync).
Rescheduled — the booking exists but with a different date/time:
- Update the
date field in frontmatter to the new date
- Update the
time field to the new time
- Rename the file from
YYYYMMDD-$PREP_PREFIX-participant-slug.md to NEW_YYYYMMDD-$PREP_PREFIX-participant-slug.md
- Append a section to the note:
## Rescheduled
Moved from ORIGINAL_DATE to NEW_DATE (detected during sync on YYYY-MM-DD).
Still active — booking exists, same date/time, accepted status:
-
Report what changed: Output a summary table listing each prep note and the action taken (no change / cancelled / rescheduled / orphaned).
Edge Cases
Status & Queries: meeting-prep status
When invoked with status, scan all prep notes and report their current state. Also output useful Dataview queries the user can paste into their vault.
Status Report
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.
Dataview Queries
Include these ready-to-paste queries in the status output:
Upcoming preps (unlinked):
```dataview
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):
```dataview
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:
```dataview
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:
```dataview
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
```
Relationship & Activity Queries
Meeting frequency by participant:
```dataview
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):
```dataview
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):
```dataview
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):
```dataview
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
```