Back to skills
SkillHub ClubGrow & DistributeFull StackTech Writer

meeting-prep

Never walk into a meeting unprepared again. Your agent researches all attendees before calendar events—pulling LinkedIn profiles, recent company news, mutual connections, and conversation starters. Generates a briefing doc with talking points, icebreakers, and context so you show up informed and confident. Triggered automatically before meetings or on-demand. Configure research depth, advance timing, and output format. Walking into meetings blind is amateur hour—missed connections, generic small talk, zero leverage. Use when setting up meeting intelligence, researching specific attendees, generating pre-meeting briefs, or automating your prep workflow.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
3,090
Hot score
99
Updated
March 20, 2026
Overall rating
C0.0
Composite score
0.0
Best-practice grade
B71.9

Install command

npx @skill-hub/cli install openclaw-skills-meeting-prep-agent

Repository

openclaw/skills

Skill path: skills/audsmith28/meeting-prep-agent

Never walk into a meeting unprepared again. Your agent researches all attendees before calendar events—pulling LinkedIn profiles, recent company news, mutual connections, and conversation starters. Generates a briefing doc with talking points, icebreakers, and context so you show up informed and confident. Triggered automatically before meetings or on-demand. Configure research depth, advance timing, and output format. Walking into meetings blind is amateur hour—missed connections, generic small talk, zero leverage. Use when setting up meeting intelligence, researching specific attendees, generating pre-meeting briefs, or automating your prep workflow.

Open repository

Best for

Primary workflow: Grow & Distribute.

Technical facets: Full Stack, Tech Writer.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: openclaw.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install meeting-prep into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/openclaw/skills before adding meeting-prep to shared team environments
  • Use meeting-prep for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: meeting-prep
description: Never walk into a meeting unprepared again. Your agent researches all attendees before calendar events—pulling LinkedIn profiles, recent company news, mutual connections, and conversation starters. Generates a briefing doc with talking points, icebreakers, and context so you show up informed and confident. Triggered automatically before meetings or on-demand. Configure research depth, advance timing, and output format. Walking into meetings blind is amateur hour—missed connections, generic small talk, zero leverage. Use when setting up meeting intelligence, researching specific attendees, generating pre-meeting briefs, or automating your prep workflow.
metadata:
  clawdbot:
    emoji: "🎯"
    requires:
      skills:
        - gog
      env:
        - GOOGLE_CALENDAR_ENABLED
---

# Meeting Prep — Never Walk In Blind

**Walking into meetings unprepared is amateur hour.**

You're juggling back-to-back calls, no time to research who's in the room. You default to generic small talk. You miss the fact that the VP you're pitching used to work at your dream client. You didn't see the news that their company just raised $50M. You fumble the connection.

**Meeting Prep fixes this.** Your agent researches every attendee before you join—LinkedIn profiles, company intel, recent news, mutual connections, conversation hooks. It generates a briefing doc with talking points, icebreakers, and context. You walk in informed, confident, and ready to connect.

## What It Does

- **Auto-triggers** before calendar events (configurable advance time)
- **Researches attendees:** LinkedIn profiles, role, background, recent activity
- **Company intelligence:** Recent news, funding, product launches, leadership changes
- **Connection mapping:** Mutual contacts, shared interests, conversation hooks
- **Generates brief:** Clean, scannable doc with talking points and icebreakers
- **On-demand mode:** Research specific people or meetings instantly

**The difference:** Most meeting tools focus on *agendas*. Meeting Prep focuses on *people*. Know who you're talking to before you open your mouth.

## Setup

1. Run `scripts/setup.sh` to initialize config and brief storage
2. Edit `~/.config/meeting-prep/config.json` with calendar settings and research preferences
3. Ensure `gog` skill is installed (for Google Calendar integration)
4. Test with: `scripts/prep.sh "meeting-id-or-attendee-email" --dry-run`

## Config

Config lives at `~/.config/meeting-prep/config.json`. See `config.example.json` for full schema.

Key sections:
- **calendar** — Which calendars to monitor, event filters, advance notice
- **research** — Depth level (quick/standard/deep), data sources, focus areas
- **output** — Format (markdown/text/telegram), delivery channel, storage location
- **auto_prep** — Enable/disable automatic prep, time thresholds, event criteria
- **icebreakers** — Tone preferences (professional/casual/witty), topic priorities

## Scripts

| Script | Purpose |
|--------|---------|
| `scripts/setup.sh` | Initialize config and brief directories |
| `scripts/prep.sh` | Research attendees for a specific meeting (on-demand) |
| `scripts/auto-prep.sh` | Check upcoming calendar events and prep meetings that qualify |
| `scripts/brief.sh` | Output formatted briefing doc for a meeting |

All scripts support `--dry-run` for testing without actually generating briefs.

## Auto-Prep Workflow

Run `scripts/auto-prep.sh` on schedule (cron every 2-4h recommended). The workflow:
1. Fetches upcoming calendar events (next 24-48h based on config)
2. Filters for events matching criteria (external attendees, duration >15min, etc.)
3. Checks if already prepped (dedup against brief history)
4. Researches each attendee: web search for LinkedIn, company site, recent news
5. Generates briefing doc with sections: Attendees, Company Context, Talking Points, Icebreakers
6. Stores brief and optionally delivers to configured channel

## On-Demand Prep

```bash
# Research a specific meeting by calendar event ID
scripts/prep.sh "meeting-id-from-calendar"

# Research specific people by email
scripts/prep.sh "[email protected],[email protected]"

# Quick brief for imminent meeting
scripts/prep.sh "[email protected]" --format telegram --send
```

## Brief Structure

Generated briefs include:

**📋 Meeting Overview**
- Title, time, duration, location/link
- Objective (auto-detected or manual)

**👥 Attendees (per person)**
- Name, title, company
- Background highlights (education, previous roles, tenure)
- Recent activity (posts, articles, company news)
- Mutual connections (if detectable)
- Conversation hooks (shared interests, recent wins)

**🏢 Company Context**
- Recent news (funding, launches, leadership changes)
- Industry position, competitors, challenges
- Relevant talking points

**💬 Icebreakers & Talking Points**
- Personalized conversation starters per attendee
- Strategic questions to ask
- Topics to avoid (if detected)

**🎯 Your Prep Checklist**
- Key things to mention
- Questions to have ready
- Follow-up actions

## Data Files

```
~/.config/meeting-prep/
├── config.json              # User configuration
├── briefs/                  # Generated briefing docs
│   ├── 2026-02-11-acme-intro.md
│   └── 2026-02-15-bigcorp-pitch.md
├── brief-history.json       # Dedup index (event → brief mapping)
└── prep-log.json            # Prep run history
```

## Research Sources

Meeting Prep uses:
- **Web search:** LinkedIn profiles, company pages, news articles
- **Web fetch:** Company blogs, press releases, LinkedIn activity
- **Calendar metadata:** Event titles, descriptions, attendee lists (via gog)
- **Future:** CRM integration, internal notes, past meeting context

## Cron Setup Example

```bash
# Auto-prep upcoming meetings every 3 hours
0 */3 * * * /Users/you/clawd/skills/meeting-prep/scripts/auto-prep.sh

# Morning brief delivery (7 AM daily)
0 7 * * * /Users/you/clawd/skills/meeting-prep/scripts/auto-prep.sh --morning-brief
```

## Privacy & Ethics

- **Your data only:** Researches public info about people you're *scheduled* to meet
- **No stalking:** Only preps for confirmed calendar events or explicit requests
- **Opt-out friendly:** Skip specific events by adding `#noprep` to event description
- **Transparent:** Briefs cite sources; you see what the agent found

## Pro Tips

- **Set advance time wisely:** 2-4 hours before works well (too early = stale, too late = useless)
- **Customize icebreakers:** Adjust tone in config (corporate vs startup vs casual)
- **Review briefs:** Agent does the research, you add the human touch
- **Feedback loop:** Mark what worked in briefs to improve future prep
- **Combine with agenda tools:** Use Fellow/Hypercontext for *what* to discuss, Meeting Prep for *who* you're discussing with

## Example Brief

```markdown
# 🎯 Meeting Brief: Acme Corp Intro Call
**When:** Today at 2:00 PM (30 min)  
**Where:** Zoom (link in calendar)  
**Objective:** Partnership exploration

## 👥 Attendees

### John Martinez — VP of Product, Acme Corp
- **Background:** 8 years at Acme, prev. led product at DataFlow (acquired 2021)
- **Education:** Stanford CS, MBA from Wharton
- **Recent:** Posted on LinkedIn about AI integration challenges in SaaS (2 days ago)
- **Hook:** Shares your interest in automation; Acme just launched API platform

### Sarah Chen — Head of Partnerships, Acme Corp  
- **Background:** Joined 6mo ago from Google Cloud partnerships
- **Recent:** Spoke at SaaS Conference last week on strategic alliances
- **Mutual:** Connected to Jamie Lee (your former colleague at XYZ)
- **Hook:** Passionate about startups (angel investor, 5 companies)

## 🏢 Company Context

**Acme Corp** — B2B SaaS platform for workflow automation  
- **Recent news:** Series B $50M (Jan 15), TechCrunch coverage
- **Growth:** 200 → 350 employees in past year
- **Challenges:** Scaling integrations (mentioned in John's post)
- **Competitors:** Zapier, Make.com

## 💬 Icebreakers & Talking Points

**For John:**
- "Saw your post on AI integration pain points—we've been tackling similar challenges"
- Ask about the new API platform launch
- Mention DataFlow (his prev. company) if relevant angle emerges

**For Sarah:**
- "Jamie Lee mentioned you were doing great things at Acme!"
- Reference her SaaS Conference talk on alliances
- Her startup/angel background = rapport opportunity

**Strategic questions:**
- What's driving the push for more integrations right now?
- How do you typically evaluate partnership fit?
- What's been your biggest challenge since the Series B?

## 🎯 Your Prep Checklist

- ✅ Review our partnership deck (focus on integration angle)
- ✅ Have 2-3 customer stories ready (SaaS companies, automation wins)
- ✅ Prepare questions about their API roadmap
- ✅ Follow up: Connect with Sarah on LinkedIn post-call

---
*Brief generated by Meeting Prep • Sources: LinkedIn, TechCrunch, Acme blog*
```

## When to Use Meeting Prep

- **Sales calls:** Know your prospect before pitching
- **Investor meetings:** Research partners, understand fund focus
- **New client kickoffs:** Start with context, not cold
- **Networking events:** Pre-game the attendee list
- **Job interviews:** Research interviewers, not just the company
- **Conference meetings:** Brief on everyone you're meeting at the event
- **Board meetings:** Know new board members before they join

## What Makes It Different

- **People-first:** Most tools prep the *agenda*, this preps *the humans*
- **Automated:** Runs in background, delivers briefs without you asking
- **Contextual:** Not just LinkedIn stalking—connects dots, finds hooks
- **Actionable:** Not a data dump—talking points you can actually use
- **Respectful:** Public info only, ethically sourced, transparent

---

**Stop walking into meetings blind.** Let your agent do the homework. You bring the human connection.


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### scripts/prep.sh

```bash
#!/bin/bash
# meeting-prep/scripts/prep.sh — Research attendees for a specific meeting (on-demand)

set -euo pipefail

# --- CONFIG & ARGS ---
PREP_DIR="${PREP_DIR:-$HOME/.config/meeting-prep}"
CONFIG_FILE="$PREP_DIR/config.json"
HISTORY_FILE="$PREP_DIR/brief-history.json"
LOG_FILE="$PREP_DIR/prep-log.json"
BRIEFS_DIR="$PREP_DIR/briefs"

TARGET="$1"
DRY_RUN=false
FORMAT="markdown"
SEND=false

# Parse flags: --dry-run, --format <fmt>, --send
shift
while [ "$#" -gt 0 ]; do
  case "$1" in
    --dry-run) DRY_RUN=true; shift ;;
    --format) FORMAT="$2"; shift; shift ;;
    --send) SEND=true; shift ;;
    *) echo "Unknown parameter: $1"; exit 1 ;;
  esac
done

# --- LOGGING ---
log() {
  echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
  if [ "$DRY_RUN" = "false" ]; then
    jq --arg msg "$1" '.preps += [{"timestamp": (now | todate), "message": $msg}]' "$LOG_FILE" > "$LOG_FILE.tmp" && mv "$LOG_FILE.tmp" "$LOG_FILE"
  fi
}

# --- FUNCTIONS ---

# research_person <email> <name>
# Simulates researching a person. In a real implementation, this would
# use `web_search` and `web_fetch` to find LinkedIn, news, etc.
research_person() {
  local email="$1"
  local name="$2"
  log "Researching person: $name <$email>"

  # In a real script, you'd use web_search here:
  # LINKEDIN_URL=$(web_search --query "$name linkedin profile" | jq -r '.[0].url')
  # And then web_fetch to get details.
  
  # For this placeholder, we'll generate mock data.
  COMPANY=$(echo "$email" | cut -d'@' -f2 | cut -d'.' -f1)
  ROLE="VP of Something"
  RECENT_ACTIVITY="Posted on LinkedIn about industry trends."
  HOOK="Shares an interest in AI automation."

  cat <<-EOF
### $name — $ROLE, ${COMPANY^}
- **Background:** Experienced professional with a strong background in their field.
- **Recent:** $RECENT_ACTIVITY
- **Hook:** $HOOK
- **Source:** Mock data (LinkedIn search placeholder)
EOF
}

# research_company <domain>
research_company() {
  local domain="$1"
  log "Researching company: $domain"
  
  # Real implementation: web_search "$domain news" and fetch their site
  
  cat <<-EOF
### Company Context: ${domain^}
- **Recent News:** Recently launched a new product line to great acclaim.
- **Industry:** A leading player in the B2B SaaS space.
- **Source:** Mock data (Web search placeholder)
EOF
}

# --- MAIN LOGIC ---
log "Starting prep for target: $TARGET"
if [ "$DRY_RUN" = "true" ]; then log "Running in DRY-RUN mode"; fi

MEETING_TITLE="Ad-hoc Briefing"
MEETING_TIME=$(date --iso-8601=minutes)
ATTENDEES=()
COMPANIES=()

# Detect if target is a calendar event ID or emails
if [[ "$TARGET" == *@* ]]; then
  log "Target is email(s). Parsing..."
  IFS=',' read -ra EMAILS <<< "$TARGET"
  for email in "${EMAILS[@]}"; do
    name=$(echo "$email" | cut -d'@' -f1 | sed 's/[._]/\ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) substr($i,2)} 1')
    ATTENDEES+=("$email|$name")
    COMPANIES+=($(echo "$email" | cut -d'@' -f2))
  done
  MEETING_TITLE="Briefing for ${EMAILS[0]}"
else
  log "Target is a meeting ID. Fetching details from calendar..."
  # In a real script, use gog to get event details:
  # EVENT_JSON=$(gog calendar get "$TARGET")
  # MEETING_TITLE=$(echo "$EVENT_JSON" | jq -r '.summary')
  # MEETING_TIME=$(echo "$EVENT_JSON" | jq -r '.start')
  # ATTENDEES=... parse from attendees list
  MEETING_TITLE="Meeting: $TARGET"
  log "NOTE: Calendar integration is a placeholder. Using mock attendee."
  ATTENDEES+=("[email protected]|John Doe")
  COMPANIES+=("example.com")
fi

UNIQUE_COMPANIES=($(echo "${COMPANIES[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
log "Found ${#ATTENDEES[@]} attendees from ${#UNIQUE_COMPANIES[@]} companies."

# --- GENERATE BRIEF ---
BRIEF_CONTENT=""
BRIEF_CONTENT+="# 🎯 Meeting Brief: $MEETING_TITLE\n"
BRIEF_CONTENT+="**When:** $(date -R -d "$MEETING_TIME")\n\n"
BRIEF_CONTENT+="## 👥 Attendees\n\n"

for attendee_data in "${ATTENDEES[@]}"; do
  IFS='|' read -r email name <<< "$attendee_data"
  BRIEF_CONTENT+=$(research_person "$email" "$name")
  BRIEF_CONTENT+="\n\n"
done

BRIEF_CONTENT+="## 🏢 Company Context\n\n"
for company_domain in "${UNIQUE_COMPANIES[@]}"; do
  BRIEF_CONTENT+=$(research_company "$company_domain")
  BRIEF_CONTENT+="\n\n"
done

BRIEF_CONTENT+="---\n*Brief generated by Meeting Prep skill.*"

# --- OUTPUT ---
MEETING_SLUG=$(echo "$MEETING_TITLE" | tr '[:upper:]' '[:lower:]' | tr -s ' ' '-' | tr -cd 'a-z0-9-')
FILENAME="$(date -d "$MEETING_TIME" +'%Y-%m-%d')-$MEETING_SLUG.md"
FILEPATH="$BRIEFS_DIR/$FILENAME"

if [ "$DRY_RUN" = "true" ]; then
  echo "--- DRY RUN BRIEF ---"
  echo -e "$BRIEF_CONTENT"
  echo "---------------------"
  log "Dry run complete. Brief would be saved to $FILEPATH"
else
  echo -e "$BRIEF_CONTENT" > "$FILEPATH"
  log "Brief saved to $FILEPATH"
  
  # Update history
  jq --arg key "$TARGET" --arg path "$FILEPATH" '.events[$key] = $path' "$HISTORY_FILE" > "$HISTORY_FILE.tmp" && mv "$HISTORY_FILE.tmp" "$HISTORY_FILE"

  if [ "$SEND" = "true" ]; then
    log "Sending brief via configured channel..."
    # Placeholder for `message send` call
    # In a real script:
    # `message send --channel <channel_from_config> --file "$FILEPATH"`
    echo "Message sending placeholder: Brief for '$MEETING_TITLE' sent."
  fi
fi

log "Prep script finished successfully."

```

### scripts/setup.sh

```bash
#!/bin/bash
# meeting-prep/scripts/setup.sh — Initialize meeting-prep config and brief storage

set -euo pipefail

PREP_DIR="${PREP_DIR:-$HOME/.config/meeting-prep}"
SKILL_DIR="$(cd "$(dirname "$0")/.." && pwd)"

echo "🎯 Meeting Prep Setup"
echo "━━━━━━━━━━━━━━━━━━━━"

# Create config directory
mkdir -p "$PREP_DIR/briefs"
echo "✓ Created $PREP_DIR"
echo "✓ Created $PREP_DIR/briefs"

# Copy example config if none exists
if [ ! -f "$PREP_DIR/config.json" ]; then
  cp "$SKILL_DIR/config.example.json" "$PREP_DIR/config.json"
  echo "✓ Created config.json (from example — edit with your calendar and preferences)"
else
  echo "• config.json already exists (skipped)"
fi

# Initialize data files
if [ ! -f "$PREP_DIR/brief-history.json" ]; then
  echo '{"events":{}}' > "$PREP_DIR/brief-history.json"
  echo "✓ Created brief-history.json"
else
  echo "• brief-history.json already exists (skipped)"
fi

if [ ! -f "$PREP_DIR/prep-log.json" ]; then
  echo '{"preps":[]}' > "$PREP_DIR/prep-log.json"
  echo "✓ Created prep-log.json"
else
  echo "• prep-log.json already exists (skipped)"
fi

# Check for gog (calendar integration)
if command -v gog &> /dev/null; then
  echo "✓ gog CLI found (calendar integration ready)"
else
  echo "⚠ gog CLI not found"
  echo "  Install gog skill for calendar integration"
fi

# Check for calendar access
if [ -f "$HOME/.config/gog/config.json" ]; then
  echo "✓ gog config found"
else
  echo "⚠ gog not configured"
  echo "  Run: gog auth login to set up calendar access"
fi

echo ""
echo "Next steps:"
echo "  1. Edit $PREP_DIR/config.json with your calendar email and preferences"
echo "  2. Ensure gog is installed and authenticated (for calendar access)"
echo "  3. Test: $(dirname "$0")/prep.sh \"[email protected]\" --dry-run"
echo "  4. Set up cron: 0 */3 * * * $(dirname "$0")/auto-prep.sh"
echo ""
echo "🎯 Meeting Prep is ready. Never walk in blind again."

```

### scripts/auto-prep.sh

```bash
#!/bin/bash
# meeting-prep/scripts/auto-prep.sh — Check upcoming calendar events and prep meetings that qualify

set -euo pipefail

# --- CONFIG & ARGS ---
PREP_DIR="${PREP_DIR:-$HOME/.config/meeting-prep}"
CONFIG_FILE="$PREP_DIR/config.json"
HISTORY_FILE="$PREP_DIR/brief-history.json"
LOG_FILE="$PREP_DIR/prep-log.json"
PREP_SCRIPT="$(dirname "$0")/prep.sh"

MORNING_BRIEF=false

while [ "$#" -gt 0 ]; do
  case "$1" in
    --morning-brief) MORNING_BRIEF=true; shift ;;
    *) echo "Unknown parameter: $1"; exit 1 ;;
  esac
done

# --- LOGGING ---
log() {
  echo "[$(date +'%Y-%m-%d %H:%M:%S')] (auto-prep) $1"
}

# --- MAIN LOGIC ---
log "Starting auto-prep cycle."

# Load config values
if [ ! -f "$CONFIG_FILE" ]; then
  log "ERROR: Config file not found at $CONFIG_FILE. Run setup.sh."
  exit 1
fi
LOOKAHEAD_HOURS=$(jq -r '.calendar.lookahead_hours' "$CONFIG_FILE")
PREP_WINDOW_START_HOURS=$(jq -r '.auto_prep.prep_window_start_hours' "$CONFIG_FILE")
PREP_WINDOW_END_HOURS=$(jq -r '.auto_prep.prep_window_end_hours' "$CONFIG_FILE")
EXCLUDE_KEYWORDS=$(jq -r '.calendar.event_filters.exclude_keywords | join(",")' "$CONFIG_FILE")

log "Config loaded: lookahead=${LOOKAHEAD_HOURS}h, prep window=${PREP_WINDOW_START_HOURS}h-${PREP_WINDOW_END_HOURS}h"

# Get upcoming events from gog
# In a real script, this would be a live `gog` call.
# For this placeholder, we'll use a mock JSON structure.
MOCK_EVENTS_JSON=$(cat <<-EOF
{
  "events": [
    {
      "id": "event123",
      "summary": "Client Pitch: Acme Corp",
      "start": "$(date -v+4H --iso-8601=seconds)",
      "attendees": ["[email protected]", "[email protected]"]
    },
    {
      "id": "event456",
      "summary": "Internal Sync",
      "start": "$(date -v+6H --iso-8601=seconds)",
      "attendees": ["[email protected]", "[email protected]"]
    },
    {
      "id": "event789",
      "summary": "Partnership Intro: BigCorp",
      "start": "$(date -v+22H --iso-8601=seconds)",
      "attendees": ["[email protected]", "[email protected]"]
    },
    {
      "id": "eventalreadyprepped",
      "summary": "Follow-up: Synergy Inc",
      "start": "$(date -v+8H --iso-8601=seconds)",
      "attendees": ["[email protected]", "[email protected]"]
    }
  ]
}
EOF
)

# Mock the history file for the "already prepped" event
jq -n '.events = {"eventalreadyprepped": "/path/to/brief.md"}' > "$HISTORY_FILE"


log "Fetching upcoming events..."
# UPCOMING_EVENTS=$(gog calendar list --start now --end "+${LOOKAHEAD_HOURS}h" --json)
UPCOMING_EVENTS="$MOCK_EVENTS_JSON"

EVENT_COUNT=$(echo "$UPCOMING_EVENTS" | jq '.events | length')
log "Found $EVENT_COUNT events in the next ${LOOKAHEAD_HOURS} hours."

PROCESSED_COUNT=0
PREPPED_COUNT=0

# Loop through events and decide whether to prep
echo "$UPCOMING_EVENTS" | jq -c '.events[]' | while read -r event; do
  PROCESSED_COUNT=$((PROCESSED_COUNT + 1))
  
  EVENT_ID=$(echo "$event" | jq -r '.id')
  SUMMARY=$(echo "$event" | jq -r '.summary')
  START_TIME=$(echo "$event" | jq -r '.start')
  
  log "Processing event: '$SUMMARY' ($EVENT_ID)"

  # 1. Check if already prepped
  if jq -e ".events[\"$EVENT_ID\"]" "$HISTORY_FILE" > /dev/null; then
    log "  -> Skipping: Already prepped."
    continue
  fi

  # 2. Check time window
  EVENT_START_TS=$(date -j -f "%Y-%m-%dT%H:%M:%S%z" "$START_TIME" "+%s")
  NOW_TS=$(date "+%s")
  HOURS_TO_EVENT=$(((EVENT_START_TS - NOW_TS) / 3600))
  
  if (( HOURS_TO_EVENT > PREP_WINDOW_START_HOURS || HOURS_TO_EVENT < PREP_WINDOW_END_HOURS )); then
    log "  -> Skipping: Event is at ${HOURS_TO_EVENT}h, outside window (${PREP_WINDOW_START_HOURS}h-${PREP_WINDOW_END_HOURS}h)."
    continue
  fi
  
  # 3. Check for external attendees (simple placeholder)
  HAS_EXTERNAL=$(echo "$event" | jq '[.attendees[] | select(contains("@example.com") | not)] | length > 0')
  if [ "$HAS_EXTERNAL" != "true" ]; then
    log "  -> Skipping: No external attendees found."
    continue
  fi
  
  # 4. Check for exclusion keywords
  SHOULD_EXCLUDE=false
  for keyword in $(echo "$EXCLUDE_KEYWORDS" | tr ',' ' '); do
    if [[ "${SUMMARY,,}" == *"$keyword"* ]]; then
      log "  -> Skipping: Summary contains excluded keyword '$keyword'."
      SHOULD_EXCLUDE=true
      break
    fi
  done
  [ "$SHOULD_EXCLUDE" = "true" ] && continue
  
  # If all checks pass, run prep
  log "  -> QUALIFIED. Running prep script for event ID: $EVENT_ID"
  PREPPED_COUNT=$((PREPPED_COUNT + 1))
  
  # Call the main prep script
  if bash "$PREP_SCRIPT" "$EVENT_ID"; then
    log "  -> Successfully prepped '$SUMMARY'."
  else
    log "  -> ERROR: Prep script failed for '$SUMMARY'."
  fi
done

log "Auto-prep cycle finished. Processed $PROCESSED_COUNT events, prepped $PREPPED_COUNT new meetings."

# Clean up mock history file
# In a real run, you wouldn't do this
[ -f "$HISTORY_FILE" ] && rm "$HISTORY_FILE"
echo '{"events":{}}' > "$HISTORY_FILE"

exit 0

```

### scripts/brief.sh

```bash
#!/bin/bash
# meeting-prep/scripts/brief.sh — Output a formatted briefing doc

set -euo pipefail

# --- CONFIG & ARGS ---
PREP_DIR="${PREP_DIR:-$HOME/.config/meeting-prep}"
HISTORY_FILE="$PREP_DIR/brief-history.json"
BRIEFS_DIR="$PREP_DIR/briefs"

TARGET="$1" # Can be a meeting ID or a path to a brief file
FORMAT="${2:---format markdown}"
shift 2

# --- FUNCTIONS ---

# Find the brief file path from a meeting ID
get_brief_path_from_id() {
  local event_id="$1"
  jq -r ".events[\"$event_id\"]" "$HISTORY_FILE"
}

# --- MAIN LOGIC ---
if [ -z "$TARGET" ]; then
  echo "Usage: $0 <meeting_id | brief_filepath> [--format <markdown|text|telegram>]"
  echo "Example: $0 event123"
  echo "Example: $0 $BRIEFS_DIR/2026-02-11-client-pitch.md"
  exit 1
fi

BRIEF_PATH=""
if [ -f "$TARGET" ]; then
  BRIEF_PATH="$TARGET"
else
  BRIEF_PATH=$(get_brief_path_from_id "$TARGET")
  if [ -z "$BRIEF_PATH" ] || [ "$BRIEF_PATH" == "null" ] || [ ! -f "$BRIEF_PATH" ]; then
    echo "Error: Brief not found for target '$TARGET'."
    echo "You can run prep first: prep.sh '$TARGET'"
    exit 1
  fi
fi

echo "Displaying brief: $BRIEF_PATH"
echo "Format: $FORMAT"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

# In a real implementation, you might use tools like `glow` for markdown,
# or format specifically for telegram's markdown variant.
# This placeholder just cats the file.
case "$FORMAT" in
  --format\ markdown)
    # For CLI, you might use a markdown renderer like glow
    if command -v glow &> /dev/null; then
      glow "$BRIEF_PATH"
    else
      cat "$BRIEF_PATH"
    fi
    ;;
  --format\ text)
    # Simple conversion placeholder
    sed 's/### /## /g; s/## /# /g; s/# /== /g; s/\*//g' "$BRIEF_PATH"
    ;;
  --format\ telegram)
    # Telegram uses a specific markdown subset.
    # This is a placeholder; a real script would be more careful.
    # e.g., escape characters like '-'
    cat "$BRIEF_PATH"
    ;;
  *)
    echo "Unknown format: $FORMAT"
    cat "$BRIEF_PATH"
    ;;
esac

```



---

## Skill Companion Files

> Additional files collected from the skill directory layout.

### _meta.json

```json
{
  "owner": "audsmith28",
  "slug": "meeting-prep-agent",
  "displayName": "Meeting Prep Agent",
  "latest": {
    "version": "1.1.0",
    "publishedAt": 1770842534758,
    "commit": "https://github.com/openclaw/skills/commit/c26d9ecc3444cc8b79ca504775a61337d66adc5c"
  },
  "history": []
}

```