Skip to main content

Meeting Minutes Action Items

Extract action items and generate structured meeting minutes from meeting transcripts.

Problem Statement

Who: Project managers, team leads, executive assistants
Why: Manual note-taking misses details. Automated extraction ensures nothing falls through the cracks.

What You’ll Build

A recipe that analyzes meeting transcripts and produces structured minutes with action items.

Input/Output Contract

InputTypeRequiredDescription
transcript_textstringYesMeeting transcript
attendeesarrayNoList of attendee names
formatstringNoOutput format: markdown or json
OutputTypeDescription
minutesstringFormatted meeting minutes
action_itemsarrayExtracted action items with assignees
okbooleanSuccess indicator

Prerequisites

export OPENAI_API_KEY=your_key_here
pip install praisonaiagents

Step-by-Step Build

1

Create Recipe Directory

mkdir -p ~/.praison/templates/meeting-minutes-action-items
cd ~/.praison/templates/meeting-minutes-action-items
2

Create TEMPLATE.yaml

name: meeting-minutes-action-items
version: "1.0.0"
description: "Extract action items from meeting transcripts"
author: "PraisonAI"
license: "MIT"

tags:
  - meetings
  - productivity
  - action-items

requires:
  env:
    - OPENAI_API_KEY
  packages:
    - praisonaiagents

inputs:
  transcript_text:
    type: string
    description: "Meeting transcript text"
    required: true
  attendees:
    type: array
    description: "List of attendee names"
    required: false
    default: []
  format:
    type: string
    description: "Output format"
    required: false
    default: "markdown"
    enum:
      - markdown
      - json

outputs:
  minutes:
    type: string
    description: "Formatted meeting minutes"
  action_items:
    type: array
    description: "List of action items"
  ok:
    type: boolean
    description: "Success indicator"

cli:
  command: "praison recipes run meeting-minutes-action-items"
  examples:
    - 'praison recipes run meeting-minutes-action-items --input ''{"transcript_text": "..."}'''

safety:
  dry_run_default: false
  requires_consent: false
  overwrites_files: false
  network_access: true
  pii_handling: true
3

Create recipe.py

# recipe.py
import json
from praisonaiagents import Agent, Task, PraisonAIAgents

def run(input_data: dict, config: dict = None) -> dict:
    """Extract action items from meeting transcript."""
    transcript_text = input_data.get("transcript_text")
    attendees = input_data.get("attendees", [])
    output_format = input_data.get("format", "markdown")
    
    if not transcript_text:
        return {"ok": False, "error": {"code": "MISSING_INPUT", "message": "transcript_text is required"}}
    
    try:
        attendees_str = ", ".join(attendees) if attendees else "Not specified"
        
        # Create analyzer agent
        analyzer = Agent(
            name="Meeting Analyst",
            role="Meeting Content Specialist",
            goal="Analyze meeting content and identify key points",
            instructions="""
            You are a meeting analysis expert.
            - Identify main topics discussed
            - Note decisions made
            - Find commitments and deadlines
            - Track who said what when relevant
            """,
        )
        
        # Create action extractor
        extractor = Agent(
            name="Action Extractor",
            role="Action Item Specialist",
            goal="Extract clear, actionable items",
            instructions=f"""
            You are an action item extraction expert.
            Known attendees: {attendees_str}
            
            For each action item, identify:
            - Task description
            - Assignee (if mentioned)
            - Due date (if mentioned)
            - Priority (if implied)
            
            Output as JSON array.
            """,
        )
        
        # Create formatter
        formatter = Agent(
            name="Minutes Formatter",
            role="Documentation Specialist",
            goal=f"Format minutes in {output_format}",
            instructions=f"""
            You are a documentation specialist.
            Format meeting minutes in {output_format} format.
            
            Include:
            - Meeting summary
            - Key discussion points
            - Decisions made
            - Action items section
            """,
        )
        
        # Define tasks
        analyze_task = Task(
            name="analyze_meeting",
            description=f"Analyze this meeting transcript:\n\n{transcript_text[:8000]}",
            expected_output="Meeting analysis with key points",
            agent=analyzer,
        )
        
        extract_task = Task(
            name="extract_actions",
            description="Extract action items from the meeting analysis",
            expected_output='JSON array: [{"task": "...", "assignee": "...", "due": "...", "priority": "..."}]',
            agent=extractor,
            context=[analyze_task],
        )
        
        format_task = Task(
            name="format_minutes",
            description=f"Format complete meeting minutes in {output_format}",
            expected_output=f"Formatted meeting minutes in {output_format}",
            agent=formatter,
            context=[analyze_task, extract_task],
        )
        
        # Execute
        agents = PraisonAIAgents(
            agents=[analyzer, extractor, formatter],
            tasks=[analyze_task, extract_task, format_task],
        )
        
        result = agents.start()
        
        # Parse action items
        actions_text = result.get("extract_actions", "[]")
        action_items = parse_action_items(actions_text)
        
        return {
            "ok": True,
            "minutes": result.get("format_minutes", ""),
            "action_items": action_items,
            "artifacts": [],
            "warnings": [],
        }
        
    except Exception as e:
        return {"ok": False, "error": {"code": "PROCESSING_ERROR", "message": str(e)}}


def parse_action_items(text: str) -> list:
    """Parse action items from agent output."""
    import re
    try:
        match = re.search(r'\[.*\]', text, re.DOTALL)
        if match:
            return json.loads(match.group())
    except json.JSONDecodeError:
        pass
    
    # Fallback: parse bullet points
    items = []
    for line in text.split('\n'):
        line = line.strip()
        if line.startswith(('-', '*', '•')) and len(line) > 2:
            items.append({"task": line[1:].strip(), "assignee": None, "due": None})
    
    return items
4

Create test_recipe.py

# test_recipe.py
import pytest
from recipe import run, parse_action_items

def test_missing_transcript():
    result = run({})
    assert result["ok"] is False
    assert result["error"]["code"] == "MISSING_INPUT"

def test_parse_action_items_json():
    text = '[{"task": "Review doc", "assignee": "John"}]'
    items = parse_action_items(text)
    assert len(items) == 1
    assert items[0]["task"] == "Review doc"

def test_parse_action_items_bullets():
    text = "- Review the document\n- Send email to client"
    items = parse_action_items(text)
    assert len(items) == 2

@pytest.mark.integration
def test_end_to_end():
    transcript = """
    John: Let's discuss the Q4 roadmap.
    Sarah: I think we should prioritize the mobile app.
    John: Agreed. Sarah, can you draft a proposal by Friday?
    Sarah: Sure, I'll have it ready.
    John: Great. Mike, please review the budget.
    Mike: Will do, I'll send it by Monday.
    """
    
    result = run({
        "transcript_text": transcript,
        "attendees": ["John", "Sarah", "Mike"],
        "format": "markdown"
    })
    
    assert result["ok"] is True
    assert len(result["action_items"]) > 0

Run Locally

# Basic usage
praison recipes run meeting-minutes-action-items \
  --input '{"transcript_text": "Meeting transcript here..."}'

# With attendees
praison recipes run meeting-minutes-action-items \
  --input '{"transcript_text": "...", "attendees": ["John", "Sarah"], "format": "json"}'

Deploy & Integrate: 6 Integration Models

from praisonai import recipe

result = recipe.run(
    "meeting-minutes-action-items",
    input={
        "transcript_text": transcript,
        "attendees": ["John", "Sarah", "Mike"]
    }
)

if result.ok:
    for item in result.output["action_items"]:
        create_task(item["task"], item["assignee"], item["due"])
Safety: Meeting content may contain sensitive business information.

Troubleshooting

Ensure the transcript clearly states commitments. Phrases like “I will” or “by Friday” help extraction.
Provide the attendees list to help the model match names correctly.

Next Steps