Free for 30 days on Scale.Start free
Meeting follow-up and action item extraction
Every step in the template

Meeting follow-up and action item extraction

A workspace where every meeting becomes a follow-up email or Slack post + a sectioned meeting log in Dock + one Action items row per task. Nothing said in a meeting falls through the cracks.

Outcome

A workspace where every meeting becomes a follow-up email or Slack post + a sectioned meeting log in Dock + one Action items row per task. Nothing said in a meeting falls through the cracks.

Time45 min setup, ongoing zero touch (transcripts flow in)DifficultybeginnerForOperators, ops leads, and EAs at $5M-$50M revenue companies running 5+ meetings per week.
How this works

Open it, hand it to your agent, walk the steps.

Paste this to your agent (Claude / Cursor / Codex)
You are the agent running on the "Meeting follow-up and action item extraction" template workspace, connected via MCP at your-org/meeting-followup-action-items.

Your job: 3x per weekday, scan for new transcripts, extract decisions + action items, send follow-up, append Meetings doc section, write Action items rows. Never mark an action item Done.

User-loop protocol:
- You propose. The owner decides. Never mark an Action items row as Done; that's owner-controlled when they complete the task.
- 3x per weekday at 9 AM / 1 PM / 5 PM (or "process new transcripts"): load processed_transcripts.json. Fetch new transcripts from either TRANSCRIPT_DIR (local folder) or Fireflies (FIREFLIES_API_KEY + FIREFLIES_LOOKBACK_HOURS).
- For each transcript whose ID is not in processed_transcripts.json:
  - extract_meeting_data() via Claude: meeting_title, meeting_date, attendees (name + email), summary (2-3 sentences), decisions (list), action_items (list with item + owner + due_date + priority).
  - append_meeting_summary() to Meetings doc: new section with title + date + attendees + summary + decisions + action items as markdown.
  - append_action_items() to Action items table: one row per action item with Status=Open.
  - If FOLLOWUP_EMAIL=true: resolve attendee emails via participants.json + transcript, send via SMTP.
  - If FOLLOWUP_SLACK=true: post Block Kit summary to SLACK_CHANNEL.
  - Append transcript ID to processed_transcripts.json.
- End of every run, write 1 paragraph to Status: transcripts processed, action items extracted, follow-ups sent, anything skipped.

Don't touch:
- processed_transcripts.json from prior runs (only append; never delete).
- An Action items row's Status after creation (owner-controlled; agent only writes Status=Open on creation).
- A Meetings doc section from a prior run.
- participants.json (operator-edited; agent only reads).

First MCP tool calls:
1. list_surfaces(workspace_slug="meeting-followup-action-items")
2. list_rows(workspace_slug="meeting-followup-action-items", surface_slug="action-items")
3. get_doc(workspace_slug="meeting-followup-action-items", surface_slug="status")
The template · 5 steps

Top to bottom. Each step has tasks, pointers, gotchas.

Pick transcript source + follow-up channel

10 min

Two operator decisions: where do transcripts come from, and where does the follow-up go. Local folder (drag .txt files in) is the simplest path. Fireflies is hands-off but needs an account. Follow-up channel can be email (attendees), Slack (team channel), or both.

Tasks
  • Ask the operator: do they have Fireflies, Gong, or Zoom AI? If Fireflies, grab the API key from the dashboard. If not, plan on local folder.
  • Ask: where should follow-ups land? Email to attendees (most personal), Slack post (faster + team-visible), or both.
  • If email: get SMTP credentials. Gmail App Passwords work; require 2FA on the Google account first.
  • If Slack: create a bot token with chat:write or use an incoming webhook for a channel.
  • If attendee emails aren't in the transcripts: populate participants.json mapping names (exactly as they appear in transcripts) to email addresses.
Gotchas
  • participants.json name matching. Names must match how they appear in the transcript exactly. After the first run, open the Meetings doc and check the Attendees line; copy those exact strings into participants.json as keys.
  • Self-email. If the operator's name is in participants.json, the script sends them their own follow-up. To skip, remove their entry or add a filter in send_email_followup().

Wire .env + the Python script

20 min

One script: extract_followup.py runs 3x per weekday. Reads new transcripts, runs extract_meeting_data() via Claude, appends to Meetings doc, writes Action items rows, sends follow-up. Idempotent via processed_transcripts.json.

Tasks
  • Open Setup guide (doc) and copy extract_followup.py into a local folder
  • Run pip install anthropic requests python-dotenv
  • Create .env with DOCK_API_KEY, DOCK_WORKSPACE_SLUG, ANTHROPIC_API_KEY, TRANSCRIPT_DIR (or FIREFLIES_API_KEY + FIREFLIES_LOOKBACK_HOURS), FOLLOWUP_EMAIL=true/false, FOLLOWUP_SLACK=true/false, SMTP_HOST + SMTP_USER + SMTP_PASSWORD (if email), SLACK_BOT_TOKEN + SLACK_CHANNEL (if Slack), PARTICIPANTS_FILE=./participants.json, CLAUDE_MODEL=claude-sonnet-4-6
  • Generate a Dock API key at trydock.ai/settings/api
  • Set up the Action items table column schema explicitly: Meeting, Item, Owner, Due Date, Priority, Status (all text).
Gotchas
  • Long transcripts. The script uses a bookend window (first half + last half, up to 15K chars) to capture both opening context AND end-of-meeting action items. Going larger blows the token budget; smaller misses the wrap-up.
  • FIREFLIES_LOOKBACK_HOURS. Default 6. If the script runs every 4 hours, 6 is the right safety margin. Smaller windows can miss meetings whose transcript finished processing late.

Test with one transcript

20 min

Before scheduling, run a real transcript through the manual path. Drop a .txt file into TRANSCRIPT_DIR, run the script, walk through what got extracted with the operator + an attendee.

Tasks
  • Drop a recent meeting transcript (.txt or .md) into TRANSCRIPT_DIR. Or confirm a recent Fireflies meeting is within FIREFLIES_LOOKBACK_HOURS.
  • Run python extract_followup.py
  • Open Meetings (doc). Confirm a new section appeared with title + attendees + summary + decisions + action items.
  • Open Action items (table). Confirm one row per extracted task with Owner + Due Date + Priority + Status=Open.
  • Check the follow-up email (or Slack post). Confirm tone, attendees, formatting.
  • Walk through with an attendee: do the action items match what they remember? If not, edit the extract_meeting_data() prompt to bias toward (or away from) implicit commitments.
Gotchas
  • Extraction quality depends on transcript clarity. Calls where everyone said 'sure' instead of 'John will follow up by Friday' produce fewer action items. The agent extracts only explicit assignments; that's intentional.
  • Names in transcripts. Fireflies often gets first names only. participants.json keys should match exactly: if Fireflies says 'John', the key is 'John', not 'John Smith'.
Agent prompt for this step
Run a first transcript through the pipeline. Load processed_transcripts.json. Fetch new transcripts from TRANSCRIPT_DIR or Fireflies. For each unprocessed transcript: extract_meeting_data() via Claude (title, attendees, summary, decisions, action_items). append_meeting_summary() to Meetings doc. append_action_items() to Action items table with Status=Open. Send follow-up via email + Slack per config. Append transcript ID to processed_transcripts.json. Post a Status entry: transcripts processed, action items extracted, follow-ups sent.

Schedule the 3x-per-weekday scan

10 min

Once test runs are clean, schedule. 9 AM catches overnight + early-morning meetings; 1 PM catches mid-morning; 5 PM catches afternoon. Weekdays only by default; flip to every day if you run weekend meetings too.

Tasks
  • Option A, cron: crontab -e, add `0 9,13,17 * * 1-5 cd /path && source .env && python3 extract_followup.py >> meeting_followup.log 2>&1`
  • Option B, CueAPI: cueapi create --schedule '0 9,13,17 * * 1-5' --timezone 'America/New_York' --name 'meeting-followup' --handler ./extract_followup.py
  • Confirm next day: Status has at least one fresh session entry. If a meeting was held, its transcript got processed.
Gotchas
  • If meetings span timezones, pick the operator's tz for the cron. CueAPI's --timezone flag is explicit.
  • Closed laptop = no run. Switch to CueAPI for cloud-scheduled if your machine isn't always on.

Make the Action items table the team's source of truth

5 min one-time

The whole flow only works if the team actually looks at the Action items table. Pin the URL in Slack, add it to weekly retros, treat any open item past its due date as a follow-up.

Tasks
  • Pin the Action items URL (trydock.ai/[org]/meeting-followup-action-items/action-items) to the team Slack channel
  • Add the table to weekly retros: walk through anything still Status=Open past its Due Date.
  • Owners flip Status=Done as they complete tasks. Archive Done rows periodically (or filter the view to Open only).
  • If an owner consistently lets items slip, that's a coaching conversation, not a script tune.
Gotchas
  • Owners controlling Status is intentional. The agent never marks Done; only the owner can. Reps appreciate that.
  • Drift between transcripts and assigned owners. If Claude mis-attributes (e.g. assigns to the meeting host when someone else volunteered), edit the Owner column on the row directly. Future meetings re-extract from scratch.
FAQ

Common questions on this template.

Does this work without Fireflies?
Yes. Set TRANSCRIPT_DIR to a local folder and drop .txt or .md transcripts in there. The script picks them up on the next scan. Useful for teams that record on Zoom or Otter but don't have a Fireflies account.
What if the transcript doesn't include attendee emails?
Populate participants.json with name-to-email mappings. The keys must match the names exactly as they appear in the transcript. The Meetings doc section shows the extracted names after the first run; copy those strings into participants.json.
Does the agent ever mark action items as done?
No. The owner does that. The agent writes new rows with Status=Open. Owners flip to Done as they complete. This is intentional, owners object to a bot closing things out from under them.
Can I add a Day 14 reminder for overdue action items?
Yes. The Extending section in Setup guide shows the pattern: a second script (overdue_reminder.py) runs daily, reads the Action items table, filters Status=Open + Due Date in the past, sends a Slack DM to each owner with their overdue rows.
What if Claude extracts action items that aren't real commitments?
Edit the extract_meeting_data() prompt to be stricter: 'Extract only explicit action items where someone said I will or NAME will. Do not infer.' Default already biases toward explicit assignments. If you need implicit + explicit, swap the language the other way.

Open this template as a workspace.

We mint a fresh copy in your org with the steps as table rows, the pointers as a separate table, and the brief as a doc. Bring your agents, start checking off boxes.