mgonto/executive-assistant-skills/meeting-prep
Claude Code and agent skill by mgonto/executive-assistant-skills
- community
Checking that the SKILL.md file is still in the repository.
Prepare briefings for today's meetings — attendee research, email history, past meeting notes, LinkedIn, and company context. Use when running the daily meeting prep cron, or when user asks to prepare for meetings, review who they're meeting with, or get context on upcoming calls.
Install
npx vskill@latest install mgonto/executive-assistant-skills/meeting-prepSKILL.md
Daily Meeting Prep
Config — read before starting
Read ../config/user.json (resolves to ~/executive-assistant-skills/config/user.json). Extract and use throughout:
name,full_name— user's nameprimary_email,work_email— Gmail accounts to checkwhatsapp— WhatsApp number for deliverytimezone— IANA timezone (e.g. America/Argentina/Buenos_Aires)slack_username— Slack DM targetworkspace— absolute path to OpenClaw workspace (e.g. /home/user/.openclaw/workspace)
Do not proceed until you have these values.
Debug Logging (MANDATORY)
Read ../config/DEBUG_LOGGING.md for the full convention. Use python3 {user.workspace}/scripts/skill_log.py meeting-prep <level> "<message>" ['<details>'] at every key step. Log BEFORE and AFTER every external call (gog, mcporter, Granola, web search). On any error, log the full command and stderr before continuing.
Scope
- Timezone: {user.timezone}
- Calendars: primary of {user.primary_email} AND {user.work_email}
- Today's meetings only
Timezone note: Use explicit ART-bounded ISO8601 timestamps for calendar queries, NOT --date. Example: gog calendar list primary --account <email> --from "2026-03-03T00:00:00-03:00" --to "2026-03-04T00:00:00-03:00" --json. The --date flag uses UTC boundaries which misaligns with ART.
- ALL meetings with attendees — both external and internal
- Skip personal/solo events with no attendees (e.g. "Personal Trainer", "Golf", all-day reminders)
Meeting types
External meetings (attendees outside your email domains)
Full research brief (email context, Granola, LinkedIn, company research) — see below.
Internal meetings (all attendees from your email domains: hypergrowthpartners.com, growth.li)
Lighter brief — no LinkedIn/company research needed, but still include:
- Attendee list
- Granola context from previous instances of this recurring meeting
- Recent email threads related to the meeting topic/agenda
- Any open action items from last time
- Format: same structure but skip LinkedIn/company sections
Recurring collaborative meetings (e.g. podcasts, content sessions with external co-hosts)
These are external meetings — give them full briefs. Don't skip recurring meetings just because they're familiar.
Error handling
- If
gog calendarfails for one account: continue with the other account, note "⚠️ [account] calendar unavailable" in output. - If Granola/Grain fails: continue without meeting history, note it per meeting.
- If WhatsApp delivery fails: attempt Slack delivery. If both fail, save to state file and report error.
For each meeting
1. Event basics
Title, local time ({user.timezone}), attendees.
RSVP status (MANDATORY): For each attendee, check responseStatus from the calendar event:
accepted→ no flag neededneedsAction→ flag as "⚠️ hasn't responded"declined→ flag as "❌ declined"tentative→ flag as "❓ tentative"
If ANY non-organizer external attendee has NOT accepted (needsAction, tentative, or declined), add a visible line in the brief:
⚠️ RSVP: <name> hasn't accepted yet
This is informational — it doesn't mean they won't join, but it's useful to know ahead of time, especially for first calls or important meetings.
2. Email context (90-day lookback, with historical fallback)
Search Gmail both accounts for exchanges with attendees. For EACH attendee, search using these strategies in order:
- Email address (primary — from calendar invite):
from:<email> OR to:<email> - Full name:
"firstname lastname" - First name + "intro":
"intro firstname"(catches informal intro subjects) - First name + company:
"firstname companyname"
The attendee's email from the calendar invite is the most reliable identifier — always start there.
Intro discovery (after general email search):
- Search for intro emails involving the attendee:
subject:intro <email>,subject:intro <firstname>,subject:introduction <email> - Also check threads where a third party CC'd/introduced the attendee
Recent email context (after intro discovery):
- Pull the most recent email threads with this attendee (by email address) to surface any recent updates, asks, or context leading into today's call
Historical fallback (if no results from 90-day search):
- Run a broader search with NO date filter:
from:<email> OR to:<email>— this catches long-standing relationships where the last email was months/years ago. If older threads exist, this is NOT a first call — note the relationship history.
- First call vs follow-up? Base this on ALL email history found (including historical), not just 90-day window
- If first call: MUST include "who introduced + when" (date) if found in email; if not found, explicitly say "No intro trail found in email"
- If follow-up: extract updates since last call
- If email contains a concrete commercial trigger (pricing, deliverables, scope, budget, urgency, timeline, decision-maker request), include it explicitly in the brief
3. Granola context
Search by ATTENDEE, not by meeting title. The same recurring meeting may have different titles week to week. Always search by the attendee's name or email to find all past meetings with them.
Cross-check with `list_meetings`: If the query results seem stale (oldest match is weeks old but you expect more recent), also run list_meetings for last_week or this_week and scan the participant lists for the attendee's email or name. This catches meetings where the title doesn't mention the attendee or company.
- Recent (< 3 weeks): Provide a richer summary (not one-liner): decisions made, key tensions, explicit action items, owners, and unresolved questions
- Older (3+ weeks): Broader context — relationship history, past decisions, recurring themes
- No attendee match but company match exists: Use company-level context and label it clearly as company-level
- No results / first meeting: Note that, provide email context instead
- Preserve citation links
[[N]](url) - Include a short explicit line: "Why this meeting now" based on prior action items or current email trigger
- Exact name matching: When attributing Granola results to an attendee, verify BOTH first AND last name match exactly. Different people can share a first name — never assume a match based on first name alone.
- Auth failure: If Granola returns an auth error, run
mcporter auth granola --resetand retry once. If still failing, note "⚠️ Granola unavailable" and continue without it. - Empty summary: If Granola returns a meeting record but with no/empty summary, note "Previous meeting found but no summary available" — don't silently skip it.
4. LinkedIn research
- Search:
"[attendee name] [company] LinkedIn" - Extract: current role, background, recent posts/activity
5. Company research
- Search:
"[company] recent news" - Search:
"[company] funding crunchbase"(if startup/VC relevant) - Extract: company stage, announcements, what they do
Research rules
Read {user.workspace}/style/MEETING_PREP_RULES.md for additional research steps.
Output format
Send via WhatsApp ({user.whatsapp}) AND Slack (DM to {user.slack_username}). One message per meeting, chronological order, is mandatory.
Also send to Chief of Staff: After sending all meeting briefs, upload the markdown brief file ({user.workspace}/state/meeting-prep-YYYY-MM-DD.md) to {user.chief_of_staff.name}'s Slack DM. Use the Slack API files.upload (or files.uploadV2):
Never collapse into a single summary block. The user expects one standalone message per meeting. Send each meeting brief as a separate message to BOTH WhatsApp and Slack. If one channel fails, still deliver to the other.
Start with a short intro: "📋 MEETING PREP — <day> — <N> meetings (<X> external, <Y> internal)"
Then one message per meeting in this format — use bold subsections and blank lines between each section for readability:
Each section on its own paragraph (blank line before each bold label). Keep it concise but well-structured — readability over density.
If a meeting already happened, prefix with ✅ and keep brief. If there's a schedule conflict, flag with ⚠️.
Save full brief
Save the full detailed brief to {user.workspace}/state/meeting-prep-YYYY-MM-DD.md and also send it as a file attachment via WhatsApp.
⚠️ CRON CREATION (CRITICAL — DO NOT SKIP)
This section is NON-OPTIONAL. Cron creation MUST happen for every run with meetings. If you run out of context or time before completing this section, the entire run is a FAILURE.
Execution order: Create ALL crons IMMEDIATELY after saving the brief file — BEFORE the assertions step. Do not defer cron creation to "after everything else."
Log: python3 {user.workspace}/scripts/skill_log.py meeting-prep INFO "Starting cron creation for N meetings"
Pre-meeting reminders
After generating all briefs, create a one-shot cron job for EACH meeting that fires 5 minutes before start time. The cron job should:
- Read
{user.workspace}/state/meeting-prep-YYYY-MM-DD.md - Find the section for that specific meeting
- Resend the FULL formatted brief for that meeting (same format as the original WhatsApp message — bold subsection labels, blank lines, links, etc.)
- Prefix with "⏰ 5 min reminder\n\n" then the full brief
Hard formatting contract (no exceptions):
- The reminder body must be copied verbatim from
{user.workspace}/state/meeting-prep-YYYY-MM-DD.mdfor that meeting block. - Do NOT rewrite, summarize, translate, normalize, or reformat any part of that block.
- Keep language exactly as generated in the source brief.
- Only allowed change is adding the
⏰ *5 min reminder*prefix.
Use openclaw cron add with --at set to 5 min before meeting time, --delete-after-run, --no-deliver, --channel whatsapp, and --to {user.whatsapp}. The --no-deliver flag prevents the announce mechanism from sending a separate message — the task sends WhatsApp directly.
Hard requirement: after creating jobs, run openclaw cron list and verify the expected number of pre-meeting- jobs for today. If count is lower than expected, immediately retry creation and report failure explicitly.
Log each created cron: python3 {user.workspace}/scripts/skill_log.py meeting-prep INFO "Created pre-meeting cron" '{"meeting": "<name>", "fires_at": "<time>"}'
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingmeeting-prep/SKILL.md
Popularity
- Repository stars
- 104
- Repository forks
- 11
- 7-day trend score
- 23
Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 20 Mar 2026, 7 months ago.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/mgonto/executive-assistant-skills/meeting-prep)