March 22, 202614 min readai-agent-workflows

Turn Meeting Recordings into Action Items with AI CLI

Record a meeting, transcribe it locally with Whisper, then let an AI CLI agent extract decisions, action items, owners, and deadlines into structured output that pushes directly to Linear or GitHub Issues via MCP.

DH
Danny Huang

The Problem Everyone Pretends Does Not Exist

The meeting ended twelve minutes ago. You remember three things: someone mentioned a deadline, there was a disagreement about the API design, and you definitely volunteered for something -- but you cannot remember what.

This is not a personal failing. It is a structural one.

A one-hour meeting generates roughly 8,000 to 10,000 words of spoken language. The average person retains four to seven discrete items from short-term memory. The math is brutal: over 99% of what was said is gone within minutes. The few things that survive are whatever was said last (recency bias) and whatever caused an emotional reaction (the argument about the API). The quiet decision at minute 23 -- the one that actually matters -- evaporates.

Organizations have tried to solve this for decades. Someone takes notes. The notes are incomplete because the note-taker was also a participant. Someone records the meeting. The recording sits in a shared drive, untouched, because nobody has 58 minutes to re-watch a meeting they already attended. Someone sends a follow-up email summarizing the action items. The email is wrong because it was written from memory, which we just established is unreliable.

The real problem is not capturing information. It is extracting structure from chaos. A meeting transcript is a river of words where the important things are pebbles on the bottom -- decisions, action items, owners, deadlines -- buried under small talk, tangents, and someone explaining their screen sharing is not working.

What you need is a metal detector for that river. Something that scans the entire transcript and pulls out exactly the structured data that matters. Then puts it where it belongs: in your project tracker, with the right owner and the right deadline, without you lifting a finger.

That is what we are building.

What You Will Build

A pipeline that takes a meeting recording and produces tracked action items. The flow:

  1. Record the meeting (any format: .mp4, .webm, .m4a, .wav)
  2. Transcribe it locally with OpenAI Whisper -- no data leaves your machine
  3. Extract decisions, action items, owners, and deadlines using Claude Code
  4. Push the structured output to Linear or GitHub Issues via MCP

One command runs steps 2 through 4. You start with an audio file and end with tickets in your project tracker.

By the end of this article, you will have:

  • A local Whisper installation for privacy-preserving transcription
  • A CLAUDE.md extraction workflow that turns raw transcripts into structured JSON
  • MCP server connections to Linear and/or GitHub for automatic ticket creation
  • A shell script that chains the entire pipeline into a single command

Total setup: about 30 minutes. After that, meeting-to-tickets takes under 2 minutes per hour of recording.

Prerequisites

  • Claude Code v2.1+ with API access
  • Python 3.10+ (for Whisper)
  • ffmpeg installed (brew install ffmpeg on macOS)
  • Node.js 18+ (for MCP servers)
  • A Linear account with an API key, or GitHub CLI (gh) authenticated

If you have never set up MCP servers before, the Build Your First MCP Server tutorial covers the fundamentals in 20 minutes.

Step 1: Install Whisper for Local Transcription

Whisper is OpenAI's open-source speech-to-text model. It runs entirely on your machine. No API calls, no cloud uploads, no privacy concerns. This matters -- meeting recordings often contain sensitive business information that should not leave your infrastructure.

Install it:

pip install openai-whisper

Verify the installation:

whisper --help

Whisper ships with several model sizes. The trade-off is speed versus accuracy:

ModelParametersEnglish AccuracySpeed (1hr audio)VRAM
tiny39M~85%~2 min~1 GB
base74M~88%~3 min~1 GB
small244M~92%~6 min~2 GB
medium769M~95%~12 min~5 GB
large-v31.5B~97%~25 min~10 GB

For meeting transcription, medium is the sweet spot. It catches names, technical terms, and cross-talk well enough that the downstream AI extraction works reliably. If you have a GPU with 10+ GB VRAM, large-v3 is better. If you are on a laptop CPU, small is the practical ceiling.

Test it on a sample recording:

whisper meeting-recording.m4a --model medium --language en --output_format txt

This produces meeting-recording.txt in the current directory. Open it. You will see a raw transcript -- no speaker labels, no timestamps in the text body (though Whisper can output those separately). The transcript is messy, full of filler words and false starts. That is fine. The AI agent's job is to find structure in that mess.

Alternative: faster-whisper. If Whisper's speed is a bottleneck, faster-whisper is a CTranslate2-based re-implementation that runs 2-4x faster with the same accuracy. Install with pip install faster-whisper and use the same model names.

Step 2: Configure MCP Servers for Ticket Creation

The extraction pipeline needs somewhere to push the action items it finds. Configure MCP servers for your project tracker.

Option A: Linear

{
  "mcpServers": {
    "linear": {
      "command": "npx",
      "args": ["-y", "@linear/mcp-server"],
      "env": {
        "LINEAR_API_KEY": "lin_api_your_key_here"
      }
    }
  }
}

Option B: GitHub Issues

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_your_token_here"
      }
    }
  }
}

Add whichever you use to your project's .mcp.json. Restart Claude Code and run /mcp to verify the server shows green status.

Important: Store tokens in environment variables, not in .mcp.json directly. The examples above show inline values for clarity only.

Step 3: Write the CLAUDE.md Extraction Workflow

This is the core of the pipeline. The CLAUDE.md tells Claude Code exactly how to parse a meeting transcript and what structured data to extract.

Add this to your project's CLAUDE.md:

## Meeting Transcript Extraction Workflow

When I provide a meeting transcript, follow this sequence:

### Phase 1: Identify Structure
1. Scan the full transcript. Identify distinct topics or agenda items discussed.
2. For each topic, note the approximate position in the transcript (beginning, middle, end).
3. Identify all participants mentioned by name or role.

### Phase 2: Extract Decisions
For each decision made during the meeting, extract:
- **Decision:** What was decided, in one sentence.
- **Context:** Why it was decided (the key argument or data point).
- **Decider:** Who made or ratified the decision.
- **Dissenters:** Anyone who disagreed (and their objection, briefly).

### Phase 3: Extract Action Items
For each action item, extract:
- **Task:** What needs to be done, in one sentence. Be specific.
- **Owner:** Who is responsible. If unclear, mark as "UNASSIGNED".
- **Deadline:** When it is due. If no deadline was stated, mark as "NO DEADLINE".
- **Priority:** Infer from context -- P0 if blocking others, P1 if mentioned as urgent,
  P2 for everything else.
- **Dependencies:** Other action items or external factors this depends on.

### Phase 4: Extract Open Questions
Items discussed but not resolved:
- **Question:** What remains unanswered.
- **Assigned to:** Who was asked to follow up (if anyone).
- **Context:** Why it matters.

### Output Format
Return a JSON object with this structure:
{
  "meeting_date": "YYYY-MM-DD",
  "participants": ["name1", "name2"],
  "topics": ["topic1", "topic2"],
  "decisions": [...],
  "action_items": [...],
  "open_questions": [...]
}

### Rules
- Extract only what was explicitly stated. Do not infer action items from vague
  discussion. "We should probably look into caching" is an open question, not an
  action item -- unless someone said "I will look into caching by Friday."
- Attribute by name when possible. If the transcript says "someone suggested," use
  the context to identify who. If genuinely unclear, mark as "UNATTRIBUTED."
- Deadlines must be explicit. "Soon" or "next week" should be captured verbatim,
  not converted to dates.
- Preserve disagreements. If the decision was contentious, the dissent is as
  important as the decision.

This workflow follows the same CLAUDE.md writing principles used across all agent workflows: specific inputs, structured output, explicit rules for ambiguous cases.

Step 4: Chain It Together

Here is the shell script that runs the full pipeline:

#!/bin/bash
# meeting-to-tickets.sh
# Usage: ./meeting-to-tickets.sh recording.m4a

set -euo pipefail

RECORDING="$1"
BASENAME="${RECORDING%.*}"
TRANSCRIPT="${BASENAME}.txt"
EXTRACTION="${BASENAME}-extraction.json"

echo "Step 1: Transcribing with Whisper..."
whisper "$RECORDING" --model medium --language en --output_format txt --output_dir .

echo "Step 2: Extracting structured data with Claude Code..."
claude -p "Read the file ${TRANSCRIPT} and run the meeting transcript extraction workflow. Output the JSON to ${EXTRACTION}." --allowedTools "Read,Write,mcp__linear__*,mcp__github__*"

echo "Step 3: Creating tickets..."
claude -p "Read ${EXTRACTION}. For each action item, create a Linear issue (or GitHub Issue) with the task as the title, the owner in the description, the deadline in the due date field, and the priority mapped to the tracker's priority levels. Skip items marked UNASSIGNED -- list those separately at the end for manual review." --allowedTools "Read,mcp__linear__*,mcp__github__*"

echo "Done. Extraction saved to ${EXTRACTION}"

Make it executable:

chmod +x meeting-to-tickets.sh

Run it:

./meeting-to-tickets.sh weekly-planning-2026-03-22.m4a

The script runs in three clean stages. Whisper transcribes. Claude Code extracts. Claude Code creates tickets. Each stage produces an artifact you can inspect: the transcript file, the extraction JSON, and the tickets in your tracker.

Why three stages instead of one? Debuggability. If the transcription is bad, you fix the Whisper model choice. If the extraction misses items, you adjust the CLAUDE.md workflow. If the tickets are formatted wrong, you tune the ticket creation prompt. Each stage is independently fixable.

Step 5: Review the Output

After the first run, open the extraction JSON. It looks like this:

{
  "meeting_date": "2026-03-22",
  "participants": ["Alice", "Bob", "Carol", "Dave"],
  "topics": [
    "Q2 roadmap priorities",
    "API versioning strategy",
    "Hiring timeline for senior backend role"
  ],
  "decisions": [
    {
      "decision": "Adopt URL-based API versioning (v2/endpoint) instead of header-based",
      "context": "Header-based versioning caused issues with CDN caching in production",
      "decider": "Alice",
      "dissenters": ["Bob -- preferred header-based for cleaner URLs"]
    }
  ],
  "action_items": [
    {
      "task": "Write the API versioning migration guide for external developers",
      "owner": "Bob",
      "deadline": "end of next sprint",
      "priority": "P1",
      "dependencies": ["API v2 endpoints must be deployed to staging first"]
    },
    {
      "task": "Schedule interviews for senior backend candidates next week",
      "owner": "Carol",
      "deadline": "next Friday",
      "priority": "P1",
      "dependencies": []
    },
    {
      "task": "Benchmark new caching layer under production-like load",
      "owner": "Dave",
      "deadline": "NO DEADLINE",
      "priority": "P2",
      "dependencies": ["Staging environment provisioned"]
    }
  ],
  "open_questions": [
    {
      "question": "Should the v1 API have a hard deprecation date or stay in maintenance indefinitely?",
      "assigned_to": "Alice",
      "context": "Affects how aggressively we push partners to migrate"
    }
  ]
}

Check three things:

  1. Are the action items real? Compare against your own memory of the meeting. The agent should not fabricate tasks from vague discussion.
  2. Are the owners correct? Name attribution from transcripts is imperfect. Whisper does not label speakers, so the agent infers from context ("I will handle that" + surrounding dialogue).
  3. Are the decisions accurate? The dissent field is especially important -- it captures the nuance that a simple summary would lose.

Improving Accuracy: Speaker Diarization

The biggest weakness of basic Whisper transcription is the lack of speaker labels. When the transcript says "I'll handle the migration guide," the agent has to guess who "I" is from context. Sometimes it guesses wrong.

Speaker diarization -- the process of labeling who speaks when -- solves this. Add it with whisperX, a Whisper extension:

pip install whisperx

Replace the Whisper step in your script:

whisperx "$RECORDING" --model medium --language en --diarize --output_format txt --output_dir .

The output now includes speaker labels:

[SPEAKER_00] Let's move on to the API versioning decision.
[SPEAKER_01] I think we should go with URL-based. The header approach broke caching.
[SPEAKER_02] I disagree. Header-based keeps the URLs clean.
[SPEAKER_00] Alright, we'll go with URL-based. Bob, can you write the migration guide?
[SPEAKER_02] Sure, I'll have it done by end of sprint.

The labels are SPEAKER_00, SPEAKER_01, etc. You can add a mapping section to your CLAUDE.md:

### Speaker Mapping
When processing diarized transcripts, use this mapping:
- SPEAKER_00 = Alice (Engineering Manager)
- SPEAKER_01 = Dave (Backend Engineer)
- SPEAKER_02 = Bob (API Lead)
- SPEAKER_03 = Carol (Recruiting)

Update this mapping for each recurring meeting group. For ad-hoc meetings, the agent can often figure out names from the transcript itself ("Thanks, Bob" or "Carol, can you handle hiring?").

Tuning the Workflow

After a few runs, you will notice patterns worth adjusting.

Too many action items. The agent might extract every vague suggestion as a task. Tighten the CLAUDE.md rule: Only extract action items where a specific person committed to a specific deliverable. Vague suggestions go in open_questions.

Missing deadlines. If your team does not state deadlines explicitly, add a rule: If no deadline is stated but the task is P0 or P1, mark the deadline as "NEEDS DEADLINE -- follow up with owner."

Wrong attribution. Without diarization, attribution errors are inevitable. Add a confidence field: For each action item owner, include a confidence score (high/medium/low). High = name was explicitly stated. Medium = inferred from context. Low = guessing.

Non-English meetings. Whisper supports 99 languages. Change --language en to your meeting language. Claude Code handles multilingual extraction natively. The CLAUDE.md can stay in English even if the transcript is in Japanese -- the agent adapts.

Automating Recurring Meetings

For weekly standups, sprint planning, or retrospectives that repeat on a schedule, automate the entire flow.

Add a shell alias:

alias meeting='./meeting-to-tickets.sh'

Or create per-meeting aliases:

alias sprint-planning='./meeting-to-tickets.sh ~/recordings/sprint-planning-latest.m4a'
alias retro='./meeting-to-tickets.sh ~/recordings/retro-latest.m4a'

If your recording tool saves files to a known directory, a cron job or filesystem watcher can trigger the pipeline automatically when a new recording appears:

# Watch for new recordings and process them
fswatch -0 ~/recordings/*.m4a | while IFS= read -r -d '' file; do
  ./meeting-to-tickets.sh "$file"
done

Now the workflow is fully hands-free: the meeting ends, the recording saves, the pipeline triggers, and tickets appear in your tracker. You review them over coffee.

The Multi-Pane Advantage

When debugging this pipeline, you are juggling three stages simultaneously. The Whisper transcription might produce garbled output for a section where multiple people talked over each other. The extraction might miss an action item. The ticket creation might map priorities incorrectly.

The productive setup: Whisper output streaming in one pane, the Claude Code extraction session in another, and your Linear or GitHub board in a third. When Whisper finishes, you can eyeball the transcript quality before the extraction starts. When extraction finishes, you review the JSON before tickets are created. Each stage is visible without switching windows.

For recurring meetings, the layout stabilizes: the main pane shows the latest extraction output, a side pane shows the tickets being created in real time, and a third holds the transcript for spot-checking when an action item looks wrong.

Try Termdock Multi Terminal Layout works out of the box. Free download →

Why CLI Beats Chat for This Workflow

You could paste a meeting transcript into a chat interface and ask for action items. People do this. It works for one-off use. But the CLI approach is fundamentally different in three ways.

First, scriptability. The shell script chains Whisper, Claude Code, and MCP ticket creation into a single command. A chat interface requires manual copy-paste at every stage.

Second, privacy. Whisper runs locally. The transcript never leaves your machine until the extraction step, and even then you control exactly which MCP servers receive data. A chat interface uploads the full transcript to a cloud service.

Third, repeatability. The CLAUDE.md workflow produces consistent extraction across every meeting. A chat prompt depends on how carefully you phrase it each time. The shell script is version-controlled. The chat prompt is ephemeral.

For a deeper comparison of AI CLI tools and their capabilities, the 2026 AI CLI Tools Guide covers the full landscape.

Recap

Meetings produce decisions that evaporate. The information exists -- it was spoken aloud in a room -- but it disappears into the gap between human memory and project trackers.

The fix is a three-stage pipeline. Whisper transcribes locally, preserving privacy. Claude Code extracts structured data -- decisions, action items, owners, deadlines -- using a well-defined CLAUDE.md workflow. MCP servers push the results to Linear or GitHub Issues as real tickets with real owners.

The total setup: Whisper installed, one MCP server configured, one CLAUDE.md workflow block, and one shell script. After that, the gap between "we decided in the meeting" and "there is a ticket for it" closes to under two minutes. The meeting that used to happen again two weeks later because nobody tracked the action items -- that meeting stops happening.

DH
Free Download

Ready to streamline your terminal workflow?

Multi-terminal drag-and-drop layout, workspace Git sync, built-in AI integration, AST code analysis — all in one app.

Download Termdock →
#ai-agent#mcp#meeting-notes#whisper#workflow-automation#claude-code#ai-cli

Related Posts