Meeting Minutes Action Items

Extract action items and generate structured meeting minutes from transcripts

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.

Diagram

📝 Transcript

Analyze Content

Extract Actions

Format Minutes

📋 Minutes + Actions

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

bash
export OPENAI_API_KEY=your_key_here
pip install praisonaiagents

Step-by-Step Build

  1. Create Recipe Directory
    bash
    mkdir -p ~/.praisonai/templates/meeting-minutes-action-items
    cd ~/.praisonai/templates/meeting-minutes-action-items
  2. Create TEMPLATE.yaml
    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
    python
    # recipe.py
    import json
    from praisonaiagents import Agent, Task, AgentTeam
    
    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 = AgentTeam(
                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
    python
    # 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

bash
# 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

Model 1: Embedded SDK

python
from praisonai import recipe

# Load or define transcript
transcript = "Meeting notes: John said we need to finish the project by Friday..."

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"]:
        print(f"Task: {item['task']}, Assignee: {item['assignee']}")

Model 2: CLI Invocation

bash
cat meeting_transcript.txt | praison recipes run meeting-minutes-action-items \
  --input '{"transcript_text": "'"$(cat)"'"}' --json

Model 3: Plugin Mode

python
class MeetingPlugin:
    def extract_actions(self, transcript, attendees=None):
        from praisonai import recipe
        return recipe.run(
            "meeting-minutes-action-items",
            input={"transcript_text": transcript, "attendees": attendees or []}
        )

Model 4: Local HTTP Sidecar

javascript
const response = await fetch('http://localhost:8765/recipes/meeting-minutes-action-items/run', {
  method: 'POST',
  body: JSON.stringify({
    transcript_text: transcript,
    format: 'json'
  })
});

Model 5: Remote Managed Runner

python
response = requests.post(
    "https://api.meeting-tools.com/extract-actions",
    headers={"Authorization": f"Bearer {api_key}"},
    json={"transcript_text": transcript}
)

Model 6: Event-Driven

python
def on_meeting_ended(event):
    import queue as q
    job_queue = q.Queue()  # Replace with SQS/RabbitMQ in production
    job_queue.put({
        "recipe": "meeting-minutes-action-items",
        "input": {
            "transcript_text": event['transcript'],
            "attendees": event['participants']
        },
        "callback_url": f"https://api.example.com/meetings/{event['meeting_id']}/minutes"
    })

Troubleshooting

Missing action items

Ensure the transcript clearly states commitments. Phrases like “I will” or “by Friday” help extraction.

Wrong assignees

Provide the attendees list to help the model match names correctly.

Next Steps