Dotfiles summarize-meetings
Use when processing, summarizing, or extracting insights from meeting notes in the Obsidian vault. Triggers on "summarize meetings", "process meetings", "meeting summaries", "extract from meetings", "meeting insights".
git clone https://github.com/harperreed/dotfiles
T=$(mktemp -d) && git clone --depth=1 https://github.com/harperreed/dotfiles "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/summarize-meetings" ~/.claude/skills/harperreed-dotfiles-summarize-meetings && rm -rf "$T"
.claude/skills/summarize-meetings/SKILL.mdSummarize Meetings
Process meeting transcripts from
Meetings/transcripts/ — extract people, action items, project ideas, blog ideas, knowledge graph connections, concepts, and general ideas. Populate the vault knowledge graph and generate rich summary files.
Campaign Workflow
Processing works in monthly batches, most-recent month first. Each month follows this cycle:
digraph campaign { rankdir=TB; "Scan month (ls -lS)" -> "Triage: check small/suspicious files"; "Triage: check small/suspicious files" -> "Identify skips vs substantive"; "Identify skips vs substantive" -> "Dispatch wave of agents (10-15)"; "Dispatch wave of agents (10-15)" -> "Wait for returns"; "Wait for returns" -> "Dispatch remaining agents"; "Dispatch remaining agents" -> "All agents returned"; "All agents returned" -> "Compile monthly report table"; "Compile monthly report table" -> "Post social media update"; "Post social media update" -> "Next month or stop"; }
Step 1: Scan the Month
ls -lS "Meetings/transcripts/" | grep "YYYY-MM"
List all transcripts for the target month, sorted by size. This gives you:
- Total count of transcripts
- File sizes (critical for triage and agent instructions)
- Filenames for slug generation
Step 2: Check for Existing Summaries
ls "Meetings/" | grep "YYYY-MM.*summary"
Skip any transcript that already has a corresponding summary file.
Step 3: Triage
Before dispatching agents, manually check files that are suspicious:
| Signal | Action |
|---|---|
| < 2K | Read the file — likely empty stub or sparse notes |
| 2K-6K | Skim the file — may be scheduling fragment, garbled recording, or logistics-only |
| Filename says "untitled" | Almost always empty — read to confirm |
| Known non-meeting patterns | Medical appointments, kid brainstorming, screen-sharing setup, recording process discussions |
Skip criteria (with log entry):
- Empty stubs (template only, no content)
- < 20 words of real content after frontmatter
- Garbled/corrupted recordings
- Scheduling fragments (just logistics, no substance)
- Medical/personal appointments
- Kid content (school brainstorming, etc.)
- Recording process discussions (just setting up Granola)
- Screen-sharing setup conversations
Sparse but substantive notes (like handwritten bullet points from a real meeting) should still be processed — even 1.2K of real fundraising notes is worth a summary.
Step 4: Dispatch Parallel Agents
Spawn one Task agent per transcript using
subagent_type: general-purpose with mode: bypassPermissions and run_in_background: true.
Wave sizing: Dispatch 10-15 agents per wave. Wait for returns, then dispatch remaining agents. This prevents overwhelming the system while maintaining parallelism.
Large file instructions: For files > 50K, include "read in chunks using offset/limit" in the agent prompt. For files > 100K, explicitly say "this is a large file — read in chunks of 500-1000 lines using offset/limit parameters."
Agent prompt template:
You are a meeting summarizer for Doctor Biz's Obsidian vault at `/Users/harper/Public/Notes/Harper Notes/`. Read the transcript at `[PATH]` ([SIZE] — [read in chunks if large]). Then: 1. Extract: People, Action Items, Project Ideas, Blog Ideas, Knowledge Graph, Concepts, Ideas 2. Write summary to `Meetings/YYYY-MM-DD-slugified-name-summary.md` 3. Create/update People notes in `People/Firstname Lastname.md` (Title Case) — check if they exist first 4. Create Concept notes in `Concepts/` for genuinely reusable insights Use the full summary template with YAML frontmatter (title, date, tags, type, source, status, related). Write a strong 2-4 paragraph narrative meeting summary. Use `[[wiki-links]]` throughout. Never fabricate info not in the transcript. Don't create People stubs for first-name-only references.
Step 5: Compile Monthly Report
After all agents return, present a summary table:
| Meeting | Date | People | Actions | Concepts | Status | |---------|------|--------|---------|----------|--------| | harper-john | Jan 31 | 1 | 5 | 3 | Done | | untitled | Jan 15 | - | - | - | Skipped (empty) |
Include: total processed, total skipped (with reasons), and notable highlights (interesting concepts, key people).
Step 6: Social Media Update
Post a completion update via
mcp__socialmedia__create_post with:
- Month completed
- Count of summaries processed
- Notable highlights (key meetings, interesting concepts)
- Tags:
["meeting-summaries", "month-year", "vault-curation"]
Transcript Format: Granola
Most transcripts come from Granola and have this structure:
--- doc_id: uuid source: granola created_at: ISO timestamp title: Meeting Title participants: - Person Name duration_seconds: N labels: [] creator: '[[Harper Reed]]' attendees: - '[[Person Name]]' summary_text: |- ### Section Header - Bullet points of AI-generated summary generator: muesli 1.0 --- # Meeting Title _Date: YYYY-MM-DD_ ## Participants - **Name**, Role, Company, (email) ## Notes (Granola-captured notes — may be sparse or detailed) --- ## Transcript Speaker 1: ... Speaker 2: ...
Key fields to use:
— canonical list of who was thereattendees
— Granola's AI summary (useful cross-reference but don't rely solely on it)summary_text
— sometimes has role/company infoparticipants- The transcript body has the real content
Common transcript quirks:
- Speaker attribution may be missing or wrong
- Names may be misspelled or use nicknames
- Some transcripts lack
entirelysummary_text - Very long transcripts (100K+) may have repetitive content from multi-hour sessions
Determining "Substantive"
A note is not substantive if:
- Body content (after frontmatter) is only template skeleton with no filled-in content
- Body has fewer than 20 words of actual content (excluding headings,
, empty bullets)--- - All discussion/notes sections are blank
- Content is garbled/corrupted (random characters, no coherent sentences)
- Content is purely logistics (scheduling, screen sharing setup)
Skip these with a log entry. Don't waste a summary on nothing.
Extraction Categories
For each substantive meeting note, extract:
1. People
- Full names mentioned in content or attendees
- Role/company/context if discernible
- Relationship to Doctor Biz if clear
2. Action Items
- Explicit tasks (
, "need to", "should", "will", "action:")- [ ] - Owner if identifiable
- Due dates if mentioned
- Preserve existing Obsidian Tasks syntax items
3. Project Ideas
- Products, tools, apps, or ventures discussed
- Both existing projects and new ideas
- Brief description of what was discussed about each
4. Blog Ideas
- Topics worth writing about publicly
- Interesting takes or contrarian views expressed
- Experiences worth sharing
5. Knowledge Graph Ideas
- Connections between entities (people ↔ projects, concepts ↔ people)
- Relationships worth capturing as wiki-links
- Patterns across meetings (if processing a batch)
6. Concepts
- Mental models, frameworks, or reusable ideas
- Strategic insights or principles discussed
- Technical concepts worth an atomic note
- Must be genuinely reusable — not just a topic that was discussed
- Check vault first — enrich existing concept notes rather than creating duplicates
7. Ideas
- General ideas that don't fit the above categories
- Shower thoughts, brainstorms, what-ifs
- Anything interesting that was floated
Vault Graph Updates
People Notes
For each person extracted:
- Check if
exists (search case-insensitively, check aliases)People/Firstname Lastname.md - If exists: Add meeting reference to
frontmatter. Append new context to Notes section. Updaterelated
if this meeting is more recent.last-contact - If not exists and full name is known: Create stub using Person template (below)
- If only first name: Do NOT create a stub. Document them in the summary's people table with whatever context is available.
Name resolution:
- Transcript may misspell names — cross-reference with
frontmatter and existing vault notesattendees - Nicknames in transcript (e.g., "Dens" for Dennis Crowley, "JB" for John Borthwick) — match to existing People notes and add as aliases
- When uncertain if a first-name reference matches an existing person, note the ambiguity rather than guessing
People note stub template:
--- title: "Firstname Lastname" date: YYYY-MM-DD tags: [people] aliases: [] type: person company: (if known from meeting) role: (if known from meeting) how-we-met: "Met in [[Meeting Note Title]] context" last-contact: YYYY-MM-DD status: active related: ["[[Summary File]]"] --- # Firstname Lastname ## Context - **Company/Org:** (if known) - **Role:** (if known) - **How we met:** From [[Meeting Note Title]] ## Notes - (context extracted from meeting) ## Key Quotes ## Action Items
File naming:
People/Firstname Lastname.md — Title Case, NEVER kebab-case for people.
Concept Notes
For concepts worth capturing in
Concepts/:
Before creating a new concept note:
- Search
for existing notes on the same topicConcepts/ - Check aliases and related terms
- If a related concept exists, enrich it with new evidence/connections rather than creating a duplicate
- Only create a new note if the insight is genuinely distinct and reusable
--- title: "Concept Name" date: YYYY-MM-DD tags: [concept] type: concept status: active related: ["[[Summary File]]", "[[Person Who Articulated It]]"] --- # Concept Name ## What is it? (extracted from meeting context) ## Why it matters (inferred from discussion) ## Connections - [[Summary File]] - [[Person]] — who articulated or contributed to this concept ## Sources / References - [[Summary File]] — extracted from meeting on YYYY-MM-DD
Project Stubs
For projects mentioned that don't exist in
Projects/:
--- title: "Project Name" date: YYYY-MM-DD tags: [project] type: project status: active started: YYYY-MM-DD related: ["[[Summary File]]"] --- # Project Name Mentioned in [[Summary File]]: (brief context)
Summary File Format
Write to:
Meetings/YYYY-MM-DD-slugified-meeting-title-summary.md
Slug generation: Use the most descriptive part of the filename. Drop common prefixes like "hangout-", "call-", "harper-reed-and-". Keep it recognizable.
--- title: "Summary: Meeting Title" date: YYYY-MM-DD tags: [meeting-summary] type: meeting source: "[[Original Transcript Filename]]" status: reference related: ["[[Person 1]]", "[[Project X]]", "[[Concept Y]]"] ---
# Summary: Meeting Title > Source: [[Original Transcript Filename]] > Date: Month DD, YYYY > Attendees: [[Person 1]], [[Person 2]] ## Meeting Summary (A strong 2-4 paragraph narrative summary capturing the substance of the conversation. What was the meeting about? What were the key themes? What decisions were made or directions set? What was the energy/vibe? This should read like a well-written meeting recap that someone who wasn't there could read and fully understand what happened and why it mattered.) ## Key Topics (Organized by discussion thread — use subheadings for distinct topics) ## People | Person | Role/Context | |--------|-------------| | [[Person Name]] | context/role/relevance from this meeting | ## Action Items - [ ] Task description — owner if known ## Project Ideas - [[Project Name]] — what was discussed, potential next steps ## Blog Ideas - **Idea title** — why it's worth writing about, angle to take ## Knowledge Graph - [[Entity A]] ↔ [[Entity B]] — nature of relationship/connection ## Concepts - [[Concept Name]] — brief description and why it matters ## Ideas - Idea description — enough context to act on later ## Key Quotes > "Notable quote" — [[Speaker]]
What NOT To Do
- Never delete or modify the original transcript
- Never strip existing links or tags from the original
- Never create duplicate People notes — check existing vault first, use aliases
- Never create duplicate Concept notes — enrich existing ones instead
- Never modify Dataview or Tasks query blocks in any note
- Never fabricate information not present in the meeting notes — extract only what's there
- Don't create People stubs for ambiguous first-name-only references unless context makes identity clear
- Don't create concept notes for trivial or obvious things — only genuinely reusable insights
- Don't create concept notes that overlap significantly with existing ones — add to the existing note instead
- Don't process medical appointments, kid content, or recording setup conversations
- Don't rely solely on Granola's
— always read the actual transcriptsummary_text